我在集群中创建了一个集群和一个表,定义如下:
create cluster roald_dahl_titles (
title varchar2(100)
);
create index i_roald_dahl_titles
on cluster roald_dahl_titles
;
create table ROALD_DAHL_NOVELS (
title varchar2(100),
published_year number
)
cluster roald_dahl_titles (title)
;
值得注意的是,这个索引不是用unique约束创建的,很有可能在roald\u dahl\u表中插入重复的值:
insert into roald_dahl_novels (title, published_year) values ('Esio Trot', 1990);
insert into roald_dahl_novels (title, published_year) values ('Esio Trot', 1990);
然后收集表和索引的统计信息,并查看使用索引的执行计划:
begin
dbms_stats.gather_table_stats(user, 'ROALD_DAHL_NOVELS');
dbms_stats.gather_INDEX_stats(user, 'I_ROALD_DAHL_TITLES');
end;
/
explain plan for
select published_year
from roald_dahl_novels
where title = 'Esio Trot';
select *
from table(dbms_xplan.display(format => 'ALL'));
不过,我发现执行计划的内容有些混乱:
Plan hash value: 2187850431
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 28 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS CLUSTER| ROALD_DAHL_NOVELS | 2 | 28 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | I_ROALD_DAHL_TITLES | 1 | | 0 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / ROALD_DAHL_NOVELS@SEL$1
2 - SEL$1 / ROALD_DAHL_NOVELS@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("TITLE"='Esio Trot')
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - "ROALD_DAHL_NOVELS".ROWID[ROWID,10], "TITLE"[VARCHAR2,100],
"PUBLISHED_YEAR"[NUMBER,22]
2 - "ROALD_DAHL_NOVELS".ROWID[ROWID,10]
作为操作2的一部分,它执行索引唯一扫描,这告诉我“esio trot”在集群中只出现一次。执行计划还说,对于该操作,它只希望返回一行。
列投影信息告诉我它希望返回一个列(这将是roald\u dahl\u表的rowid),因此这告诉我从该操作返回的rowid总数将是1(每行1个rowid对应1个rowid)。由于roald\u dahl\u表中的两行都有不同的rowid,因此此操作只能用于从表中返回一行。
当执行表访问集群操作时,执行计划(正确地)期望返回两行,这就是我发现的混乱。如果rowid正在访问这些行,那么我希望前面的操作返回(至少)两个rowid。如果rowid没有访问它们,我不希望前面的操作返回和rowids。
另外,在表访问集群中,表roald\u dahl\u的rowid列在列投影信息部分中。我没有尝试选择rowid,因此我不希望从该操作返回它。如果在任何地方,我希望它在 predicate 信息部分。
补充调查
我反复尝试将同一行插入表中,直到它包含同一行的65536个相同副本。在收集统计数据并查询索引i\u roald\u dahl\u标题的用户索引之后,我们得到了以下结果:
UNIQUENESS DISTINCT_KEYS AVG_DATA_BLOCKS_PER_KEY
UNIQUE 1 109
据我所知,这告诉我们:
索引是唯一的,因此我们希望每个键在索引中出现一次
索引只有一个不同的键('esio trot'),因此必须只有一个条目
索引期望我们的一个键与表中的几行匹配,跨越109个块
这似乎很矛盾—一个键与表中的几行相匹配意味着索引中必须有多个该键的条目(每个条目都与不同的rowid相匹配),这与索引的唯一性相矛盾。
在检查用户\扩展数据块时,索引只使用一个65536字节的扩展数据块,这没有足够的空间来保存表中每个rowid的信息。
2条答案
按热度按时间ki0zmccv1#
不是虫子。
在数据库中运行此查询:
原因是b树簇索引只存储存储该数据的集群块的数据库块地址,而不存储完整的数据
rowid
值,就像普通索引一样。所以,当你为
title = 'Esio Trot'
可能有rowid
价值观如下:b-tree集群索引只存储一个条目:“esio trot”,以及相应的数据库块地址。您可以通过以下方式在数据库中确认:
这就是为什么你会得到
UNIQUE SCAN
报道。因为就指数而言,它就是这么做的。wlzqhblo2#
实际执行计划也存在同样的问题(在19.5中测试)。可能是集群对象的显示执行计划的限制或缺陷。我会在asktom.oracle.com上问这个问题,希望得到甲骨文的官方(免费)答复。