SQL Server 2012で空の結果セットでクエリエラーが発生するのはなぜですか?


31

MS SQL Server 2012で次のクエリを実行すると、2番目のクエリは失敗しますが、最初のクエリは失敗しません。また、where句なしで実行すると、両方のクエリが失敗します。両方が空の結果セットを持つ必要があるため、どちらが失敗するのか、私は途方に暮れています。どんな助け/洞察も大歓迎です。

create table #temp
(id     int primary key)

create table #temp2
(id     int)

select 1/0
from #temp
where id = 1

select 1/0
from #temp2
where id = 1

回答:


39

実行プランを最初に見ると、式1/0がCompute Scalar演算子で定義されていることがわかります。

グラフィカルな計画

さて、実行計画を繰り返し呼び出して、左端の実行を開始しないにもかかわらず、OpenおよびGetRow子イテレータのメソッドが結果を返すために、SQL Server 2005およびそれ以降の表現がしばしばだけされていることにより、最適化を含んで定義されて、計算スカラでは、後続まで延期評価操作には結果が必要です。

SET STATISTICS XMLによって生成されたショープランに表示される計算スカラー演算子には、RunTimeInformation要素が含まれていない場合があります。 グラフィカルなショープランでは、SQL Server Management Studioで[実際の実行プランを含める]オプションが選択されている場合、[プロパティ]ウィンドウに[実際の行]、[実際の再バインド]、および[実際の巻き戻し]が表示されないことがあります。 これが発生した場合、これらの演算子はコンパイルされたクエリプランで使用されましたが、実行時クエリプランの他のオペレータによって実行されたことを意味します。 また、SET STATISTICS PROFILEによって生成されたShowplan出力の実行回数は、SET STATISTICS XMLによって生成されたShowplansの再バインドと巻き戻しの合計に等しいことに注意してください。 From:MSDN Books Online

この場合、式の結果は、クライアントに戻るために行を組み立てるときにのみ必要です(緑色のSELECTアイコンで発生すると考えることができます)。そのロジックにより、遅延評価は、どちらのプランも戻り行を生成しないため、式が評価されないことを意味します。ポイントを少し労力をかけるために、クラスター化インデックスシークもテーブルスキャンも行を返さないため、クライアントに返すためにアセンブルする行はありません。

ただし、一部の式はランタイム定数として識別され、クエリの実行が開始される前に1回評価されるため、個別の最適化があります。この場合、これが発生したことはshowplan XML(左側のクラスター化インデックスシークプラン、右側のテーブルスキャンプラン)で確認できます。

Showplan XML

このブログ投稿では、基礎となるメカニズムと、それらがパフォーマンスどのように影響するかについて詳しく説明しました。そこで提供される情報を使用して、最初のクエリを変更して、実行が開始される前に両方の式が評価およびキャッシュされるようにすることができます。

select 1/0 * CONVERT(integer, @@DBTS)
from #temp
where id = 1

select 1/0
from #temp2
where id = 1

現在、最初のプランには定数式参照も含まれており、両方のクエリでエラーメッセージが生成されます。最初のクエリのXMLには次が含まれます。

定数式

詳細:スカラー、式、およびパフォーマンスの計算


21

私は賢明に推測します(そして、その過程で、おそらく本当に詳細な答えを与えるかもしれないSQL Serverの第一人者を引き付けます)。

最初のクエリは、次のように実行にアプローチします。

  1. 主キーインデックスをスキャンする
  2. クエリに必要なデータテーブルの値を検索する

where主キーに句があるため、このパスが選択されます。2番目のステップには到達しないため、クエリは失敗しません。

2番目には実行する主キーがないため、次のようにクエリにアプローチします。

  1. データの全表スキャンを行い、必要な値を取得します

これらの値の1つが1/0問題の原因です。

これは、クエリを最適化するSQL Serverの例です。ほとんどの場合、これは良いことです。SQL Serverは、条件をselectテーブルスキャン操作に移動します。これにより、多くの場合、クエリの評価の手順が節約されます。

しかし、この最適化は単純な良いことではありません。実際、句はの前に評価されるというSQL Serverのドキュメント自体に違反しているようです。まあ、彼らはこれが何を意味するかについて、いくらかの博識な説明があるかもしれません。しかし、ほとんどの人間にとって、論理的にbeforeを処理することは(とりわけ)「ユーザーに返されない行で-clauseエラーを生成しない」ことを意味します。whereselectwhereselectselect


1
あなたが正しい場合、+ 1の手がかりはありませんが、唯一の違いが主キーであることを考えると、私が見ることができる最良の答え。

1
@GordonLinoffポールランダルは、Twitterを介して、あなたの返信が強烈であることを確認しました。
SchmitzIT 14

4
@Still、実際の実行順序は、どのように異なっていても、そのようなエラーメッセージを引き起こさないはずです。
ypercubeᵀᴹ

7
@ypercube Erland Sommarskogはあなたに同意します(接続アイテム)
Paul WhiteがGoFundMonicaを言う

2
ポインターに感謝します-私はログインし、リクエストを支持しました。
ゴードンリノフ14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.