查询性能改进
Query Performance Improvement
这里有两个表格以不同的方式(Grp 和 Cat)对相同的项目(TBL1.ID 和 TBL2.Code)进行分类
每个Item只属于一个组(两个表中组名不同)
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
感谢任何具有更好性能的解决方案。
原始子查询有一个主要缺陷:它被设计为能够 return 多个值,但这会破坏整个查询。更改您的数据,以便任何组都连接到多个类别,并且它将失败(例如 (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 的操作更轻量级,而结果相同。
这里有两个表格以不同的方式(Grp 和 Cat)对相同的项目(TBL1.ID 和 TBL2.Code)进行分类
每个Item只属于一个组(两个表中组名不同) 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
感谢任何具有更好性能的解决方案。
原始子查询有一个主要缺陷:它被设计为能够 return 多个值,但这会破坏整个查询。更改您的数据,以便任何组都连接到多个类别,并且它将失败(例如 (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 的操作更轻量级,而结果相同。