在Oracle
中,如果几个大表之间存在连接,那么它们之间的性能差异是什么:
PLAN A:
SELECT A.a, B.b, C.c
FROM A join B on a.id = b.a
join C on b.id = c.b
WHERE A.ax = '...' and B.bx = '...' and C.cx = '....';
PLAN B:
SELECT TA.a, TB.b, TC.c
FROM (
SELECT A.a, A.id
FROM A
WHERE A.ax = '...'
) as TA
join
(
SELECT B.b, B.a, B.id
FROM B
WHERE B.bx = '...'
) as TB on TA.id = TB.a
join
(
SELECT C.c, C.b,
FROM C
WHERE C.cx = '...'
) as TC on TB.id = TC.b;
PLAN A
在所有表连接在一起后放置条件,但PLAN B
首先生成每个表的子集然后将它们连接在一起,PLAN B可以比PLAN A表现更好吗?
答案 0 :(得分:1)
您的两个查询都取决于几个因素,例如索引和不索引的内容,索引策略,服务器负载,数据缓存,您编写查询的方式等等。我假设where
中的列在回答时索引子句 -
我运行了两种类型的查询,发现了一个非常相似的结果。 (这可能是因为我的表和列的设置方式)。
解释计划A
的计划SELECT STATEMENT FIRST_ROWS
Cost: 9 Bytes: 446 Cardinality: 14
解释 B计划
的计划SELECT STATEMENT FIRST_ROWS
Cost: 12 Bytes: 448 Cardinality: 14
现在您看到两者花了相同的时间但理想情况下,计划A是最佳实践中的考虑因素(从经验来看,我已经看到Plan A
查询几乎被使用了到处都是Plan B
而不是那么多)
不同的查询在不同情况下的工作方式不同[而Oracle(或任何SQL引擎)会巧妙地选择最适合您的算法。]
编辑 - 我现在检查了更大的数据集
计划A 和计划B 都是相同的
SELECT STATEMENT FIRST_ROWS
Cost: 35,413 Bytes: 1,888,512 Cardinality: 59,016
答案 1 :(得分:0)
两个查询都会产生几乎相同的查询计划。
计划A 将花费更多时间执行Index Seeks(如果使用正确的索引),同时花费更少的时间执行表扫描。
计划B 将花费更多时间执行表格扫描,同时执行索引搜索的时间更少(如果使用适当的索引)。
计划A 更加强大和紧凑。
没有一个直接的答案,我上面所说的是粗略的一瞥答案。确定环境差异的最佳方法是测试结果。实际结果会影响表的设计方式,表的大小,先前的查询执行,缓存的内容以及一些不够简单的其他方面。优化器通常非常擅长选择最佳计划。
答案 2 :(得分:0)
首先,计划取决于表格的统计信息see dbms_stat。正确的统计确保正确的查询执行。例如DBMS_STATS.gather_schema_stats(' SCOTT');按架构see example
存储统计信息同时,还有一些改进计划的选择:
不要使用JOIN语法,只是" old"风格"其中"。它强制sql 分析器过滤每个表然后加入。提示/ * +领先()* / 确保表格按正确顺序处理:
SELECT /*+ leading(a b c) */ A.a, B.b, C.c
FROM A, B, C
WHERE A.ax = '...'
and a.id = b.a
and B.bx = '...'
and b.id = c.b
and c.cx = '....';
在" on"之后的每个表上放置过滤条件条件:
SELECT A.a, B.b, C.c
FROM A join B on a.id = b.a and B.bx = '...'
join C on b.id = c.b and C.cx = '....'
WHERE A.ax = '...';
如果您的表格非常庞大并且您想过滤它,请缓存结果 然后加入,你可以使用提示/ * + no_merge()* /:
SELECT /*+ no_merge(TA) no_merge(TB) no_merge(TC) */ TA.a, TB.b, TC.c
FROM (
SELECT A.a, A.id
FROM A
WHERE A.ax = '...'
) as TA
join
(
SELECT B.b, B.a, B.id
FROM B
WHERE B.bx = '...'
) as TB on TA.id = TB.a
join
(
SELECT C.c, C.b,
FROM C
WHERE C.cx = '...'
) as TC on TB.id = TC.b;
但最好是加入2个小表,哈希结果,然后加入第三个表:
SELECT /*+ no_merge(AB) */ AB.a, AB.b, TC.c
FROM (
SELECT /*+ use_hash(a b) */ A.a, A.id a_id, B.b, B.a b_a, B.id b_id
FROM A, B
WHERE A.ax = '...'
AND a.id = b.a
AND B.bx = '...'
) as AB,
(
SELECT C.c, C.b,
FROM C
WHERE C.cx = '...'
) as TC
WHERE AB.b_id = TC.b;
答案 3 :(得分:0)
我想在这里提出上述两个查询的执行计划并进行讨论,但是Pirate X解释得很好,所以我不会提到这一点,我完全同意他,但对我来说,我有时会经历连接条件中的where子句具有更好的性能(在时间的情况下)我的意思是可能编写计划A,因为以下可能更好,没有成本可以测试它:
SELECT A.a, B.b, C.c
FROM A join B on a.id = b.a and A.ax = '...'
join C on b.id = c.b and B.bx = '...' and C.cx = '....';
以这种方式,至少你没有句法上的where子句。