同じ名前、タイプ、およびインデックスキー列を持つ2つのテーブルがあります。それらの1つには一意のクラスター化インデックスがあり、もう1つには非一意があります。
テストのセットアップ
いくつかの現実的な統計を含むセットアップスクリプト:
DROP TABLE IF EXISTS #left;
DROP TABLE IF EXISTS #right;
CREATE TABLE #left (
a char(4) NOT NULL,
b char(2) NOT NULL,
c varchar(13) NOT NULL,
d bit NOT NULL,
e char(4) NOT NULL,
f char(25) NULL,
g char(25) NOT NULL,
h char(25) NULL
--- and a few other columns
);
CREATE UNIQUE CLUSTERED INDEX IX ON #left (a, b, c, d, e, f, g, h)
UPDATE STATISTICS #left WITH ROWCOUNT=63800000, PAGECOUNT=186000;
CREATE TABLE #right (
a char(4) NOT NULL,
b char(2) NOT NULL,
c varchar(13) NOT NULL,
d bit NOT NULL,
e char(4) NOT NULL,
f char(25) NULL,
g char(25) NOT NULL,
h char(25) NULL
--- and a few other columns
);
CREATE CLUSTERED INDEX IX ON #right (a, b, c, d, e, f, g, h)
UPDATE STATISTICS #right WITH ROWCOUNT=55700000, PAGECOUNT=128000;
再現
これら2つのテーブルをクラスタリングキーで結合するとき、次のように1対多のMERGE結合が期待されます。
SELECT *
FROM #left AS l
LEFT JOIN #right AS r ON
l.a=r.a AND
l.b=r.b AND
l.c=r.c AND
l.d=r.d AND
l.e=r.e AND
l.f=r.f AND
l.g=r.g AND
l.h=r.h
WHERE l.a='2018';
これは私が欲しいクエリプランです:
(警告を気にせず、偽の統計に関係します。)
ただし、次のように、結合内で列の順序を変更すると、
SELECT *
FROM #left AS l
LEFT JOIN #right AS r ON
l.c=r.c AND -- used to be third
l.a=r.a AND -- used to be first
l.b=r.b AND -- used to be second
l.d=r.d AND
l.e=r.e AND
l.f=r.f AND
l.g=r.g AND
l.h=r.h
WHERE l.a='2018';
...これは起こります:
ソート演算子は、結合の宣言された順序に従ってストリームを並べているようです。つまりc, a, b, d, e, f, g, h
、クエリプランにブロッキング操作が追加されます。
私が見たもの
- 列を
NOT NULL
に変更してみましたが、同じ結果になりました。 - 元のテーブルはで作成されましたが
ANSI_PADDING OFF
、で作成してANSI_PADDING ON
もこの計画には影響しません。 - の
INNER JOIN
代わりにLEFT JOIN
、変更を試みました。 - 2014 SP2 Enterpriseでそれを発見し、2017 Developer(現在のCU)で再現を作成しました。
- 主要なインデックス列のWHERE句を削除することで適切なプランが生成されますが、結果に多少影響します。
最後に、質問に行きます
- これは意図的なものですか?
- クエリを変更せずに並べ替えを削除できますか(これはベンダーコードなので、実際にはそうではありません...)。テーブルとインデックスを変更できます。