2013-05-30 133 views
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 
+0

你能运行'select referenceType,通过referenceType从MessageInbox组中计数(*);'?目前Oracle假设一半的值是“B”,一半是“I”。如果这是准确的,那么你可能不想使用索引。如果这不准确,请尝试用'begin dbms_stats.gather_table_stats(,'MESSAGINGINBOX')替换'analyze table';结束;'。另外,如果将ReferenceType列设置为“NOT NULL”,那么这将使Oracle在更多情况下使用索引。 –

+0

感谢Jonearles,它为我工作,我使用DBMS_STATS视图来收集统计信息。 BitMap索引在这里有效地工作。计数I = 142652和B只有55.我想知道是否有任何替代BitMap索引。问这个问题的原因是,我需要在不同的机器上执行这个查询,我们使用的标准版本不允许使用BitMap索引。 –

回答

0

一种方法是采取的事实,即指数将不包括条目,其中全套列的为空 - 即创建一个基于函数的索引只索引“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/

0

定期B树索引应该在这里工作,你只需要确保没有对引用类型列histogram

列数据倾斜,优化程序似乎知道这一点。它正确估计不同的计数为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'; 

直方图应至少提高所估计的基数(行),这是第一个步骤至固定的执行计划。