【问题标题】:How do indexes work behind the scenes索引如何在幕后工作
【发布时间】:2016-07-06 08:02:15
【问题描述】:

我是一个初学者。我知道索引对于性能提升是必要的,但我想知道它们在幕后是如何工作的。之前,我曾经认为我们应该对那些包含在 where 子句中的列进行索引(我意识到这是错误的)

例如,SELECT * from MARKS where marks_obtained > 50

考虑到这个表的主键上有一个聚集索引,我在 ma​​rks_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


【解决方案1】:

执行计划会回答这个问题,但我会猜测:在添加了附加列后,非聚集索引不再足以满足查询。这可能导致不再使用索引。它还可能导致每行一次聚集索引搜索。

学习阅读执行计划。为您测试的每个查询定期打开“实际执行计划”功能。

【讨论】:

    猜你喜欢
    • 2014-11-18
    • 2011-02-17
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多