Dies ist ein wenig weit gefasst, aber ich denke, ich verstehe die wahre Frage und werde entsprechend antworten. Ich werde nur über Tabelle vs. Index-Spool sprechen. Ich denke, es ist nicht ganz richtig, dort eine Wahl zwischen Tabellen- und Index-Spools zu sehen. Wie Sie wissen, ist es in einem einzelnen Teilbaum möglich, eine Index- oder Tabellenspule oder sowohl eine Index- als auch eine Tabellenspule abzurufen. Ich glaube, es ist im Allgemeinen richtig zu sagen, dass Sie eine Index-Spool unter den folgenden Bedingungen erhalten:
- Das Abfrageoptimierungsprogramm hat einen Grund, einen Join in einen Apply umzuwandeln
- Das Abfrageoptimierungsprogramm führt die Transformation für die Anwendung aus
- Das Abfrageoptimierungsprogramm verwendet die Regel, um einen Index-Spool hinzuzufügen (mindestens muss der Index-Spool sicher sein).
- Der Plan mit der Index-Spool ist ausgewählt
Sie können die meisten davon mit einfachen Demos sehen. Beginnen Sie mit dem Erstellen eines Paares von Heaps:
DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_901;
CREATE TABLE dbo.X_10000_VARCHAR_901 (ID VARCHAR(901) NOT NULL);
INSERT INTO dbo.X_10000_VARCHAR_901 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_800;
CREATE TABLE dbo.X_10000_VARCHAR_800 (ID VARCHAR(800) NOT NULL);
INSERT INTO dbo.X_10000_VARCHAR_800 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
Bei der ersten Abfrage gibt es nichts zu suchen:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
CROSS JOIN dbo.X_10000_VARCHAR_901 b
OPTION (MAXDOP 1);
Es gibt also keinen Grund für das Optimierungsprogramm, den Join in eine Anwendung umzuwandeln. Aus Kostengründen erhalten Sie eine Tabellenspule. Diese Abfrage besteht also den ersten Test nicht.
Für die nächste Abfrage ist zu erwarten, dass das Optimierungsprogramm einen Grund hat, eine Anwendung in Betracht zu ziehen:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);
Aber es soll nicht sein:
Diese Abfrage besteht den zweiten Test nicht. Eine vollständige Erklärung finden Sie hier . Zitat des relevantesten Teils:
Das Optimierungsprogramm erwägt nicht, einen Index im laufenden Betrieb zu erstellen, um eine Anwendung zu ermöglichen. Vielmehr ist die Reihenfolge der Ereignisse normalerweise umgekehrt: Transformiere, um anzuwenden, weil ein guter Index existiert.
Ich kann die Abfrage umschreiben, um das Optimierungsprogramm zu ermutigen, sich zu bewerben:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (MAXDOP 1);
Es gibt aber noch keine Index-Spool:
Diese Abfrage besteht den dritten Test nicht. In SQL Server 2014 war die Länge des Indexschlüssels auf 900 Byte begrenzt. Dies wurde in SQL Server 2016 erweitert, jedoch nur für nicht gruppierte Indizes. Der Index für eine Spool ist ein Clustered-Index, sodass das Limit bei 900 Bytes bleibt . In jedem Fall kann die Index-Spool-Regel nicht angewendet werden, da dies zu einem Fehler bei der Abfrageausführung führen kann.
Das Reduzieren der Datentyplänge auf 800 liefert schließlich einen Plan mit einer Index-Spool:
Es überrascht nicht, dass der Index-Spool-Plan erheblich günstiger ist als ein Plan ohne Spool: 89,7603 Einheiten gegenüber 598,832 Einheiten. Sie können den Unterschied anhand des undokumentierten QUERYRULEOFF BuildSpool
Abfragehinweises erkennen:
Dies ist keine vollständige Antwort, aber es ist hoffentlich etwas von dem, wonach Sie gesucht haben.