假设我有两张桌子:
Table A
ProdID | PartNumber | Data...
1 | ABC-a | "Data A"
2 | (null) | "Data B"
3 | ABC-c | "Data C"
...
和
Table B
ProdID | PartNumber | DataB
(null) | ABC-a | "Data D"
2 | (null) | "Data E"
3 | (null) | "Data F"
(null) | ABC-z | "Data G"
...
不理想,但无论如何。我想要
ProdID | PartNumber | Data | DataB...
1 | ABC-a | "Data A" | "Data D"
2 | (null) | "Data B" | "Data E"
3 | ABC-c | "Data C" | "Data F"
(null) | ABC-z | (null) | "Data G"
所以我用
SELECT *
FROM Table1 T1
RIGHT JOIN Table2 T2 ON
T1.ProdID = T2.ProdID OR T1.PartNumber = T2.PartNumber
这正是我想要的,但似乎需要大约100倍于单独的任何一方。作为更复杂查询的一部分,OR
需要2分钟,而仅int
需要1秒,而nvarchar(50)
需要1秒。表“A”有~13k行,表“b”有~35k,整个查询返回〜40k。
查询计划
我认为这个“表盘管”可能是问题所在。
SQL Server 2008 R2 Express。想法?
答案 0 :(得分:4)
单独加入每个方式,然后合并结果:
SELECT T1.ProdID, T1.PartNumber, T1.Data, ISNULL(tprodid.DataB, tpartno.DataB) as DataB
FROM Table1 T1
LEFT JOIN Table2 tprodid ON T1.ProdID = tprodid.ProdID
LEFT JOIN Table2 tpartno ON T1.PartNumber = tpartno.PartNumber;
这将使用两个索引,并将表现良好。您可能希望根据自己的喜好调整ISNULL
逻辑。
答案 1 :(得分:0)
将查询更改为联合,您应该获得更好的性能:
Select * from Table1 Left Join Table2 On Table1.ProdID = Table2.ProdID
where Table1.PartNumber is null
union
Select * from Table1 Left Join Table2 On Table1.PartNumber = Table2.PartNumber
where Table1.ProdId is null
union运算符将消除重复的行。也就是说,两个查询返回的行只返回一次。所以这应该返回与主查询相同的数据。
答案 2 :(得分:0)
你仍然需要OR,但你可以通过FULL JOIN做得更好:
SELECT COALESCE(t1.ProdID,t2.ProdID) ProdID,
COALESCE(t1.PartNumber,t2.PartNumber) PartNumber,
t1.Data, t2.DataB
FROM TableA t1
FULL JOIN TableB t2 ON t1.ProdID = t2.ProdID OR t1.PartNumber = t2.PartNumber
性能较慢的原因是因为OR强制它与索引不匹配,强制手动比较一个整个表与另一个整个表。如果您仍然遇到FULL JOIN的性能问题,您可以通过添加部件号索引或使用索引提示告诉优化器您的ProdID索引仍然有用来修复它。
答案 3 :(得分:0)
虽然我不太了解MSSQL,但我会尝试至少为您的问题提供解决方案!
对于您可能想要加入的每个列使用LEFT JOIN
,然后合并结果如下所示,您应该会获得更好的结果:
SELECT
COALESCE(TA.ProdID, TB2.ProdID) AS ProdID,
COALESCE(TA.PartNumber, TB.PartNumber) AS PartNumber,
TA.Data,
COALESCE(TB.Data2, TB2.Data2) AS Data2
FROM TableA TA
LEFT JOIN TableB TB On TA.ProdID = TB.ProdID
LEFT JOIN TableB TB2 On TA.PartNumber = TB2.PartNumber
GROUP BY ProdId
虽然完全猜测,但我会说它可能仅限于每个连接只使用一个索引,强制它使用全表扫描来执行其中一个列。您可以尝试将两列放入一个索引中,并将该索引用作连接的索引提示,并查看其执行情况。
答案 4 :(得分:0)
我喜欢Jeff Siver关于使用UNION
的建议,尽管他建议的查询是错误的。这是一个可能的解决方案:
SELECT *
FROM Table1 T1
JOIN Table2 T2
ON T1.ProdID = T2.ProdID
UNION
SELECT *
FROM Table1 T1
JOIN Table2 T2
ON T1.PartNumber = T2.PartNumber
UNION
SELECT NULL, NULL, NULL, *
FROM Table2 T2
WHERE NOT EXISTS (
SELECT *
FROM Table1 T1
WHERE T1.ProdID = T2.ProdID
)
AND NOT EXISTS (
SELECT *
FROM Table1 T1
WHERE T1.PartNumber = T2.PartNumber
);