34

TopLevelParent、2 つの中間レベル テーブル MidParentA と MidParentB、および MidParentA または MidParentB の親を持つことができる子テーブルの 4 つのテーブルがあります (一方または他方の 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

この結合を行うためのより効率的な方法はありますか?

4

4 に答える 4

8

これが私が最終的に行ったことで、実行時間が 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 ビット フラグを使用して、2 つの同一の MidParentIds (つまり、1 の ID) がある場所を区別します。 IsMidParentA および IsMidParentB)。

時間を割いて回答してくれたすべての人に感謝します。

于 2013-11-01T13:33:10.440 に答える
1

それを書く別の方法:

LEFT JOIN Child c ON c.ParentAId = COALESCE(a.ParentAId, b.ParentBId)

編集

考えられる 1 つの方法は、最初に MidParentA をクエリし、次に MidParentB をクエリし、次にUNION結果をクエリすることです。

SELECT tlp.*,
       a.MidParentAId,
       null MidParentBId,
       c.ChildId
FROM TopLevelParent tlp
LEFT JOIN MidParentA a ON tlp.TopLevelPatientId = a.TopLevelPatientId
LEFT JOIN Child c ON c.MidParentAId = a.MidParentAId 
UNION
SELECT tlp.*,
       null MidParentAId,
       b.MidParentBId,
       c.ChildId
FROM TopLevelParent tlp
LEFT JOIN MidParentB b ON tlp.TopLevelPatientId = b.TopLevelPatientId
LEFT JOIN Child c ON c.MidParentBId = b.MidParentBId 

SQLFiddleのデモ

于 2013-11-01T10:58:12.937 に答える