Oracle查询未使用索引。

4

我是 Oracle 的新手,虽然我相当广泛地使用了 SQL Server,但我没有深入研究数据库设计的细节......特别是索引。因此,我花了很多时间通过教程学习索引......无论是概念上还是针对 Oracle 的。

为了将我的理解付诸实践,我设置了一个非常简单的表格并添加了一些基本索引。

CREATE TABLE "SYSTEM"."TBL_PERSON" 
   (    
        "PERSON_ID" NUMBER(10,0) NOT NULL ENABLE, 
        "FIRST_NAME" NVARCHAR2(120) NOT NULL ENABLE, 
        "MIDDLE_NAME" NVARCHAR2(120), 
        "LAST_NAME" NVARCHAR2(120) NOT NULL ENABLE, 
        "DOB" DATE NOT NULL ENABLE, 
        "IS_MALE" NCHAR(1) DEFAULT 'T' NOT NULL ENABLE,
        CONSTRAINT "TBL_PERSON_PK" PRIMARY KEY ("PERSON_ID")
   )

您可以看到,PERSON_ID字段包含了表中每条记录的唯一ROWID,并且是自增的主键。

(请不要因缺少SQL而感到困扰,除非它涉及到索引无法工作的问题。我尝试仅选择DDL中相关的SQL,可能会错过一些项目。那里有很多东西我认为与这个问题无关,所以我试图将其删除)

我在表上创建了几个额外的非聚集索引。

CREATE INDEX "SYSTEM"."IDX_LAST_NAME" ON "SYSTEM"."TBL_PERSON" ("LAST_NAME") 
CREATE INDEX "SYSTEM"."IDX_PERSON_NAME" ON "SYSTEM"."TBL_PERSON" ("FIRST_NAME", "LAST_NAME")

当我在以下SQL上运行“解释计划”时,我被通知PK索引已按预期使用。
select * from TBL_PERSON where PERSON_ID = 21

enter image description here

然而,当我运行一个查询,选择具有特定LAST_NAME的人时,LAST_NAME索引似乎被忽略了。

select * from TBL_PERSON where LAST_NAME = 'Stenstrom'

enter image description here

为什么不使用IDX_LAST_NAME?说实话,我在复合索引IDX_PERSON_NAME上也遇到了同样的问题。


3
虽然不是直接与您当前的问题相关,但有些事情可以使转移到Oracle更容易... 不要在SYSSYSTEM模式中创建自己的对象,而是为您的对象创建一个新的模式。 SYSSYSTEM由Oracle保留,因此该功能偶尔会在此处表现出不同行为。ROWID是Oracle中的保留字,指的是行的物理地址,而不是主键值。在新开发中很少需要使用NVARCHAR2数据类型,请选择Unicode字符集,改用VARCHAR2代替。 - Justin Cave
2
此外,Oracle 没有所谓的聚集索引(Clustered Index),所以将索引称为“非聚集型”只会让人感到困惑。在 Oracle 中最接近聚集索引(Clustered Index)的是索引组织表(Index-Organized Table)——如果你谈论“非聚集型索引(Non-clustered Index)”,人们可能会认为你创建了一个索引组织表而不是堆组织表(Heap-Organized Table)。 - Justin Cave
@a_horse_with_no_name(美国!不错 :))-我已经将计数增加到大约25个记录。在这个特定的查询中,将返回8条记录。 - Gary O. Stenstrom
@Justin Cave - 感谢您的建议。不过,NVARCHAR2 是否涵盖国际字符集呢? - Gary O. Stenstrom
1
对于25行中的8行使用索引没有意义。这25行可能都驻留在同一个数据库块中,这意味着全表扫描只需要进行一次I/O操作-最多2次。对于较大的表来说,仅当查询返回不超过总行数的约10-15%时,索引扫描通常才有效。 - user330315
显示剩余2条评论
1个回答

5
你的问题关键在于“基数”这一列。你估计只会返回五行数据。
Oracle有两种执行计划:
1. 加载数据页。扫描数据页上的五条记录并选择与条件匹配的记录。 2. 加载索引并扫描其以进行匹配。然后加载数据页并查找匹配的记录。
针对五条记录,Oracle认为第一种方法更快。如果将更多数据加载到表中,则应该会看到执行计划的变化。或者,如果您使用的是select last_name而不是select *,那么Oracle很可能会选择使用索引。

2
+1 但值得注意的是,基数5并不是Oracle对表中总行数的估计,它是在过滤后返回的行数的估计。 - Jon Heller
@jonearles...谢谢您的澄清。 - Gordon Linoff
大约需要多少记录才能使用索引?是几百,几千等?我现在有25个记录,仍然没有使用索引... 我的亲戚们都用完了!哈哈 - Gary O. Stenstrom
我添加了2020行数据,索引开始在“Explain Plan”中显示出来了 - 谢谢! - Gary O. Stenstrom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接