SQL Server 2014 Enterpriseにあるクエリのパフォーマンスを調整しようとしています。
SQL Sentry Plan Explorerで実際のクエリプランを開いたところ、1つのノードでSeek Predicateと述語
Seek PredicateとPredicateの違いは何ですか?
注:このノードには多くの問題(たとえば、推定行と実際の行、残りのIO)があることがわかりますが、質問はそれとは関係ありません。
いくつかの列とともに100万行を一時テーブルにスローしてみましょう。
CREATE TABLE #174860 (
PK INT NOT NULL,
COL1 INT NOT NULL,
COL2 INT NOT NULL,
PRIMARY KEY (PK)
);
INSERT INTO #174860 WITH (TABLOCK)
SELECT RN
, RN % 1000
, RN % 10000
FROM
(
SELECT TOP 1000000 ROW_NUMBER () OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values v1,
master..spt_values v2
) t;
CREATE INDEX IX_174860_IX ON #174860 (COL1) INCLUDE (COL2);
ここで、PK
列にクラスター化インデックス(デフォルト)があります。 COL1
のキー列があり、COL1
を含む非クラスター化インデックスがCOL2
にあります。
次のクエリについて考えてみます。
SELECT *
FROM #174860
WHERE PK >= 15000 AND PK < 15005
AND COL2 = 5000;
ここで私はBETWEEN
を使用していません。なぜなら、Aaron Bertrandがこの質問にぶら下がっているからです。
SQL Serverオプティマイザはどのようにクエリを実行する必要がありますか?まあ、私はPK
のフィルターが結果セットを5行に減らすことを知っています。 SQLサーバーは、クラスター化インデックスを使用して、テーブル内の100万行すべてを読み取る代わりに、これらの5行にジャンプできます。ただし、クラスター化インデックスには、キー列としてPK列しかありません。行がメモリに読み込まれたら、COL2
にフィルターを適用する必要があります。ここで、PK
はシーク述語であり、COL2
は述語です。
SQLサーバーは、シーク述語を使用して5つの行を検出し、通常の述語を使用して、これらの5つの行を1つの行にさらに減らします。
クラスタ化インデックスを別の方法で定義した場合:
CREATE TABLE #174860 (
PK INT NOT NULL,
COL1 INT NOT NULL,
COL2 INT NOT NULL,
PRIMARY KEY (COL2, PK)
);
同じクエリを実行すると、異なる結果が得られます。
この場合、SQL ServerはWHERE
句で両方の列を使用してシークできます。キー列を使用して、テーブルから正確に1行が読み込まれます。
もう1つの例として、次のクエリを考えてみます。
SELECT *
FROM #174860
WHERE COL1 = 500
AND COL2 = 3545;
IX_174860_IXインデックスは、クエリに必要なすべての列が含まれているため、カバリングインデックスです。ただし、COL1
のみがキー列です。 SQL Serverはその列でシークして、一致するCOL1
値を持つ1000行を見つけることができます。 COL2
列の行をさらにフィルタリングして、最終的な結果セットを0行に減らすことができます。