我不是在寻找以下优化,只是一个解释.我有这个查询:
SELECT COUNT(LARGE_A.id_a), SUM(LARGE_A.b_integer)
FROM LARGE_A
INNER JOIN MEDIUM_A ON LARGE_A.id_a = MEDIUM_A.id
INNER JOIN MEDIUM_B ON LARGE_A.id_b = MEDIUM_B.id
WHERE
MEDIUM_A.a_varchar2 LIKE 'Example%' AND
EXTRACT(YEAR FROM MEDIUM_B.a_datetime) = 2000 AND
LARGE_A.a_integer BETWEEN 0 AND 1000;
属性的类型写在它们的名称中。ID是整数。表LARGE_A
有1 000 000行,中等的有100 000行。ID是主键,但是表LARGE_A
有一个复合键(id_a, id_b)
。
然后我从V$SQL
视图中得到了以下执行计划,因为Autotrace在这一点上撒谎了。
SELECT STATEMENT
|SORT AGGREGATE
||HASH JOIN
|||NESTED LOOPS
||||NESTED LOOPS
|||||STATISTICS COLLECTOR
||||||NESTED LOOPS
|||||||TABLE ACCESS FULL LARGE_A
|||||||TABLE ACCESS BY INDEX ROWID MEDIUM_A
||||||||INDEX UNIQUE SCAN PK(MEDIUM_A)
|||||INDEX UNIQUE SCAN PK(MEDIUM_B)
||||TABLE ACCESS BY INDEX ROWID MEDIUM_B
|||TABLE ACCESS FULL MEDIUM_B
PK表示括号中给出的表的主键(整数)上的非聚集索引。这里我不使用IOT。
为什么优化器首先从索引PK(MEDIUM_B)
中逐个查询记录,然后使用ROWID获取其余的行,然后再次运行FULL表扫描?
1条答案
按热度按时间yqlxgs2m1#
你看到的是一个完整的计划,而不是真正的计划。(在
v$sql
中,full_plan_hash_value
和plan_hash_value
之间的差异)。自12 c起,Oracle有自适应计划,如果它在运行时发现它的基数猜测偏离很远,它就能够从一个计划更改到另一个计划。完整的计划提供了两个选项-散列连接+表B的全扫描,或表B的嵌套循环+索引访问。这完全取决于它从表A获得多少行,以确定哪一个是最佳计划。你可以这样看得最清楚:
你会在禁用的计划行旁边看到
-
标记,默认情况下不会使用...但它们仍然是计划的一部分,因此如果Oracle决定在执行中切换,它可以启用这些行并禁用原始默认值。要查看代码在运行时实际使用的内容,你必须通过获取v$session.sql_id / sql_child_number
来观察它,然后执行: