繁体   English   中英

如何优化此UNION查询?

[英]How do I optimize this UNION query?

我有这个测试模式:

CREATE TABLE A
(
  ID INT PRIMARY KEY,
  A VARCHAR(1),
  B VARCHAR(3),
  C VARCHAR(3),
  BID INT,
  DATE DATETIME2(7)
)

INSERT INTO A values
(1, NULL, 'AAA', 'XXX', 1, '2018-04-04'),
(2, NULL, 'BBB', 'YYY', 2, '2018-05-05'),
(3, NULL, 'CCC', 'ZZZ', 2, '2018-06-06')

CREATE TABLE B
(
  ID INT PRIMARY KEY,
  X VARCHAR(1),
  Y VARCHAR(1),
  Z VARCHAR(1)
)

INSERT INTO B values
(1, 'A', 'A', 'A'),
(2, 'B', 'B', 'B'),
(3, 'C', 'C', 'C'),
(4, 'D', 'D', 'D'),
(5, 'E', 'E', 'E')

CREATE TABLE C
(
  ID INT PRIMARY KEY,
  NAME VARCHAR(12)
)

INSERT INTO C values
(1, 'Mary'),
(2, 'John'),
(3, 'Peter')

CREATE TABLE D
(
  ID INT PRIMARY KEY,
  CID INT,
  R VARCHAR(3),
  S VARCHAR(3)
)

INSERT INTO D values
(1, 1, 'AAA', 'ABC'),
(2, 2, 'BBB', 'ZZZ'),
(3, 1, 'FOO', 'ZZZ'),
(4, 3, 'BAR', 'YYY')

我有这个问题:

WITH T1 AS
(
    SELECT A.ID, A.A, A.B, A.C, B.X, B.Y, B.Z
    FROM A
    LEFT JOIN B
    ON A.BID = B.ID
    WHERE A.DATE BETWEEN '2018-01-01' AND '2018-12-31'
)

(
    SELECT T1.ID, T1.A, T1.B AS VALUE, T1.X, T1.Y, T1.Z, T2.NAME
    FROM T1
    LEFT JOIN
    (
        SELECT C.NAME, D.R
        FROM C
        INNER JOIN D
        ON C.ID = D.CID
    ) AS T2
    ON T1.B = T2.R
)
UNION ALL
(
    SELECT T1.ID, T1.A, T1.C AS VALUE, T1.X, T1.Y, T1.Z, T2.NAME
    FROM T1
    LEFT JOIN
    (
        SELECT C.NAME, D.S
        FROM C
        INNER JOIN D
        ON C.ID = D.CID
    ) AS T2
    ON T1.C = T2.S
)

小提琴在这里

执行计划可以在小提琴中找到。

查看当前的执行计划,有两个树从连接中分支出来。 两棵树几乎完全相同。 这意味着由于UNION ALL T1内的查询已执行两次。 有什么方法可以重写这个,可能用JOIN替换UNION ALL吗?

PS编辑测试架构和小提琴的问题。

我有更好的计划使用以下内容:

;WITH T1 AS
(
    SELECT A.ID, A.A, A.B, A.C, B.X, B.Y, B.Z
    FROM A
    LEFT JOIN B ON A.BID = B.ID
    WHERE A.DATE BETWEEN '2018-01-01' AND '2018-12-31'
)
SELECT T1.ID, T1.A, IIF(v.N=1,T1.B,T1.C) AS VALUE, T1.X, T1.Y, T1.Z, C.NAME
FROM T1
CROSS JOIN (VALUES (1),(2)) v(N) -- or (SELECT 1 N UNION ALL SELECT 2) v
LEFT JOIN D ON ((T1.B = D.R AND v.N=1) OR (T1.C = D.S AND v.N=2))
LEFT JOIN C ON C.ID = D.CID

您也可以在没有CTE的情况下重写它(相同的计划,但看起来更短):

SELECT A.ID, A.A, IIF(v.N=1,A.B,A.C) AS VALUE, B.X, B.Y, B.Z, C.NAME
FROM A
LEFT JOIN B ON A.BID = B.ID
CROSS JOIN (VALUES (1),(2)) v(N) -- or (SELECT 1 N UNION ALL SELECT 2) v
LEFT JOIN D ON ((A.B = D.R AND v.N=1) OR (A.C = D.S AND v.N=2))
LEFT JOIN C ON C.ID = D.CID
WHERE A.DATE BETWEEN '2018-01-01' AND '2018-12-31'
WITH T1 AS
(
    SELECT A.ID, A.A, A.B, A.C, B.X, B.Y, B.Z
    FROM A
    LEFT JOIN B
    ON A.BID = B.ID
    WHERE A.DATE BETWEEN '2018-01-01' AND '2018-12-31'
)

(
    SELECT T1.ID, T1.A, T1.B AS VALUE, T1.X, T1.Y, T1.Z, C.NAME
    FROM T1
    Left JOIN D ON 
    T1.C = D.R
    LEFT JOIN C ON 
    C.ID = D.CID

)
UNION ALL
(
    SELECT T1.ID, T1.A, T1.C AS VALUE, T1.X, T1.Y, T1.Z, C.NAME  
    FROM T1
    Left JOIN D ON 
    T1.C = D.S
    LEFT JOIN C ON 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM