这是一个我已经苦苦挣扎了几天的精致问题。
我有一个静态表,我创建并构建索引,然后我创建一个存储过程来运行。我的问题很奇怪,我会尽力解释。
我运行相同的脚本来创建和执行194个数据库......其中绝大多数运行得非常快......但是在少数几个数据库中,它们的运行速度非常慢。
我们很清楚这里是INDEX:
CREATE UNIQUE CLUSTERED INDEX IX_ID
ON DC_DuplicateMatch(ID)
go
CREATE INDEX IX_LastName_FirstName
ON DC_DuplicateMatch(ID, LastName, FirstName)
GO
CREATE INDEX IX_LastName_PostalCode
ON DC_DuplicateMatch(ID, LastName, PostalCode)
GO
CREATE INDEX IX_LastName_YearBorn
ON DC_DuplicateMatch(ID, LastName, YearBorn)
GO
CREATE INDEX IX_FirstName_PostalCode
ON DC_DuplicateMatch(ID, FirstName, PostalCode)
GO
CREATE INDEX IX_FirstName_YearBorn
ON DC_DuplicateMatch(ID, FirstName, YearBorn)
GO
CREATE INDEX IX_PostalCode_YearBorn
ON DC_DuplicateMatch(ID, PostalCode, YearBorn)
GO
以下是存储过程:
CREATE PROC dbo.DC_GetPotentialDuplicates
@ID int,
@FirstName varchar(30),
@LastName varchar(30),
@PostalCode varchar(10),
@YearBorn varchar(4)
AS
SELECT *
FROM DC_DuplicateMatch WITH(INDEX(IX_LastName_FirstName))
WHERE ID > @ID AND
(LastName = @LastName AND
FirstName = @FirstName)
UNION
SELECT *
FROM DC_DuplicateMatch WITH(INDEX(IX_LastName_PostalCode))
WHERE ID > @ID AND
(LastName = @LastName AND
PostalCode = @PostalCode)
UNION
SELECT *
FROM DC_DuplicateMatch WITH(INDEX(IX_LastName_YearBorn))
WHERE ID > @ID AND
(LastName = @LastName AND
YearBorn = @YearBorn)
UNION
SELECT *
FROM DC_DuplicateMatch WITH(INDEX(IX_FirstName_PostalCode))
WHERE ID > @ID AND
(FirstName = @FirstName AND
PostalCode = @PostalCode)
UNION
SELECT *
FROM DC_DuplicateMatch WITH(INDEX(IX_FirstName_YearBorn))
WHERE ID > @ID AND
(FirstName = @FirstName AND
YearBorn = @YearBorn)
UNION
SELECT *
FROM DC_DuplicateMatch WITH(INDEX(IX_PostalCode_YearBorn))
WHERE ID > @ID AND
(PostalCode = @PostalCode AND
YearBorn = @YearBorn)
GO
表定义
ID int no 4 10 0
FirstName varchar no 30
LastName varchar no 30
PostalCode char no 10
YearBorn varchar no 4
这个proc在较大的表上运行得更快...较小的表“偶尔”运行得更慢。速度范围从4,000记录/秒“快速”下降到70记录/秒“慢”。
问题是,如果我在某个时刻将空白填充记录添加到目标表中,而没有任何其他更改,则速度从70向上增加到接近4,000标记。就好像查询计划没有根据表中的记录数正确构建。
运行数据库引擎调优器和性能监视器后,我发现问题是SQL忽略了最后一个UNION上的INDEX,并对某些查询进行了表扫描。并且执行计划明确地说我需要创建我已经在表上的确切索引(因此INDEX Hints)。
所以我删除了第6个选择UNION
问题仍然存在;然而这一次它抱怨说缺失的指数再次出现在工会的最后一个表格上(这是上面列出的第5个表格,当有6个选择的UNIONS时没有问题)。
对于为什么会发生这种情况或者我可以采取哪些措施来避免它? (除了添加虚拟空白记录以增加表格大小或创建假的第7个最终联盟......这两者都会提高性能)。
答案 0 :(得分:1)
现有索引不是那么好,因为ID
是前导列。这使得他们在这种情况下无法实现。这是一个更好的设置:
CREATE INDEX IX_LastName_FirstName
ON DC_DuplicateMatch(LastName, FirstName, ID) INCLUDE (PostalCode, YearBorn)
GO
CREATE INDEX IX_LastName_PostalCode
ON DC_DuplicateMatch(LastName, PostalCode, ID) INCLUDE (FirstName, YearBorn)
GO
CREATE INDEX IX_LastName_YearBorn
ON DC_DuplicateMatch(LastName, YearBorn, ID) INCLUDE (FirstName, PostalCode)
GO
CREATE INDEX IX_FirstName_PostalCode
ON DC_DuplicateMatch(FirstName, PostalCode, ID) INCLUDE (LastName, YearBorn)
GO
CREATE INDEX IX_FirstName_YearBorn
ON DC_DuplicateMatch(FirstName, YearBorn, ID) INCLUDE (LastName, PostalCode)
GO
CREATE INDEX IX_PostalCode_YearBorn
ON DC_DuplicateMatch(PostalCode, YearBorn, ID) INCLUDE (LastName, FirstName)
GO
这些非常适合此查询。
每个查询都有6个索引。我们需要采取一些严厉的技巧来打败这个。
答案 1 :(得分:0)
根据我的经验,大多数情况下,查询规划器不使用适当的索引,因为需要重新运行update statistics以使优化器正常工作。这似乎表明您的查询计划只对某些值有害。
由于您提供索引提示,但这似乎不太可能 - 通常提示会强制规划人员使用该索引,但这可能取决于您的供应商。