为啥使用 UNION 运算符的相同查询比使用 UNION ALL 的成本低得多?
Posted
技术标签:
【中文标题】为啥使用 UNION 运算符的相同查询比使用 UNION ALL 的成本低得多?【英文标题】:Why the same query with UNION operator costs much less than with UNION ALL?为什么使用 UNION 运算符的相同查询比使用 UNION ALL 的成本低得多? 【发布时间】:2019-06-04 13:07:22 【问题描述】:如果我使用 UNION,我的测试查询的成本是 910,如果我使用 UNION ALL,它是 46726。我使用 PL/SQLDeveloper。据我了解 UNION ALL 应该花费更少,因为它不需要花费时间来删除重复的行。有人可以向我解释为什么使用 UNION 的查询要快得多吗?
我的测试查询是: 选择 RELATED_ORDR.ORDR_ID ID ,RELATED_ORDR.ORDR_ID ,EXT_TYPE 类型 ,DECODE(RELATION, 1, GOR_CONTINGENCY, CONTINGENCY) CONTINGENCY_TYPE ,关系 ,DECODE(SIGN(ORDR_QTY),1,'B',-1,'S') BSS ,ORDR_QTY 数量 ,FXRE2_ORDER_AUDIT_REPORT.getOrderStatus(EXT_STATUS) 状态 ,STATUS_DT DT ,TRADE_ID TICKET ,CASE WHEN EXT_TYPE IN ('OR', 'CR', 'RE', 'RTE') THEN RATE2 其他价格 结束率 ,OFFER_ID 从 (选择 DISTINCT RO.ID ORDR_ID ,RO.CONTINGENCY_TYPE CONTINGENCY ,解码(RO.ID, GOR.ORDR_ID_PRIMARY, 1, 解码(RO.CONTINGENCY_ID,GOR.CONTINGENCY_ID,3, 解码(RO.CONTINGENCY_ID,GOR.ORDR_ID,2, 解码(RO.ORDR_ID_PRIMARY, GOR.ORDR_ID, 2)))) 关系 ,GOR.CONTINGENCY_TYPE GOR_CONTINGENCY FROM /*GIVEN_ORDR GOR --GIVEN*/ (SELECT to_number(regexp_substr('21153473;21151187;21151187;3;5240435','[^;]+',1,1)) 作为 ORDR_ID ,to_number(regexp_substr('21153473;21151187;21151187;3;5240435','[^;]+',1,2)) 作为 ORDR_ID_PRIMARY ,to_number(regexp_substr('21153473;21151187;21151187;3;5240435','[^;]+',1,3)) 作为 CONTINGENCY_ID , regexp_substr('21153473;21151187;21151187;3;5240435','[^;]+',1,4) 作为 CONTINGENCY_TYPE ,to_number(regexp_substr('21153473;21151187;21151187;3;5240435','[^;]+',1,5)) 作为 ACCT_ID FROM dual t) GOR --GIVEN ,ORDR_HIST RO --相关/链接 哪里 GOR.ACCT_ID = RO.ACCT_ID AND RO.ID != GOR.ORDR_ID-- 未给出 ORDR 并且 RO.STATUS_DT 不为空 AND (RO.ID = GOR.ORDR_ID_PRIMARY 或 RO.CONTINGENCY_ID = GOR.CONTINGENCY_ID 或 RO.CONTINGENCY_ID = GOR.ORDR_ID 或 RO.ORDR_ID_PRIMARY = GOR.ORDR_ID)) RELATED_ORDR ,ORDR_HIST WHERE ORDR_HIST.ID = (SELECT MAX(ID) FROM ORDR_HIST WHERE ID = RELATED_ORDR.ORDR_ID) 联合所有 SELECT RELATED_ORDR.ORDR_ID ID -- 只是为了兼容,不使用 ,RELATED_ORDR.ORDR_ID ,EXT_TYPE 类型 ,DECODE(RELATION, 1, GOR_CONTINGENCY, CONTINGENCY) CONTINGENCY_TYPE ,关系 ,DECODE(SIGN(ORDR_QTY),1,'B',-1,'S') BSS ,ORDR_QTY 数量 ,FXRE2_ORDER_AUDIT_REPORT.getOrderStatus(EXT_STATUS) 状态 ,STATUS_DT DT ,TRADE_ID TICKET ,CASE WHEN EXT_TYPE IN ('OR', 'CR', 'RE', 'RTE') THEN RATE2 其他价格 结束率 ,OFFER_ID 从 (选择 DISTINCT RO.ID ORDR_ID ,RO.CONTINGENCY_TYPE CONTINGENCY ,解码(RO.ID, GOR.ORDR_ID_PRIMARY, 1, 解码(RO.CONTINGENCY_ID,GOR.CONTINGENCY_ID,3, 解码(RO.CONTINGENCY_ID,GOR.ORDR_ID,2, 解码(RO.ORDR_ID_PRIMARY, GOR.ORDR_ID, 2)))) 关系 ,GOR.CONTINGENCY_TYPE GOR_CONTINGENCY FROM /*GIVEN_ORDR GOR --GIVEN*/ (SELECT to_number(regexp_substr('21153473;21151187;21151187;3;5240435','[^;]+',1,1)) 作为 ORDR_ID ,to_number(regexp_substr('21153473;21151187;21151187;3;5240435','[^;]+',1,2)) 作为 ORDR_ID_PRIMARY ,to_number(regexp_substr('21153473;21151187;21151187;3;5240435','[^;]+',1,3)) 作为 CONTINGENCY_ID , regexp_substr('21153473;21151187;21151187;3;5240435','[^;]+',1,4) 作为 CONTINGENCY_TYPE ,to_number(regexp_substr('21153473;21151187;21151187;3;5240435','[^;]+',1,5)) 作为 ACCT_ID FROM dual t) GOR --GIVEN ,ORDR_HIST RO --相关/链接 哪里 GOR.ACCT_ID = RO.ACCT_ID AND RO.ID != GOR.ORDR_ID-- 未给出 ORDR 并且 RO.STATUS_DT 不为空 AND (RO.ID = GOR.ORDR_ID_PRIMARY 或 RO.CONTINGENCY_ID = GOR.CONTINGENCY_ID 或 RO.CONTINGENCY_ID = GOR.ORDR_ID 或 RO.ORDR_ID_PRIMARY = GOR.ORDR_ID)) RELATED_ORDR ,指令 WHERE ORDR.ID = (SELECT MAX(ID) FROM ORDR_HIST WHERE ID = RELATED_ORDR.ORDR_ID) 按 ID 订购; 2个查询的计划是: 联合 0.078 秒成本卡。字节 CPU 成本 IO 成本 临时空间 选择声明 910 4528 271695 214479428 905 联合所有 0.032 秒 选择语句 46726 3194117 198026200 970740819 46626 选择声明 910 4528 271695 214479428 905 排序唯一 909 4528 271695 172294190 905 UNION-ALL 哈希连接 551 1 75 45895432 550 嵌套循环 551 1 75 45895432 550 嵌套循环 551 1 75 45895432 550 统计收集器 嵌套循环 452 1 33 45187910 451 查看 U1R2_DEV 353 1 20 44482687 352 哈希唯一 353 1 18 44482687 352 嵌套循环 352 1 18 4775046 352 快速双 2 1 7271 2 分区范围 ALL 350 1 18 4767775 350 按本地索引 ROWID 批处理的表访问 U1R2 ORDR_HIST 350 1 18 4767775 350 索引范围扫描 U1R2 OH_ACCT_ID_IDX 101 1285 977115 101 查看推送的预测 SYS VW_SQ_1 99 1 13 705223 99 筛选 排序聚合 1 6 分区范围 ALL 99 1 6 705223 99 索引范围扫描 U1R2 ORDR_HIST2_ACCT_ID 99 1 6 705223 99 分区范围 ALL 98 1 698951 98 索引范围扫描 U1R2 ORDR_HIST2_ACCT_ID 98 1 698951 98 按本地索引 ROWID U1R2 ORDR_HIST 访问表 99 1 42 707523 99 分区范围 ALL 99 1 42 707523 99 表访问完整 U1R2 ORDR_HIST 99 1 42 707523 99 嵌套循环 356 1 60 44506492 355 嵌套循环 356 1 60 44506492 355 查看 U1R2_DEV 353 1 20 44482687 352 哈希唯一 353 1 18 44482687 352 嵌套循环 352 1 18 4775046 352 快速双 2 1 7271 2 分区范围 ALL 350 1 18 4767775 350 按本地索引 ROWID 批处理的表访问 U1R2 ORDR_HIST 350 1 18 4767775 350 索引范围扫描 U1R2 OH_ACCT_ID_IDX 101 1285 977115 101 索引范围扫描 U1R2 ORDR_AIM 2 1 15293 2 分区范围 ALL MIN/MAX 1 6 排序聚合 1 6 第一行 99 1 6 705223 99 索引范围扫描(最小值/最大值) U1R2 ORDR_HIST2_ACCT_ID 99 1 6 705223 99 按索引 ROWID U1R2 ORDR 3 1 40 23804 3 访问表 联合所有 0.032 秒 选择语句 46726 3194117 198026200 3970740819 46626 按 808 3194117 198026200 89696701 806 269771000 排序 UNION-ALL 嵌套循环 452 1 62 45190210 451 嵌套循环 452 1 62 45190210 451 查看 U1R2_DEV 353 1 20 44482687 352 哈希唯一 353 1 18 44482687 352 嵌套循环 352 1 18 4775046 352 快速双 2 1 7271 2 分区范围 ALL 350 1 18 4767775 350 按本地索引 ROWID 批处理的表访问 U1R2 ORDR_HIST 350 1 18 4767775 350 索引范围扫描 U1R2 OH_ACCT_ID_IDX 101 1285 977115 101 分区范围 ALL 98 1 698951 98 索引范围扫描 U1R2 ORDR_HIST2_ACCT_ID 98 1 698951 98 分区范围 ALL MIN/MAX 1 6 排序聚合 1 6 第一行 99 1 6 705223 99 索引范围扫描(最小值/最大值) U1R2 ORDR_HIST2_ACCT_ID 99 1 6 705223 99 按本地索引 ROWID U1R2 ORDR_HIST 访问表 99 1 42 707523 99 嵌套循环 356 1 60 44506492 355 嵌套循环 356 1 60 44506492 355 查看 U1R2_DEV 353 1 20 44482687 352 哈希唯一 353 1 18 44482687 352 嵌套循环 352 1 18 4775046 352 快速双 2 1 7271 2 分区范围 ALL 350 1 18 4767775 350 按本地索引 ROWID 批处理的表访问 U1R2 ORDR_HIST 350 1 18 4767775 350 索引范围扫描 U1R2 OH_ACCT_ID_IDX 101 1285 977115 101 索引范围扫描 U1R2 ORDR_AIM 2 1 15293 2 分区范围 ALL MIN/MAX 1 6 排序聚合 1 6 第一行 99 1 6 705223 99 索引范围扫描(最小值/最大值) U1R2 ORDR_HIST2_ACCT_ID 99 1 6 705223 99 按索引 ROWID U1R2 ORDR 3 1 40 23804 3 访问表【问题讨论】:
【参考方案1】:Union和Union all的区别如下。
UNION 确保您从两个表中获得 DISTINCT 记录。 UNION ALL 从两个表中提取所有重复记录。
您的 union all 查询成本较高的原因可能是 Oracle 正在获取更多行, 请检查这两个查询的解释计划,您可能会发现 Union all 查询可能比 union 查询做更多的处理。
【讨论】:
【参考方案2】:-
“成本”一词并不总是与查询执行所用的时间相关联。 “成本”具有更广泛的含义,而不仅仅是执行查询所花费的时间。 “成本”包括物理资源和逻辑资源。
UNION 运算符执行两项工作:根据 SELECTed 列查找不同的记录并对结果集进行排序。基本上,UNION 对结果集进行排序。这就是为什么您会在解释计划中看到“SORT UNIQUE”。
UNION ALL 没有查找唯一记录并对其进行排序的负担。它的工作是最简单的。将第二个查询的记录附加到第一个查询并返回结果。这就是为什么与使用 UNION 运算符的 SELECT 相比,检索时间更短的原因。与 UNION 相比,您需要查看的非常重要的一点是 UNION ALL 使用的物理和逻辑资源。
选择语句 46726 3194117 198026200 970740819 46626
在大多数情况下,Oracle DB 会找到以更简单的方式做事的方法。与 UNION 相比,如果您使用 UNION ALL 进行查询,Oracle DB 会更快乐。这就是为什么 UNION 比 UNION ALL 花费的时间更多,尽管 UNION ALL 比 UNION 使用更多的可用资源。
UNION 0.078sec ---> 执行时间更长。 UNION ----> 使用更少的资源。 成本卡。字节 CPU 成本 IO 成本 温度空间 选择语句 910 4528 271695 214479428 905
UNION ALL 0.032sec ---> 更少的执行时间。 UNION ALL ---> 使用更多资源。 成本卡。字节 CPU 成本 IO 成本 临时空间 选择语句 46726 3194117 198026200 970740819 46626
希望这能澄清您的疑问。
【讨论】:
以上是关于为啥使用 UNION 运算符的相同查询比使用 UNION ALL 的成本低得多?的主要内容,如果未能解决你的问题,请参考以下文章
mysql数据库多个表union all查询并排序的结果为啥错误