如何索引一个列是否在oracle中不是null查询?

时间:2012-02-09 11:00:26

标签: oracle indexing

我有一个包含大量列的表,我的查询就像这样

select  * from ( select my_table_id from my_table where start_time_local>=? 
and type_pk<>? and rule_pk=? and this_.name is not null order by start_time_gmt 
desc ) where rownum <= ?

如果我在

上创建索引
(start_time_local, type_pk, rule_pk, name) 

效率低,因为name是varchar(1024)。有没有更好的方法来索引像:

 (start_time_local, type_pk, rule_pk, isNotNull(name))

谢谢,

2 个答案:

答案 0 :(得分:2)

通常,查询的最佳索引是按照where子句中的所有内容的索引,按顺序降低选择性,然后按order by中的所有内容,按顺序降低选择性,然后选择所有内容你尚未编入索引。这意味着您将只使用索引而不是其背后的表。

然而,这种方法可能完全荒谬。由你决定你想走多远。

Selective表示索引中有多少值占总行数的百分比。通常,列中的值越多,在索引中查找的速度就越快。我通常会说,因为每条规则都有始终例外。

例如,如果rule_pk是表的主键,则可能足以对此列进行索引。这意味着您执行唯一的索引扫描,然后通过rowid进行表访问。

继续假设rule_pk是主键,start_time_local几乎是唯一的,其他列同样具有选择性最佳索引类似于: (rule_pk, start_time_local, type_pk, this_.name, start_time_gmt, my_table_id)。这虽然相当荒谬。

我建议阅读this部分文档,了解如何阅读解释计划并定期使用它们。

同样不要忘记在创建索引后收集统计信息,因为这会产生很大的不同:

dbms_stats.gather_table_stats( 'SCHEMA_NAME'
                             , 'TABLE_NAME'
                             , cascade => True
                             , method_opt => 'FOR ALL INDEXED COLUMNS'
                               );

应该足够了。

答案 1 :(得分:2)

如果某个字段仅针对NOT NULL 搜索而从不搜索实际值,则可以使用基于函数的索引来节省索引中的空间(并可能通过更好的缓存利用率)。例如:

CREATE TABLE THE_TABLE (
    ID INT PRIMARY KEY,
    THE_FIELD VARCHAR2(20)
);

CREATE INDEX THE_TABLE_IE1 ON THE_TABLE(NVL2(THE_FIELD, 'Y', 'N')) COMPRESS;

(索引中会有很多重复的'Y'和'N'值,因此可能值COMPRESS索引,如上所示。)

然后选择如下:

SELECT * FROM THE_TABLE WHERE NVL2(THE_FIELD, 'Y', 'N') = 'Y' -- Equivalent to THE_FIELD IS NOT NULL
SELECT * FROM THE_TABLE WHERE NVL2(THE_FIELD, 'Y', 'N') = 'N' -- Equivalent to THE_FIELD IS NULL

如果你不需要搜索NULL,你可以像这样挤出更多的空间效率:

CREATE INDEX THE_TABLE_IE1 ON THE_TABLE(NVL2(THE_FIELD, 'Y', NULL)) COMPRESS;
SELECT ID FROM THE_TABLE WHERE NVL2(THE_FIELD, 'Y', NULL) = 'Y' -- Equivalent to THE_FIELD IS NOT NULL

Oracle不会对NULL进行索引(在基于B树的索引中),因此NVL2(THE_FIELD,'Y', NULL )将完全消除索引中的THE_FIELD IS NULL行。