2011-11-29 37 views
2

比方说,我有两个表:性能与连接或

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分钟,<需要1秒,int需要1秒,nvarchar(50)需要1秒。表“A”具有〜13k行,表“b”具有〜35k并且整个查询返回〜40k。

查询计划 OR query int nvarchar

我觉得这个 “表后台打印” 可能是问题。 enter image description here

SQL Server 2008 R2 Express。思考?

+0

您的结果与您的源数据不匹配,因为TableA和TableB都有一个ProdID 4,但该记录的结果显示为空ProdID。如果其中一个源表有空,或者结果是否有prodID 4? –

+0

我已经更新了示例,希望更清楚。 – Fowl

+0

Gee很好的例子很难! – Fowl

回答

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逻辑。

+0

即时,谢谢,我真的不喜欢必须通过使用COALESCE“做它的工作” – Fowl

+0

如果有人感兴趣,这里是最后一个查询 SELECT COALESCE (a.ProdID,b1.ProdID,b2.ProdID)AS ProdID, COALESCE(a.PartNum,b1.PartNum,b2.PartNum)AS PartNum, a.Data COALESCE(b1.DataB,b2.DataB)AS数据B FROM表1 AS一 RIGHT OUTER JOIN表2 AS B2 ON a.ProdID = b2.ProdID RIGHT OUTER JOIN表2 为B1 ON a.PartNum = b1.PartNum – Fowl

+1

您的代码不能运行(提示:'T2'不是一个有效的相关名称),结果集与OP的不一样(你的回报有三行,OP的有四行,再加上你缺少的列),你没有明显的原因改变了'RIGHT'到'LEFT'。你还会得到三个赞誉和“正确答案”奖!你的秘密是什么? ;) – onedaywhen

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 

工会运营商将消除重复行。也就是说,两个查询返回的行只会返回一次。所以这应该返回与您的主要查询相同的数据。

+1

这不会做他想做的事,因为它不会给数据A和数据B以相同的关系 –

+0

为什么它不给数据A和数据B?这应该返回相同的结果。 –

+0

该联盟的结果将只有三列。他正在寻找4列的结果。 –

0

你仍然需要OR,但你可以做一个完整的好一点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索引仍然有帮助。

+0

使用样品数据,您会得到2个零件编号为Abc-a的记录吗? – Tahbaza

+0

不幸的是,这是在三分钟即将来临:( – Fowl

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 

虽然完全猜,我会说,它可能会受限于每个连接只使用一个索引,但是强制它使用全表扫描来完成其中一列。您可以尝试将两个列放入一个索引中,并将该索引用作连接上的索引提示,并查看它是如何执行的。

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 
        );