1

有什么方法可以在 REFERENCETYPE 列上使用索引。下面是表结构和执行计划。

SQL> desc messaginginbox
 Name                                      Null?    Type
 ----------------------------------------- -------- ---------------------------
 MESSAGINGINBOXID                          NOT NULL VARCHAR2(28)
 REFERENCEID                               NOT NULL VARCHAR2(28)
 REFERENCETYPE                                      VARCHAR2(1)
 LISTINGID                                 NOT NULL VARCHAR2(28)
 CREATEDATE                                         DATE
 LASTUPDATED                               NOT NULL DATE
 UPDATEDBY                                 NOT NULL VARCHAR2(28)
 RENTERLISTINGMANAGERID                             VARCHAR2(28)
 OWNERLISTINGMANAGERID                              VARCHAR2(28)
 OCA                                       NOT NULL NUMBER(38)

SQL> create index idx_MESSAGINGIN_REFERENCE on MESSAGINGINBOX( REFERENCETYPE);
Index created.

SQL> analyze table MESSAGINGINBOX compute statistics;

Table analyzed.

SQL> select * from MESSAGINGINBOX where referencetype='B';

55 rows selected.

Execution Plan
-------------------------------------------------------------------------
| Id  | Operation         | Name           | Rows  | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                | 71354 |     9M|   873   (1)|
|*  1 |  TABLE ACCESS FULL| MESSAGINGINBOX | 71354 |     9M|   873   (1)|
-------------------------------------------------------------------------

SQL> create bitmap index idx_MESSAGINGIN_REFERENCE
     on MESSAGINGINBOX( REFERENCETYPE);

Index created.

SQL> analyze table MESSAGINGINBOX compute statistics;

Table analyzed.

SQL> select * from MESSAGINGINBOX where referencetype='B';

55 rows selected.

Execution Plan
-------------------------------------------------------------------------
| Id  | Operation         | Name           | Rows  | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                | 71354 |     9M|   873   (1)|
|*  1 |  TABLE ACCESS FULL| MESSAGINGINBOX | 71354 |     9M|   873   (1)|
-------------------------------------------------------------------------

SQL> select count(*) from MESSAGINGINBOX;

  COUNT(*)
----------
    142707

SQL> select distinct referencetype from MESSAGINGINBOX;

REFERENCETYPE
-------------
I             
B       

SQL> select count(distinct referencetype) from MESSAGINGINBOX;

COUNT(DISTINCTREFERENCETYPE)
----------------------------
                   2
4

2 回答 2

0

常规的 Btree 索引应该在这里工作,您只需要确保ReferenceType 列上有一个直方图。

列数据是倾斜的,优化器似乎知道这一点。它正确地将不同计数估计为 2,这就是为什么行估计几乎完全是行数除以 2。使用默认设置,Oracle 根据数据分布和列的使用方式创建直方图。

将不推荐使用analyze table的替换为dbms_stats.gather_table_stats并确保使用所有默认选项。在收集统计信息之前,您还需要对 ReferenceType 运行查询过滤。默认情况下,如果列未在谓词中使用,Oracle 将不会创建直方图。

运行此查询以查看是否生成了直方图:

select owner, table_name, column_name, histogram
from all_tab_columns
where table_name= 'MESSAGINGINBOX';

直方图至少应该改进估计的基数(行),这是修复执行计划的第一步。

于 2013-06-04T19:07:08.450 回答
0

一种方法是利用索引不包括完整列集为 NULL 的条目这一事实 - 即创建一个仅索引“B”记录的基于函数的索引:

CREATE INDEX just_the_Bs ON messaginginbox
  (CASE WHEN referencetype='B' THEN 'B' END);

但是,要使用索引,您必须使用相同的表达式进行查询,例如:

SELECT * FROM messaginginbox
WHERE (CASE WHEN referencetype='B' THEN 'B' END) = 'B';

鉴于与该谓词匹配的数据量相对较小,我希望这很可能使用索引范围扫描,然后按 rowid 查找表。

另一种方法是使用提示 - 但请注意,您可能需要添加更多提示(例如USE_NL)以避免一些非常糟糕的执行计划:

SELECT /*+INDEX(messaginginbox,idx_MESSAGINGIN_REFERENCE)*/ *
FROM messaginginbox WHERE referencetype='B';

特别是,请注意此处关于提示的建议 - 强制 CBO 使用特定计划可能需要很多提示:http: //jonathanlewis.wordpress.com/2013/05/28/how-to-hint/

于 2013-05-30T06:57:38.977 回答