sql—集群中表的执行计划需要一行,而它应该需要多行

3mpgtkmj  于 2021-07-29  发布在  Java
关注(0)|答案(2)|浏览(323)

我在集群中创建了一个集群和一个表,定义如下:

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的信息。

ki0zmccv

ki0zmccv1#

不是虫子。
在数据库中运行此查询:

select UNIQUENESS from dba_indexes where index_name = upper('i_roald_dahl_titles');
UNIQUENES
---------
UNIQUE

原因是b树簇索引只存储存储该数据的集群块的数据库块地址,而不存储完整的数据 rowid 值,就像普通索引一样。
所以,当你为 title = 'Esio Trot' 可能有 rowid 价值观如下:

select rowid row_id, title from roald_dahl_novels n;
ROW_ID             TITLE                                                                                               
------------------ ----------------------------------------------------------------------------------------------------
ABocNnACmAABWsWAAL Esio Trot                                                                                           
ABocNnACmAABWsWAAM Esio Trot                                                                                           
ABocNnACmAABWsWAAN Esio Trot

b-tree集群索引只存储一个条目:“esio trot”,以及相应的数据库块地址。您可以通过以下方式在数据库中确认:

select num_rows from dba_indexes where index_Name = 'I_ROALD_DAHL_TITLES';
NUM_ROWS
 ----------
          1

这就是为什么你会得到 UNIQUE SCAN 报道。因为就指数而言,它就是这么做的。

wlzqhblo

wlzqhblo2#

实际执行计划也存在同样的问题(在19.5中测试)。可能是集群对象的显示执行计划的限制或缺陷。我会在asktom.oracle.com上问这个问题,希望得到甲骨文的官方(免费)答复。

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  f41cf1x2zdyyr, child number 0
-------------------------------------
select published_year   from roald_dahl_novels  where title = 'Esio
Trot'

Plan hash value: 2187850431

--------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation        | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |               |      1 |        |       |     1 (100)|      |      2 |00:00:00.01 |       3 |
|   1 |  TABLE ACCESS CLUSTER| ROALD_DAHL_NOVELS   |      1 |      2 |    28 |     1   (0)| 00:00:01 |      2 |00:00:00.01 |       3 |
|*  2 |   INDEX UNIQUE SCAN  | I_ROALD_DAHL_TITLES |      1 |      1 |       |     0   (0)|      |      1 |00:00:00.01 |       1 |
--------------------------------------------------------------------------------------------------------------------------------------

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):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------

   1 - "ROALD_DAHL_NOVELS".ROWID[ROWID,10], "TITLE"[VARCHAR2,100], "PUBLISHED_YEAR"[NUMBER,22]
   2 - "ROALD_DAHL_NOVELS".ROWID[ROWID,10]

32 rows selected.

相关问题