我问这个问题是为了更好地了解优化器的行为并了解索引假脱机的限制。假设我将 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;
Run Code Online (Sandbox Code Playgroud)
并强制嵌套循环连接MAXDOP 1:
SELECT *
FROM X_10000 a
INNER JOIN X_10000 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)
这是对 SQL Server 采取的相当不友好的操作。当两个表都没有任何相关索引时,嵌套循环连接通常不是一个好的选择。这是计划:
在我的机器上查询需要 13 秒,从 table spool 中提取了 100000000 行。但是,我不明白为什么查询必须很慢。查询优化器能够通过索引假脱机动态创建索引。这个查询似乎是索引假脱机的完美候选者。
以下查询返回与第一个相同的结果,具有索引假脱机,并且在不到一秒的时间内完成:
SELECT *
FROM X_10000 a
CROSS APPLY …Run Code Online (Sandbox Code Playgroud) 我知道出于性能原因应该避免它,但我试图展示一个条件,它显示为演示如何确保它不会出现。
但是,我最终得到了缺少索引警告,但优化器选择不创建临时索引。
我正在使用的查询是
SELECT
z.a
FROM dbo.t5 AS z WITH(INDEX(0))
WHERE
EXISTS
(
SELECT y.a
FROM dbo.t4 AS y
WHERE y.a = z.a
)
OPTION (MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)
表模式是:
CREATE TABLE dbo.t4
(
a integer NULL,
b varchar(1000) NULL,
p varchar(100) NULL
);
CREATE TABLE dbo.t5
(
a integer NULL,
b varchar(1000) NULL
);
CREATE UNIQUE CLUSTERED INDEX c1
ON dbo.t5 (a);
Run Code Online (Sandbox Code Playgroud)
两个表都有 10,000 行,您可以使用以下方法进行模拟:
UPDATE STATISTICS dbo.t4
WITH
ROWCOUNT = 10000,
PAGECOUNT = 1000;
UPDATE STATISTICS dbo.t5
WITH
ROWCOUNT = …Run Code Online (Sandbox Code Playgroud) 当我更新或删除分区表时,它在执行计划中显示急切的假脱机。
\n\n显示急切假脱机的更新查询执行计划的图像:- \n
我可以\xe2\x80\x99t 理解为什么只有当我在分区表上更新或删除时它才会执行急切假脱机操作,当我在非分区表上运行相同的查询时,它不会执行急切假脱机操作。
\n对大型表执行 UPDATE 语句后,执行计划会显示包含更新列的索引(所有非聚集索引)的更新。
在每次索引更新之前,都有一个 Eager Spool 操作符,后面跟着一个非常昂贵的 Sort。
总的来说,索引的更新消耗了大约50%的执行时间。
有没有办法优化索引并最小化成本?