web-dev-qa-db-ja.com

非集計列でのWHERE対HAVING。長所/短所/無関係?

必要なすべてのデータを取得しなくなったクエリを書き換えているところです。私の質問は、私が今まで見たことのないプラクティスに関するもので、StackExchangeでこの問題に特に対処する質問を見つけていません。

HAVINGが個々の行に条件を導入するのと同じように、WHEREステートメントの目的は集計に条件を導入することです。ただし、このコードでは、集約を使用したクエリでHAVINGの代わりにWHEREが使用されています。 HAVINGの条件は、集計に対してではなく、非集計列に適用されます。

例えば:

SELECT id, filedate, SUM(amount)
FROM Sales
GROUP BY id, filedate
HAVING id = 123 AND filedate = '1/1/2018'

とは対照的に:

SELECT id, filedate, SUM(amount)
FROM Sales
WHERE id = 123 AND filedate = '1/1/2018'
GROUP BY id, filedate

この戦略には、パフォーマンスへの影響やその他の利点/欠点がありますか?

私は診断を自分で実行しようとしたことはありません。優先順位ではありません。自分の時間に実行する必要があります。しかし、これについて明確な答えがなければ、私はそう思うかもしれません。

私の懸念は、オプティマイザがこのクエリをどのように表示するかです。すべてのデータを集計し、HAVING句に基づいて結果セットを制限しますか、または非集計列を具体的に参照しているため、個々の行に所持条件を適用できることを認識していますか?

編集:私のサンプルクエリと書き換えている実際のSQLの場合、プランは同じですが、クエリは同様の複雑さであり、同じプランから結論を導き出すにはまだ十分な知識がありません。

7
Jacob Barnes

HAVINGの条件は、集計に対してではなく、非集計列に適用されます。

ここでの問題は、HAVING句が何に適用されるかをどのように説明しているかにあります。 HAVINGalwaysaggregatedフィールドに適用され、これは、残りのすべての列post-aggregationです。 HAVING句が集計関数に適用されていないことを示したり、伝えたりしようとしています。 。しかし実際には、HAVING句がその集約関数の結果、または最初の例ではグループ化列の結果を管理します。ただし、どちらの場合も、集計はすでに実行されています。

したがって、パフォーマンスの観点から(後でこのコードを更新しようとする他の人にとって読みやすさは言うまでもありません)、WHERE句を使用してが何になるかをフィルターで絞り込みます集約し、次にHAVING句を使用して、が集約されたものを除外します。そして、質問に示されている単純なテストの結果は、2つのタイミング(またはクエリが処理されるシーケンス内の論理配置)のタイミングの違いを覆い、同じことを「実行」しているように見えますが、行の束を集約して、後でそれらを論理的に削除して破棄することができる場合にのみ、それらを破棄するのが効率的でなかったら、私はかなり驚きます。ただし、これらの実行例がこの単純な例で類似していることがわかった場合、これらのHAVING条件を実際のWHERE条件は、実行前にクエリを書き換えます。しかし、その場合でも、このような方法でクエリを作成しないことをお勧めします。それは、オプティマイザがより効率的な計画を見つけるためにその時間/ CPUサイクルを費やす必要があるときに、不正なコードを書き換えるのに余分な時間をかけるためです。 @ DavidSpillett 追加(この回答のコメント内):「さらに、クエリプランナーが最適化の可能性を確認しているため、より複雑なクエリではないか、コードが移植された場合別のデータベース(またはSQL Serverの古いバージョンのみ)」.

その価値については、Microsoft HAVING句のドキュメント でも、GROUP BYが存在しない場合はWHERE句として機能すると述べています。ドキュメントがGitHubにあるので、最近 プルリクエスト#235:HAVING句を修正して改善する で修正できました。

14
Solomon Rutzky

ソロモンは非常に良い説明をしますが、私にとって、簡単な答えは、Itzik Ben-Ganが書いたSQLクエリの論理処理順序を覚えておくことです here シーケンスは常に

FROM-> WHERE-> GROUP BY-> HAVING-> SELECT-> ORDER BY

つまり、GROUP BYの前にWHEREフィルターを適用できる場合、GROUP BYによって処理されるデータの量を減らすことができます。適切なインデックスが存在する場合、WHERE操作は非常に効率的です。そのため、WHEREを使用してHAVINGがビジネスの観点から同じ結果を返す場合、WHEREは常にHAVINGよりも優れています。

10
jyao