良い、悪い、または無関心:WHERE 1 = 1


14

redditに関するこの質問を踏まえて、クエリをクリーンアップして、クエリのどこに問題があるのか​​を指摘しました。最初にコンマを使用しWHERE 1=1、クエリの変更を簡単にするため、クエリは通常、次のようになります。

SELECT 
     C.CompanyName
    ,O.ShippedDate
    ,OD.UnitPrice
    ,P.ProductName
FROM 
               Customers       as C
    INNER JOIN Orders          as O  ON C.CustomerID = O.CustomerID
    INNER JOIN [Order Details] as OD ON O.OrderID    = OD.OrderID
    INNER JOIN Products        as P  ON P.ProductID  = OD.ProductID
Where 1=1
--  AND O.ShippedDate Between '4/1/2008' And '4/30/2008'
    And P.productname = 'TOFU'
Order By C.CompanyName

誰かが基本的に、1 = 1は一般に怠け者でパフォーマンスに悪いと言いました。

「時期尚早に最適化する」ことを望まないことを考えると、私は良い習慣に従いたいと思います。以前にクエリプランを見てきましたが、一般的には、クエリをより高速に実行するために追加(または調整)できるインデックスを見つけるためだけです。

質問は本当に... Where 1=1悪いことが起こるのですか?もしそうなら、どうすればわかりますか?

マイナーな編集:私も常に「想定」しており、それ1=1が最適化されているか、最悪の場合無視できると思います。「後藤は悪」や「時期尚早な最適化...」、またはその他の想定される事実など、マントラに疑問を投げかけることはありません。1=1 ANDクエリプランに現実的に影響するかどうかはわかりませんでした。サブクエリについてはどうですか?CTEの?手順?

必要な場合を除き、最適化する人ではありません...しかし、実際に「悪い」ことをしている場合、影響を最小限に抑えるか、必要に応じて変更したいと思います。


2
いいえ、そうではありません。オプティマイザが冗長条件を削除するための数マイクロ秒を除きます。日付リテラルがあいまいにならないように注意してください。
ypercubeᵀᴹ

@ypercubeが言ったように、違いはありません。クエリオプティマイザーは、そのようなことで何らかの違いを生むために****の一部である必要があります;)
Philᵀᴹ13年

4
redditで読むすべてを信じないでください。お願いします。
アーロンバートランド

1
@AaronBertrand私はそれを直接体験するまで、すべてを一粒の塩で取ります。もっともらしい質問を取り、それが真実であるかどうか、特にそれが日々の仕事に影響を与える場合は特に。
WernerCD

4
塩の粒があります、そして、あなたのオフィスビルの上にダンプ全体の海洋の塩分があります:P
Philᵀᴹ

回答:


13

SQLサーバー パーサーオプティマイザには、クエリからトートロジー式を削除する「定数折りたたみ」と呼ばれる機能があります。
実行計画を見ると、述語のどこにもその式が表示されません。これは、この理由およびその他の理由により、コンパイル時にとにかく定数折りたたみが実行されることを意味し、クエリのパフォーマンスには影響しません。

詳細については、カーディナリティ推定中の定数の折りたたみと式の評価を参照してください。


これは、フィールドの連結を行う既知のパターンであるため、おそらくコンパイルされています。
jcolebrand

いいえ、それはトートロジー的であるためコンパイルされます。2736 = 2736でも同じように機能しますが、これは1 = 1と同じように普通ではありません。同じことが矛盾に当てはまります。その場合、この機能は「矛盾検出」と呼ばれます。
スパゲッティ

「既知のパターン」のどの部分が「1 = 1でなければならない」ことを意味していましたか?
jcolebrand

9

冗長な述語を追加すると、SQL Serverに違いが生じる可能性があります。

以下の実行計画@1では、最初の計画と'foo'2番目の計画のリテラルに注目してください。

ここに画像の説明を入力してください

これは、SQL Serverが実行計画の再利用を促進するために単純なパラメーター化の最初のクエリを検討したことを示しますが、2つの定数の比較により、2番目のケースでこれが発生しません。

単純なパラメーター化(以前は自動パラメーター化として知られていました)を妨げる条件のリストは、Microsoftテクニカルペーパーのキャッシュの計画の付録Aにあります。

とにかく、単純なパラメーター化は一般的にあなたが頼るべきものではありません。クエリを明示的にパラメーター化することをお勧めします。


4

最新のRDBMS(Oracle、Microsoft SQL Server、PostgreSQLなど)では、これはパフォーマンスに影響しません。

誰かが述べたように、これはクエリ計画フェーズにのみ影響します。したがって、次のようにデータを返さない単純なクエリを何千回も繰り返し実行した場合にのみ、違いが表示されます。

SELECT 1 FROM empty_table; -- run this 10 000 times.

SELECT 1 FROM empty_table WHERE 1=1; -- run this 10 000 times and compare.

私にとって、PostgreSQL 9.0では、これは10000回の反復で表示されます。

filip@srv:~$ pgquerybench.pl -h /var/run/postgresql/ -q "select 1 from never where 1=1" -q "select 1 from never" -i 10000
Iterations: 10000
Query:   select 1 from never where 1=1
Total:   2.952 s
Average: 0.295 ms
Query:   select 1 from never
Total:   2.850 s
Average: 0.285 ms

0

データベースパラメータcursor_sharingを使用する場合、これはOracleの「問題」になる可能性があります。これを「強制」に設定すると、すべてのSQLステートメントが変更されます。クエリ内のすべての「定数」は、バインド変数(1 =>:SYS_0など)に置き換えられます。

このオプションは、いくつかの怠developersな開発者に対処するために導入されました。一方、他の怠け者の開発者にも害を及ぼす可能性があります。しかし、リスクはそれほど高くありません。11g以降、バインド変数のピーク機能があります。


「11g以降、バインド変数のピーク機能があります」を明確にできますか手段?
ypercubeᵀᴹ

@ypercube「バインド変数のピーク」は、オプティマイザーがバインド変数の実際の値を観察し、データ統計を使用してクエリ実行プランを再評価し、場合によっては再生成することを意味します。しかし、ピークはデータ統計に依存しないため、議論されている構造に影響を与えることはありません。
ムスタッチョ14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.