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

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 'EastRiver' 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...