0

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

编辑:

在下面的示例中,使用了六个表,每个表都有超过 100000 条记录。Or运算符介于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结合起来,性能会因为两次执行而下降。

4

1 回答 1

1

在不了解或更改数据模型的情况下,您无能为力

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

先把子查询拉出来加入一个join,相信这个改动会在某些版本的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 子句更清晰。

现在很容易在主选择中看到 or 的公共部分并将其拉出(从而减少 or 子句进行的检查次数并提高性能):

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)  
于 2013-08-21T11:33:36.300 回答