sql-server - 为什么一个查询非常慢,但相似表上的相同查询却眨眼间就运行完毕

标签 sql-server query-performance

我有这个查询......运行速度非常慢(几乎一分钟):

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、RelatedPrimeId、列 4-7 上有复合 PK。在RelatedPrimeId 上还有一个单独的索引。

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

我有相同的查询,使用 ATTRADDRESS 而不是 ATRGROUP。 ATTRADDRESS 具有与 ATRGROUP 相同的键和索引结构。它只有 11k 行,诚然,它较小,但在这种情况下,查询运行大约一秒,并返回 11k 行。

所以我的问题是这样的:

尽管结构相同,但一个表上的查询怎么会比另一个表慢这么多。

到目前为止,我已经在 SQL 2005 和(使用相同的数据库,已升级)SQL 2008 R2 上尝试过此操作。我们两个人独立获得了相同的结果,将相同的备份恢复到两台不同的计算机。

其他详细信息:

  • 即使在慢速查询中,括号内的位也能在不到一秒的时间内运行
  • 执行计划中可能有一条线索,但我不明白。这是其中的一部分,其中包含可疑的 320,000,000 行操作:

enter image description here enter image description here

但是,该表的实际行数略高于 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    

关于sql-server - 为什么一个查询非常慢,但相似表上的相同查询却眨眼间就运行完毕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7037116/

相关文章:

sql - SORT 操作的瓶颈

Mysql查询11000条记录只需要20分钟。如何优化下面的mysql查询select查询在where子句中不存在

mysql - 如何使使用左连接的查询更快?

SQL Server 选择多个值,如果没有找到值,则返回 null

SQL 更新,更新所有行 (MS-SQL 2008)

SQL如何处理页面上的大量评论/注释

sql - 为什么这个简单的查询不使用 postgres 中的索引?

java - 插入数据时出现 SQL 异常 : com. microsoft.sqlserver.jdbc.SQLServerException

mysql - 选择到/插入 SQL Server 查询重复项

MySQL UPDATE 语句性能