footmark

ひよっこエンジニアの足跡

スパゲティクエリは悪!?

会社の研修中、同期と以下のSQLクエリについて議論になりました。

【Code 1】一番数量の多い注文をした受注先を求めるクエリ
SELECT customer.name, s.item_sum
FROM (SELECT order_no, SUM(quontity) AS item_sum FROM order_detail GROUP BY order_no) s
JOIN orders ON orders.no = s.order_no
JOIN customer ON customer.no = orders.customer_no
WHERE item_sum IN (SELECT MAX(item_sum)
FROM (SELECT order_no, SUM(quontity) AS item_sum
FROM order_detail GROUP BY order_no) s);

論点

見にくい

論点というより感想ですが、見にくい!
パッと見何がしたいクエリなのか分からないし、デバッグも大変そうだよ!

1クエリで書いた方がいいのか

僕だけかもしれませんが、SQLって1クエリで書いた方が良いというか、書けた方がすごい感ありませんか?
僕だけですよね。知ってます。

普段のプログラミングを思い出したり、デバッグすることを考えたりすると、1クエリに拘る必要がないような。。。

同じSELECT文使いまわしてね?

SELECT order_no, SUM(quontity) AS item_sum
FROM order_detail GROUP BY order_no

を使いまわしています。
これってナンセンスなんじゃないですか?

SQLアンチパターン買った

なんとなく Code 1 のクエリが悪に思えてきました。

じゃあ実際どうなの?
( ゚∀゚)o彡゜実例!実例!

ということでSQLアンチパターン買いました。
17章 スパゲティクエリ が今回の論点にマッチしていたのでまとめます。

SQLアンチパターン

SQLアンチパターン

スパゲティクエリ

SQLアンチパターンでは、Code 1 のように1つのクエリで多くの処理をしているクエリをスパゲティコードと呼んでいます。
あえてスパゲティクエリを書くメリットはほとんどなく^1、反対に以下のデメリットがあります。

  • しばしばデカルト積が生じる^2
  • 記述ミスが生じる
  • クエリの記述、修正、デバッグが難しくなる
    • 例えばRDBの場合、正規化によってテーブルを小さくし、拡張性を大きくしているのに、クエリによってそれを小さくしてしまうのは良くない
  • 結合やサブクエリを用いると実行が遅くなる
    • 複雑なクエリを1つ実行するよりもシンプルなクエリを複数実行する方が良い

スパゲティクエリが生まれる原因

クエリ数を減らすことで仕事をシンプルにしようとする

プログラマーは、タスクの複雑性を減らすことはできませんが、解決策はシンプルにしたいと考えます。そこで、クエリを「優雅に」「効率的に」書くことを目標にします。そしてタスクを1つのクエリで解決することで、この目標を達成したと見なします。

さっきの僕じゃないですか!

複雑な問題を1クエリで解決しようとする

SQLは1つのクエリですべてのタスクを処理することを強要するものではありませんし、ときにはそれが良くないアイデアである場合もあります。

解決策

クエリをワンステップ単位に分割する

まったく同じ結果セットを生む2つのクエリを選択できる場合は、単純なクエリを選ぶべきであると言えます。

これはクエリの記述・修正の容易性や、実行速度、はたまたコードレビューに良い結果をもたらします。

UNION を用いる

どうしても1クエリで実現したい場合は、分割したクエリを UNION で繋げれば良いのです。

まとめ

  • スパゲティクエリは悪!
  • クエリはワンステップずつ書こう!

参考

SQLアンチパターン

SQLアンチパターン