【发布时间】:2016-07-06 08:02:15
【问题描述】:
我是一个初学者。我知道索引对于性能提升是必要的,但我想知道它们在幕后是如何工作的。之前,我曾经认为我们应该对那些包含在 where 子句中的列进行索引(我意识到这是错误的)
例如,SELECT * from MARKS where marks_obtained > 50
考虑到这个表的主键上有一个聚集索引,我在 marks_obtained 列上创建了一个非聚集索引,因为它在我的 where 子句中。
我的看法:因此叶节点将包含指向聚集索引的指针,并且当聚集索引指向实际行时,它将选择整行(由于我的查询中的星号)
场景
我遇到了以下查询(来自创建了非聚集索引的 AdventureWorks DB),该查询运行良好,执行 3200000 行 直到出现新列所需的时间不到 一秒已插入其中:
查询
SELECT x.*
INTO#X
FROM dbo.bigProduct AS p
CROSS APPLY
(
SELECT TOP 1000 *
FROM dbo.bigTransactionHistory AS bth
WHERE
bth.ProductId = p.bth.ProductId
ORDER BY
TransactionDate DESC
) AS x
WHERE
p.ProductId BETWEEN 1000 AND 7500
GO
新插入的列
ALTER TABLE dbo.bigTransactionHistory
ADD CustomerId INT NULL
插入上述列后,花了 17 秒!意味着慢 17 倍。非聚集索引现在在索引中缺少 CustomerId 列。在包含 CustomerId 之后,问题就消失了。
问题 CustomerId 似乎是罪魁祸首,直到它被添加到索引中。 但是怎么做???
【问题讨论】:
-
您正在插入临时表,因此实际上 write 操作可能需要额外的时间。我想说的是,所有操作都不是“在空中”执行的,每一个操作都会产生后果。由于最近的相关缓存内容,先前的操作可能需要那么少的时间(在 DBCC DROPCLEANBUFFERS 之后它将执行多长时间?)先前的操作导致将 3.2M 行写入 tempdb。 17s有可能对tempdb进行了文件放大。列插入后发生了多少页拆分?之后您是否重新创建(碎片整理)聚集索引?
-
这不仅仅是关于“索引如何在选择上工作”。你所做的每一个动作都有效果。 Select 有效果,还有 insert、column create 和另一个 select-into。而且我不太明白您为什么开始谈论
MARKS表,而是在另外两个表上进行了测试。 -
DBCCDROPCLEANBUFFERS 在执行上述查询之前执行。是的,在新插入的列之后重新创建了聚集索引(包括 CustomerId 列)
-
按照 usr 提到的方式发布这两个计划。并且可能是 IO 统计信息。
标签: sql-server query-optimization non-clustered-index