5

SQLクエリのselect部分のスカラー関数は、where句のすべての条件を満たす行にのみ適用されると常に素朴に想定していたと思います。

今日、私はベンダーからのコードをデバッグしていて、その仮定に異議を唱えました。このコードが失敗したと私が考えることができる唯一の理由は、WHERE句によってフィルターで除外されるべきデータに対してSubstring()関数が呼び出されていることです。しかし、フィルタリングが行われる前に部分文字列呼び出しが適用されているようで、クエリは失敗しています。これが私の言いたいことの例です。2つのテーブルがあり、それぞれに2つの列があり、それぞれ2つの行と1つの行があるとします。それぞれの最初の列は単なるIDです。NAMEは単なる文字列であり、NAME_LENGTHは、同じIDを持つ名前の文字数を示します。LONG_NAMESテーブルに対応する行があるのは、複数の文字を含む名前のみであることに注意してください。

NAMES: ID, NAME
    1, "Peter"
    2, "X"
LONG_NAMES: ID, NAME_LENGTH
    1, 5

最後の3文字を切り取って各名前を出力するクエリが必要な場合は、最初に次のようなものを試してみてください(今のところSQL Serverの構文を想定しています)。

SELECT substring(NAME,1,len(NAME)-3)
    FROM NAMES;

「X」に達すると、部分文字列呼び出しで負の数を使用しようとし、失敗するため、これでエラーが発生することがすぐにわかります。私のベンダーがこれを解決することを決定した方法は、文字列が短すぎてlen-3クエリが機能しない行を除外することでした。彼は別のテーブルに参加することによってそれをしました:

SELECT substring(NAMES.NAME,1,len(NAMES.NAME)-3) 
    FROM NAMES 
        INNER JOIN LONG_NAMES 
            ON NAMES.ID = LONG_NAMES.ID;

一見すると、このクエリは機能するように見えます。結合条件は、部分文字列呼び出しが失敗するのに十分短いNAMEフィールドを持つ行をすべて削除します。

ただし、私が観察できることから、SQL Serverは、テーブル内のすべての部分文字列式を計算し、結合を適用して行を除外しようとすることがあります。これはこのように起こるはずですか?特定のことがいつ発生するかを知ることができる、文書化された操作の順序はありますか?特定のデータベースエンジンまたはSQL標準の一部に固有ですか?NAMESテーブルに述語を含めて短い名前(len(NAME)> 3など)を除外することにした場合、SQL Serverは、部分文字列を適用しようとした後にそれを適用することも選択できますか?もしそうなら、部分文字列を実行する唯一の安全な方法は、selectの「casewhen」構文でそれをラップすることだと思われますか?

4

3 に答える 3

2

マーティンは、何が起こっているかをほぼ説明するこのリンクを提供しました.クエリオプティマイザには、好きなように並べ替える自由があります. 何かを受け入れることができるように、これを回答として含めています。マーティン、あなたのリンクを含む回答を作成していただければ、この回答ではなく喜んで受け入れます。

検索するのが難しいと思うので、ここに質問を残しておきたいと思います。また、この問題の特定の言い回しは、将来他の誰かが見つけやすくなる可能性があります。

0 を含む列がないにもかかわらず、TSQL のゼロによる除算が発生しました

編集: より多くの回答が寄せられたため、私は再び混乱しています。オプティマイザーが select 節内の項目を評価できる正確な時期はまだ明らかではないようです。SQL標準を自分で見つけて、それを理解できるかどうかを確認する必要があると思います。

于 2011-03-09T17:51:19.523 に答える
1

初期の SQL 標準の作成を支援した Joe Celko は、さまざまな USENET ニュースグループでこれに似た内容を数回投稿しています。(あなたの SELECT ステートメントに当てはまらない句は飛ばしています。) 彼は通常、「ステートメントが機能するように振る舞うには、このようにする必要があります」のようなことを言いました。つまり、SQL 実装は、これらの各手順を実際に実行する必要がなくても、これらの手順を実行した場合とまったく同じように動作する必要があります。

  1. FROM 句のすべてのテーブル コンストラクターから作業テーブルを作成します。
  2. WHERE 句を満たさない行を作業テーブルから削除します。
  3. 作業テーブルに対して SELECT 句で式を作成します。

したがって、これに従って、SQL dbms は、WHERE 句を適用するように動作する前に、SELECT 句で関数を評価するように動作してはなりません。

最近の投稿で、Joe は手順を拡張して CTE を含めました。

CJ Date と Hugh Darwen は、著書A Guide to the SQL Standard の第 11 章 ("Table Expressions") で本質的に同じことを述べています。彼らはまた、この章が SQL 標準の「クエリ仕様」セクション (セクション?) に対応していることにも注目しています。

于 2011-03-09T17:55:05.240 に答える
0

クエリ実行計画と呼ばれるものについて考えています。これは、クエリの最適化ルール、インデックス、一時バッファー、および実行時間の統計に基づいています。SQL Managment Studio を使用している場合は、クエリ エディター上にツールボックスがあり、推定実行計画を確認できます。これは、クエリがどのように変化して速度が向上するかを示しています。そのため、名前テーブルを使用しただけでバッファ内にある場合、エンジンは最初にデータをサブクエリしてから、他のテーブルと結合しようとする可能性があります。

于 2011-03-09T17:21:14.650 に答える