小编典典

SQL Server使用“或”运算符左联接

sql

我有四个表,即TopLevelParent,两个中级表MidParentA和MidParentB,以及一个子表,该表可以具有MidParentA或MidParentB的父级(一个或另一个midParent必须存在)。两个中级表都有一个父表TopLevelParent。

顶层表如下所示:

TopLevelId | Name
--------------------------
1          | name1   
2          | name2

MidParent表如下所示:

MidParentAId | TopLevelParentId |           MidParentBId | TopLevelParentId |
------------------------------------       ------------------------------------
1            |        1         |           1            |        1         |
2            |        1         |           2            |        1         |

子表如下所示:

ChildId | MidParentAId | MidParentBId
--------------------------------
1       |     1        |   NULL
2       |    NULL      |     2

我在较大的存储过程中使用了以下左连接,该存储过程正在超时,并且看起来最后一个左连接上的OR运算符是罪魁祸首:

SELECT *    
FROM TopLevelParent tlp
LEFT JOIN MidParentA a ON tlp.TopLevelPatientId = a.TopLevelPatientId
LEFT JOIN MidParentB a ON tlp.TopLevelPatientId = b.TopLevelPatientId
LEFT JOIN Child c ON c.ParentAId = a.ParentAId OR c.ParentBId = b.ParentBId

是否有更高效的方法来进行此加入?


阅读 209

收藏
2021-03-17

共1个答案

小编典典

这是我最后所做的,这使执行时间从52秒减少到4秒。

SELECT * 
FROM (
    SELECT tpl.*, a.MidParentAId as 'MidParentId', 1 as 'IsMidParentA' 
    FROM TopLevelParent tpl 
    INNER JOIN MidParentA  a ON a.TopLevelParentId = tpl.TopLevelParentID
UNION
    SELECT tpl.*, b.MidParentBId as 'MidParentId', 0 as 'IsMidParentA'  
    FROM TopLevelParent tpl 
    INNER JOIN MidParentB b ON b.TopLevelParentId = tpl.TopLevelParentID
UNION
    SELECT tpl.*, 0 as 'MidParentId', 0 as 'IsMidParentA'  
    FROM TopLevelParent tpl 
    WHERE tpl.TopLevelParentID NOT IN (
       SELECT pa.TopLevelParentID 
       FROM TopLevelParent tpl
       INNER JOIN MidParentA  a ON a.TopLevelParentId = tpl.TopLevelParentID
    UNION
       SELECT pa.TopLevelParentID 
       FROM TopLevelParent tpl
       INNER JOIN MidParentB b ON h.TopLevelParentId = tpl.TopLevelParentID
    )
) tpl
LEFT JOIN MidParentA a ON a.TopLevelParentId = tpl.TopLevelParentID
LEFT JOIN MidParentB b ON b.TopLevelParentId = tpl.TopLevelParentID
LEFT JOIN 
(
        SELECT  [ChildId]
                ,[MidParentAId] as 'MidParentId'
                ,1 as 'IsMidParentA'
        FROM Child c
        WHERE c.MidParentAId IS NOT NULL
   UNION
        SELECT [ChildId]
               ,[MidParentBId] as 'MidParentId'
               ,0 as 'IsMidParentA'
        FROM Child c
        WHERE c.MidParentBId IS NOT NULL
) AS c
ON c.MidParentId = tpl.MidParentId  AND c.IsMidParentA = tpl.IsMidParentA

这消除了正在发生的表扫描,因为我已经将顶级记录与它的中级父级(如果存在)进行了匹配,并将其标记在该记录上。

我也对子记录进行了相同的操作,这意味着我可以将子记录加入MidParentId的顶级记录中,并使用IsMidParentA位标志来区分存在两个相同的MidParentId的位置(例如,ID为1
IsMidParentA和IsMidParentB)。

感谢所有花时间回答的人。

2021-03-17