使用UNION的执行计划首先显示的步骤少了很多,不幸的是,执行计划并不是全部,还有表扫描、逻辑读取、CPU使用率,所以这不是全部,结束它很大程度上取决于您的数据和指标。
第一个查询应该执行得更好,因为UNION 删除重复项发生在连接之前,导致对表 3 的表扫描次数减少。如果表 1 和表 2 中没有重复项,那么应该没有区别。
这可以通过一些示例数据来证明。我的所有示例都使用以下 5 个表(T4 和 T5 只是将输出转储到其中,因此您不必在 SQL fiddle 页面向下滚动数英里即可查看执行计划)
CREATE TABLE T1 (ID INT NOT NULL);
CREATE TABLE T2 (ID INT NOT NULL);
CREATE TABLE T3 (FK INT NOT NULL, SomeValue VARCHAR(10) NOT NULL);
CREATE TABLE T4 (ID INT NOT NULL, SomeValue VARCHAR(10) NULL);
CREATE TABLE T5 (ID INT NOT NULL, SomeValue VARCHAR(10) NULL);
并且全部使用以下进行测试(也反向完成以消除任何查询计划缓存):
INSERT INTO T4
SELECT ID, SomeValue
FROM T1
LEFT JOIN T3
ON ID = FK
UNION
SELECT ID, SomeValue
FROM T2
LEFT JOIN T3
ON ID = FK;
INSERT INTO T5
SELECT ID, SomeValue
FROM ( SELECT ID
FROM T1
UNION
SELECT ID
FROM T2
) T
LEFT JOIN T3
ON ID = FK;
示例 1 - T1 包含也在 T2 中的行
INSERT INTO T1 (ID)
SELECT *
FROM GENERATE_SERIES(0, 40000);
INSERT INTO T2 (ID)
SELECT *
FROM GENERATE_SERIES(20000, 60000);
INSERT INTO T3 (FK, SomeValue)
SELECT *, 'VALUE'
FROM GENERATE_SERIES(10000, 50000);
Example on SQL Fiddle 表明插入到 T4(UNION 之前 JOIN)表现更好。我已经运行了 25 次,其中 22 次插入到 T4 运行得更快。没有足够的数据从等式中消除服务器负载,因此正如预期的那样,存在一些异常情况。在this example 中插入的顺序颠倒了,再次看到了类似的结果。
示例 2 - table1 和 table2 中没有重复项
INSERT INTO T1 (ID)
SELECT *
FROM GENERATE_SERIES(0, 30000);
INSERT INTO T2 (ID)
SELECT *
FROM GENERATE_SERIES(30001, 60000);
INSERT INTO T3 (FK, SomeValue)
SELECT *, 'VALUE'
FROM GENERATE_SERIES(10000, 50000);
在这个例子中,执行时间更接近,并且经常在哪个方法执行得更快之间切换。
Sample Data
Sample Data 2
最后,重申已经提出的观点,如果您不期待被欺骗/不关心被欺骗,那么UNION ALL 将提高性能,但由于没有欺骗,两种方法的性能应该大致相似这应该在同等程度上改进这两种方法。我没有对此进行测试,但更改我用来检查的测试数据应该不是一项艰巨的任务。
编辑
我刚刚尝试了 SQL Fiddle 上的查询,它们显示出的差异比在我的本地计算机上的差异要大得多,因此请用少量盐来处理这些示例并在您自己的服务器上进行测试,这样更容易创造一个公平的测试环境!