開発中のプログラムがあまり進んでないのでSQLの小ネタ。
昔、よくあった遅いSQLの改善方法について、記載。
インデックスを張ったりするのもいいけど、SQLを作るときにデータをたくさん持ってきてまとめて条件分岐をCASE式でするだけで
圧倒的に速度が改善できる。
例えば、業務アプリで帳票などを作成する際に、列に月の集計結果を、持たせようとするケースがよくある。
2018年
1月|2月|3月|・・・・
得意先A 100| 60| 40|・・・・
得意先B 0| 20| 40|・・・・
こういう集計をSQL側でGroupByを何個も書いて集計していたりするのをよく見る。
(例)
SELECT *
FROM 得意先マスター AS 得意先
LEFT JOIN (
SELECT SUM(売上金額) AS 1月売上
,得意先CD
FROM 売上テーブル
WHERE 年月 = '201801'
GROUP BY 年月,得意先CD
) AS 1月売上金額
ON 得意先.得意先CD = 1月売上金額.得意先CD
以下、LEFT JOIN が11ヶ月分続く
しかし、やむを得ない場合なら仕方ないけど、特に考えもせずにこんなソースを書いている人がいると殴りたくなってくる。
実際に昔、こんな感じのSQLを発行して、メモリエラーが発生するんでどうしたらいいでしょう。みたいなことを言われたことがある。
その時には3万行のSQLを発行して使い物にならなかった。
SUM関数の中にCASE式を書くことができるので、下記のSQLで一気に12か月分のデータを取得できる。
(例)
SELECT SUM(CASE WHEN RIGHT(年月,2) = '01' THEN 売上金額 ELSE 0 END) AS 1月売上
,SUM(CASE WHEN RIGHT(年月,2) = '02' THEN 売上金額 ELSE 0 END) AS 2月売上
,SUM(CASE WHEN RIGHT(年月,2) = '03' THEN 売上金額 ELSE 0 END) AS 3月売上
,SUM(CASE WHEN RIGHT(年月,2) = '04' THEN 売上金額 ELSE 0 END) AS 4月売上
,SUM(CASE WHEN RIGHT(年月,2) = '05' THEN 売上金額 ELSE 0 END) AS 5月売上
,得意先CD
FROM 売上テーブル
WHERE LEFT(年月,4) = '2018'
GROUP BY 得意先CD
件数のカウントとかも、「SUM(CASE WHEN RIGHT(年月,2) = '02' THEN 1 ELSE 0 END) AS 2月売上件数」とすることで
一つのSQL文で対応ができる。
Window関数を利用すればもっといろんなことができる。
意外と集計関数の中にCASE式が書けないことを知らない人がいたのでメモをしておく。
処理速度もSQLの文量も修正の手間も圧倒的に違うので、普段からある程度慣れ親しんでいてほしい。
SQLは慣れてくるとパズルみたいに思えてくるので、頭の体操としてはすごくいい感じ。
登録:
コメントの投稿 (Atom)
PowerShellでDataSetのXMLの内容をシリアライズし、生成された文字列を再度デシリアライズする
修正前のテーブルの内容をXMLデータとして保存し、ログテーブルに格納することで、履歴を退避する Step1 DataSetをシリアライズしXML形式の文字列を作成する Step2 文字列をログテーブルへ保存する(普通にInsert) Step3 ログ...
-
TreeListView上でコンボボックスを利用するときにフォーカスのあるコンボボックスの色をイベントで変えようとしたけど上手くいかなかった。 色々と調べているとXaml側のテンプレートをいじる必要があるみたいだったので、いろいろとやってみた。 とりあえず、コンボボックス...
-
サイトに自動でログインするVBSのソース 事前に対象のWebサイトを開いて、F12キーを押下して、要素の名前を調べておく。 ※Edge、Chromeなどのブラウザ objIE.Visible = Trueの部分を objIE.Visible = Falseにしておけば...
-
開発中のプログラムがあまり進んでないのでSQLの小ネタ。 昔、よくあった遅いSQLの改善方法について、記載。 インデックスを張ったりするのもいいけど、SQLを作るときにデータをたくさん持ってきてまとめて条件分岐をCASE式でするだけで 圧倒的に速度が改善できる。 例えば...
0 件のコメント:
コメントを投稿