查询性能提升

时间:2018-10-12 16:40:45

标签: sql-server tsql query-performance

这里有两个表以不同的方式(Grp和Cat)对同一项目(TBL1.ID和TBL2.Code)进行分类

每个项目仅属于一个组(两个表中的组名不同) TBL2中的项目是TBL1中项目的子集

TBL2中仅现有猫的遗失物品,需要适当的猫。(不需要A4)

TBL1:

    Grp         ID
--------------------
    X1          A1        
    X1          B1        
    X1          C1        
    X1          D1        
    X2          A2        
    X2          B2        
    X2          C2        
    X2          D2        
    X3          A3        
    X3          B3        
    X4          A4        

TBL2:

   Cat         Code
--------------------
    1           A1        
    1           B1        
    1           C1        
    2           A2        
    2           B2        
    3           A3        
    5           A5        

所需:

    ID         Grp         Cat        
---------------------------------
    D1          X1          1         
    C2          X2          2         
    D2          X2          2         
    B3          X3          3         

此查询工作正常,但对于大量记录来说太慢了:

SELECT
  TBL1.ID
  ,TBL1.Grp
  ,(SELECT DISTINCT T2.Cat FROM TBL2 T2 WHERE T2.Code IN
  (SELECT T1.ID FROM TBL1 T1 WHERE T1.Grp = TBL1.Grp )) AS Cat

FROM TBL1
LEFT JOIN TBL2
ON TBL1.ID = TBL2.Code
WHERE TBL2.Code IS NULL
AND (SELECT DISTINCT T2.Cat FROM TBL2 T2 WHERE T2.Code IN
    (SELECT T1.ID FROM TBL1 T1 WHERE T1.Grp = TBL1.Grp ))  IS NOT NULL

任何具有更好性能的解决方案都是值得赞赏的。

1 个答案:

答案 0 :(得分:2)

原始子查询有一个主要缺陷:它被设计为能够返回多个值,但这会破坏整个查询。更改数据,以使任何组都连接到多个类别,并且该类别将失败(例如(1, 'A1') -> (2, 'A1'))。 DISTINCT确实可以帮助您避免使用给定的样本数据而失败,但无法帮助您避免使用不同的值。

如果没有多个匹配组,则没有指定要选择的类别。我使用了MAX

SELECT
  t.ID
  ,t.Grp
  ,c.Cat
FROM TBL1 t
INNER JOIN (
  SELECT g.Grp, MAX(c.Cat) Cat 
  FROM TBL1 g
  INNER JOIN TBL2 c
  ON c.Code = g.ID
  GROUP BY g.Grp
) c
ON c.Grp = t.Grp
WHERE NOT EXISTS(SELECT 1 FROM TBL2 t2 WHERE t2.Code = t.ID)

此处TBL1已加入连接到任何类别的所有组的列表INNER JOIN将仅保留与至少一个类别(相当于您的NOT NULL)相关的组。我将您的LEFT JOIN替换为NOT EXISTS,因为它对SQL SERVER的操作更轻巧,而结果却相同。