ora*_*r54 7 database oracle indexing
我的问题涉及Oracle 11g以及SQL查询中索引的使用.
在我的数据库中,有一个结构如下的表:
Table tab (
rowid NUMBER(11),
unique_id_string VARCHAR2(2000),
year NUMBER(4),
dynamic_col_1 NUMBER(11),
dynamic_col_1_text NVARCHAR2(2000)
) TABLESPACE tabspace_data;
Run Code Online (Sandbox Code Playgroud)
我创建了两个索引:
CREATE INDEX Index_dyn_col1 ON tab (dynamic_col_1, dynamic_col_1_text) TABLESPACE tabspace_index;
CREATE INDEX Index_unique_id_year ON tab (unique_id_string, year) TABLESPACE tabspace_index;
Run Code Online (Sandbox Code Playgroud)
该表包含大约1到2百万条记录.我通过执行以下SQL命令从中提取数据:
SELECT distinct
"sub_select"."dynamic_col_1" "AS_dynamic_col_1","sub_select"."dynamic_col_1_text" "AS_dynamic_col_1_text"
FROM
(
SELECT "tab".* FROM "tab"
where "tab".year = 2011
) "sub_select"
Run Code Online (Sandbox Code Playgroud)
不幸的是,查询需要大约1小时才能执行,尽管我创建了上述两个索引.解释计划显示Oracle使用"表完全访问",即全表扫描.为什么不使用索引?
作为实验,我测试了以下SQL命令:
SELECT DISTINCT
"dynamic_col_1" "AS_dynamic_col_1", "dynamic_col_1_text" "AS_dynamic_col_1_text"
FROM "tab"
Run Code Online (Sandbox Code Playgroud)
即使在这种情况下,也不使用索引并执行全表扫描.
在我的真实数据库中,该表包含更多索引列,如"dynamic_col_1"和"dynamic_col_1_text".整个索引文件的大小约为50 GB.
还有一些信息:
如果有人能告诉我如何让Oracle在第一个查询中使用索引,我真的很高兴.因为第一个查询被另一个程序用来从数据库中提取数据,所以很难改变.所以最好调整表格.
提前致谢.
[01.10.2011:更新]
我想我找到了问题的解决方案.两列dynamic_col_1
,并dynamic_col_1_text
可以为空.更改表以禁止两列中的"NULL"值并仅为列添加新索引后year
,Oracle执行快速索引扫描.优点是查询现在需要大约5秒执行而不是之前的1小时.
您确定索引访问速度比全表扫描更快吗?作为一个非常粗略的估计,全表扫描比读取索引快20倍.如果tab
2011年的数据超过5%,那么Oracle将使用全表扫描就不足为奇了.正如@Dan和@Ollie所提到的,year
作为第二列,这将使索引更慢.
如果索引确实更快,那么问题可能就是糟糕的统计数据.有数百种统计数据可能不好的方法.非常简短,这是我首先要看的内容:
此外,这与您的问题无关,但您可能希望避免使用带引号的标识符.一旦你使用它们,你必须在任何地方使用它们,它通常会使你的表和查询难以使用.
我不知道它是否相关,但我测试了以下查询:
SELECT DISTINCT
"dynamic_col_1" "AS_dynamic_col_1", "dynamic_col_1_text" "AS_dynamic_col_1_text"
FROM "tab"
WHERE "dynamic_col_1" = 123 AND "dynamic_col_1_text" = 'abc'
Run Code Online (Sandbox Code Playgroud)
该查询的解释计划显示 Oracle 在这种情况下使用索引扫描。
列dynamic_col_1
和dynamic_col_1_text
可为空。这对索引的使用有影响吗?
2011 年 10 月 1 日:更新]
我想我已经找到了问题的解决方案。列dynamic_col_1 和dynamic_col_1_text 都可以为空。在更改表以禁止两列中的“NULL”值并仅为列年份添加新索引后,Oracle 会执行快速索引扫描。优点是执行查询现在大约需要 5 秒,而不是像以前那样需要 1 小时。