我有以下测试架构:
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
)
小提琴是here。
执行计划可以在小提琴中找到。
看看当前的执行计划,有两棵树从一个连接中分支出来。两棵树几乎是相同的。这意味着由于T1
,UNION ALL
内部的查询已执行了两次。我有什么办法可以重写它,可能将UNION ALL
替换为JOIN
?
P.S。用测试模式和小提琴编辑问题。
答案 0 :(得分:1)
我使用以下方法得到了更好的计划:
;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'
答案 1 :(得分:-1)
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