替换“或”以避免两次评估条件并提高查询性能

时间:2013-08-21 10:49:00

标签: sql sql-server performance sql-server-2008 operators

“或”会降低查询性能,因为优化程序必须同时评估这两种情况。在复杂查询中,由于连接和繁重的表,评估两个条件变得非常昂贵。那么什么是“Or”运算符的替代品。我们每次都使用UNION吗?然后两次运行相同的复杂查询呢?相反,它也很昂贵。

修改

在下面的示例中,使用了六个表,它们每个都有超过100000个记录。 运算符位于 ccm.cID = 1001 (ma.coID = 2 AND ma.cID = 1001)之间。要获取记录,优化程序必须评估这两个条件。 :

SELECT dep.*
FROM dep with (NOLOCK)
JOIN ma with (NOLOCK) ON dep.mID = ma.mID  
LEFT JOIN ccm with (NOLOCK) ON ccm.cID = dep.cID  
LEFT JOIN ctm with (NOLOCK) ON ctm.cID = dep.cID  
LEFT JOIN cptgm with (NOLOCK) ON cptgm.cID = dep.cID  
WHERE ma.mtID = 3
AND dep.del = 0 AND dep.pub = 1   
AND (ccm.cID = 1001 OR (ma.coID = 2 AND ma.cID = 1001))  
AND ctm.tID = 2  
AND cptgm.ptgID IN (SELECT ptgID FROM psptgm WHERE psID = 145214
AND ib = 1)

如果我们将查询分成两部分,一次只有一个条件,然后将其与 UNION 结合,则性能会因为两次执行而降低。

1 个答案:

答案 0 :(得分:1)

在不了解或更改数据模型的情况下,您可以做很多事情

让我们一步一步地在这个例子中找到一个小优化:

首先将子查询拉出到连接,我相信这个更改会在某些版本的SQL上提供更好的性能。它也使查询更清晰。

SELECT dep.*
FROM dep with (NOLOCK)
JOIN ma with (NOLOCK) ON dep.mID = ma.mID  
LEFT JOIN ccm with (NOLOCK) ON ccm.cID = dep.cID  
LEFT JOIN ctm with (NOLOCK) ON ctm.cID = dep.cID  
LEFT JOIN cptgm with (NOLOCK) ON cptgm.cID = dep.cID  
JOIN psptgm with (NOLOCK) ON cptgm.ptgID = psptgm.ptgID and psptgm.ib = 1 and psptgm.psID = 145214
WHERE ma.mtID = 3
  AND dep.del = 0 
  AND dep.pub = 1   
  AND (ccm.cID = 1001 OR (ma.coID = 2 AND ma.cID = 1001))  
  AND ctm.tID = 2

我也喜欢这样写(我认为更清楚):

SELECT dep.*
FROM dep with (NOLOCK)
JOIN ma with (NOLOCK) ON dep.mID = ma.mID and  ma.mtID = 3
LEFT JOIN ccm with (NOLOCK) ON ccm.cID = dep.cID  
LEFT JOIN ctm with (NOLOCK) ON ctm.cID = dep.cID AND ctm.tID = 2
LEFT JOIN cptgm with (NOLOCK) ON cptgm.cID = dep.cID  
JOIN psptgm with (NOLOCK) ON cptgm.ptgID = psptgm.ptgID and psptgm.ib = 1 and psptgm.psID = 145214
WHERE dep.del = 0 
  AND dep.pub = 1   
  AND (ccm.cID = 1001 OR (ma.coID = 2 AND ma.cID = 1001))  

这使得仅连接修饰符与where子句更清晰。

现在很容易看到主要选择中的常用部分并将其拉出(从而减少了或子句所做的检查次数并提高了性能):

WITH prequery AS
(
  SELECT dep.*
  FROM dep with (NOLOCK)
  LEFT JOIN ctm with (NOLOCK) ON ctm.cID = dep.cID AND ctm.tID = 2
  LEFT JOIN cptgm with (NOLOCK) ON cptgm.cID = dep.cID  
  JOIN psptgm with (NOLOCK) ON cptgm.ptgID = psptgm.ptgID and psptgm.ib = 1 and psptgm.psID = 145214
  WHERE dep.del = 0 AND dep.pub = 1
)
SELECT dep.*
FROM prequery with (NOLOCK)
JOIN ma with (NOLOCK) ON dep.mID = ma.mID and  ma.mtID = 3
LEFT JOIN ccm with (NOLOCK) ON ccm.cID = dep.cID  
LEFT JOIN cptgm with (NOLOCK) ON cptgm.cID = dep.cID  
WHERE ISNULL(ccm.cID,0) = 1001 OR (ma.coID = 2 AND ma.cID = 1001)