Bei einem einfachen Join mit drei Tabellen ändert sich die Abfrageleistung drastisch, wenn ORDER BY eingeschlossen wird, auch wenn keine Zeilen zurückgegeben werden. Das tatsächliche Problemszenario benötigt 30 Sekunden, um Nullzeilen zurückzugeben, ist jedoch sofort verfügbar, wenn ORDER BY nicht enthalten ist. Warum?
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 */
Ich verstehe, dass ich einen Index für bigtable.smallGuidId haben könnte, aber ich glaube, das würde es in diesem Fall noch schlimmer machen.
Hier ist ein Skript zum Erstellen / Auffüllen der zu testenden Tabellen. Interessanterweise scheint es wichtig zu sein, dass smalltable ein nvarchar (max) -Feld hat. Es scheint auch von Bedeutung zu sein, dass ich mich mit einem Guid auf dem Bigtable anmelde (was meiner Meinung nach dazu führt, dass Hash-Matching verwendet werden soll).
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
Ich habe auf SQL 2005, 2008 und 2008R2 mit den gleichen Ergebnissen getestet.