我问这个问题是为了更好地了解优化器的行为并了解索引假脱机的限制。假设我将1到10000之间的整数放入堆中:
CREATE TABLE X_10000 (ID INT NOT NULL);
truncate table X_10000;
INSERT INTO X_10000 WITH (TABLOCK)
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
并强制嵌套循环加入MAXDOP 1
:
SELECT *
FROM X_10000 a
INNER JOIN X_10000 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);
对SQL Server采取的措施是相当不友好的。当两个表都没有任何相关索引时,嵌套循环联接通常不是一个好选择。这是计划:
该查询在我的计算机上花费了13秒,从表假脱机中提取了100000000行。但是,我不明白为什么查询必须很慢。查询优化器具有通过索引假脱机动态创建索引的能力。该查询似乎将是索引假脱机的理想选择。
以下查询返回与第一个查询相同的结果,具有索引假脱机,并且在不到一秒钟的时间内完成:
SELECT *
FROM X_10000 a
CROSS APPLY (SELECT TOP (9223372036854775807) b.ID FROM X_10000 b WHERE a.ID = b.ID) ca
OPTION (LOOP JOIN, MAXDOP 1);
此查询还具有索引假脱机,并且在不到一秒的时间内完成:
SELECT *
FROM X_10000 a
INNER JOIN X_10000 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (LOOP JOIN, MAXDOP 1);
为什么原始查询没有索引假脱机?是否有任何已记录或未记录的提示或跟踪标志集将为其提供索引假脱机?我确实找到了这个相关的问题,但是它不能完全回答我的问题,因此我无法获得神秘的跟踪标志来处理该查询。