単純な3つのテーブルの結合を考えると、行が返されない場合でもORDER BYを含めると、クエリのパフォーマンスが大幅に変わります。実際の問題シナリオでは、ゼロ行を返すのに30秒かかりますが、ORDER BYが含まれていない場合は即座に発生します。どうして?
SELECT *
FROM tinytable t /* one narrow row */
JOIN smalltable s on t.id=s.tinyId /* one narrow row */
JOIN bigtable b on b.smallGuidId=s.GuidId /* a million narrow rows */
WHERE t.foreignId=3 /* doesn't match */
ORDER BY b.CreatedUtc /* try with and without this ORDER BY */
bigtable.smallGuidIdにインデックスを作成できることは理解していますが、この場合は実際にインデックスが悪化するものと考えています。
テスト用のテーブルを作成/設定するスクリプトを次に示します。奇妙なことに、smalltableにはnvarchar(max)フィールドがあることが問題のようです。また、GUIDを使用してbigtableに参加していることも重要なようです(これにより、ハッシュマッチングを使用したいと思うでしょう)。
CREATE TABLE tinytable
(
id INT PRIMARY KEY IDENTITY(1, 1),
foreignId INT NOT NULL
)
CREATE TABLE smalltable
(
id INT PRIMARY KEY IDENTITY(1, 1),
GuidId UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(),
tinyId INT NOT NULL,
Magic NVARCHAR(max) NOT NULL DEFAULT ''
)
CREATE TABLE bigtable
(
id INT PRIMARY KEY IDENTITY(1, 1),
CreatedUtc DATETIME NOT NULL DEFAULT GETUTCDATE(),
smallGuidId UNIQUEIDENTIFIER NOT NULL
)
INSERT tinytable
(foreignId)
VALUES(7)
INSERT smalltable
(tinyId)
VALUES(1)
-- make a million rows
DECLARE @i INT;
SET @i=20;
INSERT bigtable
(smallGuidId)
SELECT GuidId
FROM smalltable;
WHILE @i > 0
BEGIN
INSERT bigtable
(smallGuidId)
SELECT smallGuidId
FROM bigtable;
SET @i=@i - 1;
END
SQL 2005、2008、2008R2で同じ結果をテストしました。