为什么在此执行计划上同一索引上同时存在过滤器和访问谓词?
考虑此查询的执行计划:
SQL_ID 1m5r644say02b, child number 0
-------------------------------------
select * from hr.employees where department_id = 80 intersect select *
from hr.employees where first_name like 'A%'
Plan hash value: 1738366820
------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 4 |00:00:00.01 | 8 | | | |
| 1 | INTERSECTION | | 1 | | 4 |00:00:00.01 | 8 | | | |
| 2 | SORT UNIQUE | | 1 | 34 | 34 |00:00:00.01 | 6 | 6144 | 6144 | 6144 (0)|
|* 3 | TABLE ACCESS FULL | EMPLOYEES | 1 | 34 | 34 |00:00:00.01 | 6 | | | |
| 4 | SORT UNIQUE | | 1 | 11 | 10 |00:00:00.01 | 2 | 2048 | 2048 | 2048 (0)|
| 5 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 11 | 10 |00:00:00.01 | 2 | | | |
|* 6 | INDEX SKIP SCAN | EMP_NAME_IX | 1 | 11 | 10 |00:00:00.01 | 1 | | | |
------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("DEPARTMENT_ID"=80)
6 - access("FIRST_NAME" LIKE 'A%')
filter("FIRST_NAME" LIKE 'A%')
执行计划在emp_name_ix
index上,使用相同的a%
谓词具有访问和过滤谓词。但是,访问谓词在这里是否足够,因为它们俩都会过滤相同的行?为什么它执行其他过滤器谓词?
何时访问和过滤器相同时是否有一般规则?基于gv $ sql_plan
,当操作具有访问或过滤器谓词时,它们的时间仅为1%。而且这种情况只有在操作和选项(例如索引)(完整/范围/跳过/唯一)和排序(JOIN/唯一)之类的选项中发生。
select *
from gv$sql_plan
where access_predicates = filter_predicates;
Considering the execution plan for this query :
SQL_ID 1m5r644say02b, child number 0
-------------------------------------
select * from hr.employees where department_id = 80 intersect select *
from hr.employees where first_name like 'A%'
Plan hash value: 1738366820
------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 4 |00:00:00.01 | 8 | | | |
| 1 | INTERSECTION | | 1 | | 4 |00:00:00.01 | 8 | | | |
| 2 | SORT UNIQUE | | 1 | 34 | 34 |00:00:00.01 | 6 | 6144 | 6144 | 6144 (0)|
|* 3 | TABLE ACCESS FULL | EMPLOYEES | 1 | 34 | 34 |00:00:00.01 | 6 | | | |
| 4 | SORT UNIQUE | | 1 | 11 | 10 |00:00:00.01 | 2 | 2048 | 2048 | 2048 (0)|
| 5 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 11 | 10 |00:00:00.01 | 2 | | | |
|* 6 | INDEX SKIP SCAN | EMP_NAME_IX | 1 | 11 | 10 |00:00:00.01 | 1 | | | |
------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("DEPARTMENT_ID"=80)
6 - access("FIRST_NAME" LIKE 'A%')
filter("FIRST_NAME" LIKE 'A%')
The execution plan has both access and filter predicates with the same A%
predicate here on the EMP_NAME_IX
index. But shouldn't the access predicate be enough here, as they both will filter the same rows? Why did it perform the additional filter predicate?
Is there a general rule for when both access and filter are the same? Based on GV$SQL_PLAN
, when an operation has either an access or a filter predicate, they are only equal about 1% of the time. And this situation only happens with operations and options like INDEX (FULL/RANGE/SKIP/UNIQUE) and SORT (JOIN/UNIQUE).
select *
from gv$sql_plan
where access_predicates = filter_predicates;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
大概您在
hr.employees
上有一个索引,其中包括first_name
列。但是,您是从*
中从hr.employees
中选择*
,以便从索引获得的行必须与表一起回到(即加入)。为了理解概念,它有助于将索引视为具有原始表主要钥匙的外键的普通表。当使用索引有帮助时,这两个表将加入。当索引包含所有需要的列时,该索引将单独使用。
在这种情况下,我们假设需要加入,因为您选择
*
。访问
hr.employee
Intersect
的第二个查询表,因为其其中等级 > filter s在索引列上,在过滤之前执行与索引的连接。像'a%'的第一次出现
“ first_name”是确定索引使用情况的原因。第二次出现是实际的过滤。过滤仅发生一次,而不是两次。
这些被列为不同的操作,因为决定使用索引(因此执行加入)具有其自身成本。
Presumably you have an index on
hr.employees
that includes thefirst_name
column. But you are selecting*
fromhr.employees
such that the rows obtained from the index would have to traced back (i.e. join) with the table.For conceptual understanding it helps to think of indexes as plain tables with a foreign key to the original table's primary key. When usage of indexes helps, these two tables are joined. The index is used alone when it contains all needed columns.
In this case we assume a join is required since you are selecting
*
. Whenaccess
ing thehr.employee
table for the second query of theintersect
, because itswhere
clausefilter
s on an index column, a join to the index is performed prior to filtering.The first occurrence of
"FIRST_NAME" LIKE 'A%'
is the reason usage of the index is decided. The second occurrence, is then the actual filtering. Filtering happens only once, not twice.These are listed as distinct operations as deciding to use the index (and therefore perform the join) has its own costs.