删除语句中忽略了聚簇和覆盖索引。发生表扫描

时间:2012-11-16 20:22:18

标签: sql sql-server-2005 database-design indexing database-scan

为什么SQL Server 2005会更有效地执行表扫描而不是使用主键上的可用聚簇索引(并且只使用主键)?

声明主键上的非群集,非唯一索引,没有包含列。这让我感到困惑,我们已经有一个好办公室笑了。如果这个指数最终成为问题,那么我们就知道该拍哪个。不幸的是,它是一个生产网站,我不能把它撕掉,但如果有必要的话会制定计划。

可能问题不是精神缺陷的相反指数,但是......

根据FogLight PASS,当我们通过主键删除一行时,以下语句已导致在一个表上扫描约1000万行,每小时约600次:

DELETE FROM SomeBigTable WHERE ID = @ID

表DDL:

CREATE TABLE [SomeBigTable]
(
    [ID] [int] NOT NULL,
    [FullTextIndexTime] [timestamp] NOT NULL,
    [FullTextSearchText] [varchar] (max) NOT NULL,
    CONSTRAINT [PK_ID] PRIMARY KEY CLUSTERED
    (
        [ID] ASC
    )
) -- ...
ON PRIMARY

聚集索引约束详细信息:

ADD CONSTRAINT [PK_ID] PRIMARY KEY CLUSTERED
(
    [ID] ASC 
) WITH  PAD_INDEX = OFF
       ,STATISTICS_NORECOMPUTE = OFF
       ,SORT_IN_TEMPDB = OFF
       ,IGNORE_DUP_KEY = OFF
       ,ONLINE = OFF
       ,ALLOW_ROW_LOCKS = ON
       ,ALLOW_PAGE_LOCKS = ON
       ,FILLFACTOR = 75
ON PRIMARY

同一个表上的非唯一非聚集索引:

CREATE NONCLUSTERED INDEX [IX_SomeBigTable_ID] ON [SomeBigTable]
(
    [ID] ASC
) WITH  PAD_INDEX = OFF
       ,STATISTICS_NORECOMPUTE = OFF
       ,SORT_IN_TEMPDB = OFF
       ,IGNORE_DUP_KEY = OFF
       ,ONLINE = OFF
       ,ALLOW_ROW_LOCKS = ON
       ,ALLOW_PAGE_LOCKS = ON
       ,FILLFACTOR = 98
ON PRIMARY

[ID]列上的外键约束指向同样大的表。

使用相同的语句,600个表扫描大约是该表每小时总删除操作的约4%。因此,并非所有此语句的执行都会导致表扫描。

毋庸置疑,但无论如何都要这样说......这是我要发送包装的很多令人讨厌的I / O.

2 个答案:

答案 0 :(得分:1)

您是否尝试在桌面上重新计算statistics并清除proc cache? 例如像这样的东西:

USE myDatabase;
GO

UPDATE STATISTICS SomeBigTable;
GO

DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS

可能是sql server只是使用了错误的索引,因为当表中有不同的数据时,缓存的计划很糟糕。

答案 1 :(得分:1)

有些事要尝试,有些事要检查:

您是否正在运行DELETE SomBigTable where ID = @Parameter声明?如果是这样,是类型为int的@Parameter,还是与被删除的列不同的数据类型? (可能不是这样,但是我遇到了一个字符串被转换为unicode的情况,这导致了一个索引被忽略。)

制作数据库的副本并乱用它:

  • 尝试确定哪些删除导致扫描,哪些删除不导致
  • 是否与FK相关表中数据的存在或缺失有关?
  • 是否信任外键(通过sys.foriegn_keys检查)
  • 放弃FK。它有什么改变吗?
  • 删除第二个索引。这有什么改变吗?

可能不是这些,但是在弄乱它们时你可能会遇到真正的问题。