database - 甲骨文 11g : Index not used in "select distinct"-query

标签 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;

我创建了两个索引:

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;

该表包含大约 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"

不幸的是,查询需要大约 1 小时才能执行,尽管我创建了上述两个索引。 解释计划显示 Oracle 使用“表完全访问”,即全表扫描。为什么没有使用索引?

作为实验,我测试了以下 SQL 命令:

SELECT DISTINCT
 "dynamic_col_1" "AS_dynamic_col_1", "dynamic_col_1_text" "AS_dynamic_col_1_text"
 FROM "tab"

即使在这种情况下,也不会使用索引并执行全表扫描。

在我的真实数据库中,该表包含更多索引列,如“dynamic_col_1”和“dynamic_col_1_text”。 整个索引文件的大​​小约为 50 GB。

更多信息:

  • 数据库是我本地电脑上安装的Oracle 11g。
  • 我使用 Windows 7 企业版 64 位。
  • 整个索引分为 3 个大约 50GB 大小的 dbf 文件。

如果有人能告诉我如何让 Oracle 在第一个查询中使用索引,我将非常高兴。 因为第一个查询被另一个程序用来从数据库中提取数据,所以它几乎不能改变。因此,最好改为调整表格。

提前致谢。

[2011 年 10 月 1 日:更新]

我想我已经找到了问题的解决方案。 dynamic_col_1dynamic_col_1_text 列都可以为空。在更改表以禁止两列中的“NULL”值并仅为 year 列添加新索引后,Oracle 执行快速索引扫描。 优点是现在执行查询大约需要 5 秒,而不是以前的 1 小时。

最佳答案

您确定索引访问会比全表扫描更快吗?作为一个非常粗略的估计,全表扫描比读取索引快 20 倍。如果 tab 在 2011 年拥有超过 5% 的数据,那么 Oracle 使用全表扫描也就不足为奇了。正如@Dan 和@Ollie 提到的那样,将 year 作为第二列,这将使索引变得更慢。

如果索引真的更快,那么问题很可能是错误的统计数据。有数百种统计数据可能不好的方式。非常简短,这是我首先要看的内容:

  1. 在有和没有索引提示的情况下运行一个解释计划。基数是否相差 10 倍或更多?时间是否减少了 10 倍或更多?
  2. 如果基数关闭,请确保表和索引上有最新的统计信息,并且您使用的是合理的 ESTIMATE_PERCENT(DBMS_STATS.AUTO_SAMPLE_SIZE 几乎总是 11g 的最佳选择)。
  3. 如果时间不对,请检查您的工作量统计数据。
  4. 你在使用并行吗? Oracle 总是假设并行性有近乎线性的改进,但在只有一个硬盘驱动器的台式机上,您可能根本看不到任何改进。

此外,这与您的问题并不相关,但您可能希望避免使用带引号的标识符。一旦使用它们,就必须在所有地方使用它们,这通常会使您的表和查询难以使用。

关于database - 甲骨文 11g : Index not used in "select distinct"-query,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7539453/

相关文章:

C# 使用 lambda 获取列值并读取代码后面的值

asp.net - 从数据库中以另一种格式检索日期

c - 用于 Oracle 数据库访问的线程安全全局 sqlca 结构

sql-server - 请帮我做这个查询(sql server 2008)

sql - Postgres 不使用索引,即使返回的行少于 5%

matlab - 如何在 MATLAB 中找到多维矩阵的最大值或最小值?

php - 多个服务层和数据库事务

database - 用于我的 ionic 项目的最佳数据库

sql - 需要有关汽车公司 ER 图的帮助

oracle - 在 Oracle SQL Developer 中发现未知的关系图符号