【SQL実践|実務向け】なぜHAVING句は「WHERE句の代わり」に使ってはいけないのか

HAVING句の本来の役割を再定義する

データベース管理者として現場を見ていると、WHERE句で書けるはずの条件をあえてHAVING句に記述しているクエリを見かけることがあります。例えば、特定のユーザーIDのみを抽出するためにGROUP BYとHAVINGを使っているケースです。これは単にパフォーマンスを低下させるだけでなく、SQLの意図を不明瞭にします。HAVING句は「グループ化された後の集計結果に対してフィルタリングを行う」ためのものであり、個々の行に対する抽出条件は、原則としてWHERE句で処理すべきです。

実行計画から見るパフォーマンスの差

なぜWHERE句を優先すべきなのか。それは実行順序にあります。SQLは「WHERE句による行の絞り込み」を先に行い、その後に「GROUP BYによる集計」を行い、最後に「HAVING句によるグループ後の絞り込み」を行います。
もし、数百万件のテーブルでWHERE句で済む条件をHAVING句に記述してしまうと、データベースエンジンは全てのデータを集計用メモリ(一時領域)に展開してからフィルタリングを行うことになります。これはI/O負荷の増大とメモリ枯渇のリスクを直結させる行為です。実務では、この「無駄な集計」がデッドロックやレスポンス遅延の主原因となることが多々あります。

具体的な活用事例:動的な閾値判定

では、HAVING句が真価を発揮するのはどのような場面でしょうか。それは「集計した結果に基づいて、動的にデータを選択したい場合」です。
例えば、ECサイトの分析において「過去1ヶ月の購入回数が平均の2倍を超えている顧客」を抽出したいとします。
SELECT user_id, COUNT() as order_count
FROM orders
GROUP BY user_id
HAVING COUNT() > (SELECT AVG(order_count) 2 FROM (SELECT COUNT() as order_count FROM orders GROUP BY user_id) as sub);
このように、「集計結果そのものを評価対象にする」という文脈においては、HAVING句は唯一無二の手段となります。

DBAからのアドバイス:可読性と保守性

SQLは書ければ良いというものではありません。後からコードを見た開発者が「なぜここでグループ化が必要なのか」を一目で理解できることが重要です。WHERE句で書けるものはWHERE句に書き、HAVING句は「集計後の絞り込み」という本来の目的に限定する。この使い分けを徹底するだけで、クエリの可読性は向上し、予期せぬパフォーマンス劣化を未然に防ぐことができます。

次のチューニング機会があれば、まず「そのHAVING句はWHERE句に移動できないか?」を自問自答してみてください。それが、安定したデータベース運用への第一歩です。

コメント

タイトルとURLをコピーしました