在SQL最后UNION忽略现有的索引(The last UNION in SQL ignores e

2019-10-19 02:21发布

这是一个精致的问题,我一直在挣扎了几天。

我有创造和建立索引上,我再创建一个存储过程来对运行静态表。 我的问题是奇怪的,我会尽我所能来解释它。

我运行相同的脚本来创建和跨越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始终运行在较大的表快......小表“偶尔”运行速度较慢。 速度范围从4000记录/第二个是“快”至70-记录/第二个是“慢”。

问题是,如果我在空白填充记录到目标表在某个点从70向上接近添加,没有任何其他的变化,速度增加至4000关口。 这是因为如果查询计划不是没有被正确地构建基于表中的记录数。

同时运行的数据库引擎调谐器和性能监视器我发现这个问题后,SQL忽略了最后一个联盟索引并且对一些查询表扫描。 而执行计划特别说我需要创建我已经在桌子上(因此索引提示)确切的指标。

所以我删除了第六选择UNION

这个问题依然如故。 然而,这一次却抱怨说,缺少指数再次是对工会的最后一个表(这是上面列出的第5和没有问题工作时,那里有6选工会)。

为什么这有什么想法正在发生或我能做些什么来避免呢? (除了在虚拟空白记录将增加表的大小或创建一个假的第七最终联盟......这两个提高性能)。

Answer 1:

现有的指标不是那么好,因为ID是领先的列。 这使得他们在这种情况下unseekable。 这里有一个更好的设置:

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索引搜索。 我们就需要拉一些严重的招数击败这一点。



Answer 2:

根据我的经验,大部分的时候,查询规划不使用合适的索引,因为它的更新的统计数据需要重新运行到正确的有优化工作。 这似乎有症状的事实,你的查询计划是不好的只是一些价值。

既然你虽然提供索引提示,这似乎unlikely-通常暗示会迫使规划者使用该索引,但也许这取决于你的供应商。



文章来源: The last UNION in SQL ignores existing INDEX