我有一个包含大量列的表,我的查询就像这样
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))
谢谢,
答案 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
行。