sql-server – 为什么一个查询非常慢,但在类似的表上相同的查询在眨眼间运行

前端之家收集整理的这篇文章主要介绍了sql-server – 为什么一个查询非常慢,但在类似的表上相同的查询在眨眼间运行前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有这个查询……运行速度非常慢(差不多一分钟):
select distinct main.PrimeId 
from PRIME main 
join   
( 
select distinct p.PrimeId   from PRIME p   
left  outer join ATTRGROUP a 
on p.PrimeId = a.PrimeId   or p.PrimeId = a.RelatedPrimeId    
where a.PrimeId is not null and a.RelatedPrimeId is not null  
) mem  
on main.PrimeId = mem.PrimeId

PRIME表有18k行,并且在PrimeId上有PK.

ATTRGROUP表有24k行,在PrimeId,col2上有复合PK,然后是RelatedPrimeId,然后是cols 4-7. RelatedPrimeId上还有一个单独的索引.

查询最终返回8.5k行 – PRIME表上的PrimeId的不同值,与ATTRGROUP表上的PrimeId或RelatedPrimeId匹配

我有相同的查询,使用ATTRADDRESS而不是ATTRGROUP. ATTRADDRESS具有与ATTRGROUP相同的密钥和索引结构.它只有11k行,不过可以肯定它是小的,但在这种情况下,查询运行大约一秒钟,并返回11k行.

所以我的问题是:

尽管结构相同,但查询如何在一个表上比另一个表慢得多.

到目前为止,我已经在sql 2005上尝试了这一点,并且(使用相同的数据库,已升级)sql 2008 R2.我们两个人独立地获得了相同的结果,将相同的备份恢复到两台不同的计算机.

其他详情:

>即使在慢速查询中,括号内的位也会在不到一秒的时间内运行
>执行计划中可能存在一些线索,我不明白.这是它的一部分,有可疑的320,000,000行操作:

但是,该表上的实际行数略多于24k,而不是320M!

如果我在括号内重构查询的一部分,那么它使用UNION而不是OR,因此:

select distinct main.PrimeId 
from PRIME main 
join   
( 
select distinct p.PrimeId   from PRIME p   
left  outer join ATTRGROUP a 
on p.PrimeId = a.PrimeId
where a.PrimeId is not null and a.RelatedPrimeId is not null  
UNION
select distinct p.PrimeId   from PRIME p   
left  outer join ATTRGROUP a 
on p.PrimeId = a.RelatedPrimeId    
where a.PrimeId is not null and a.RelatedPrimeId is not null  
) mem  
on main.PrimeId = mem.PrimeId

…然后慢速查询需要一秒钟.

我非常感谢对此的任何见解!如果您需要更多信息,请告诉我,我会更新问题.谢谢!

顺便说一句,我意识到在这个例子中有一个冗余连接.这不容易被删除,因为在生产中,整个事物是动态生成的,括号中的位采用许多不同的形式.

编辑:

我在ATTRGROUP上重建了索引,没有太大的区别.

编辑2:

如果我使用临时表,那么:

select distinct p.PrimeId into #temp
from PRIME p   
left  outer join ATTRGROUP a 
on p.PrimeId = a.PrimeId   or p.PrimeId = a.RelatedPrimeId    
where a.PrimeId is not null and a.RelatedPrimeId is not null  

select distinct main.PrimeId 
from Prime main join   
#temp mem  
on main.PrimeId = mem.PrimeId

…然后,即使在原始的OUTER JOIN中使用OR,它也会在不到一秒的时间内运行.我讨厌像这样的临时表,因为它总是感觉像是承认失败,所以它不是我将要使用的重构,但我觉得有趣的是它会产生这样的差异.

编辑3:

更新统计数据也没有区别.

感谢您到目前为止的所有建议.

解决方法

根据我的经验,最好在JOIN子句中使用两个左连接而不是OR.
所以代替:
left  outer join ATTRGROUP a 
    on p.PrimeId = a.PrimeId   or p.PrimeId = a.RelatedPrimeId

我会建议:

left  outer join ATTRGROUP a 
    on p.PrimeId = a.PrimeId
    left  outer join ATTRGROUP a2
    on p.PrimeId = a2.RelatedPrimeId

猜你在找的MsSQL相关文章