sql - 如何在 Oracle 10+ 中对包含 NULL 的列使用基于函数的索引?

标签 sql oracle

假设您在 Oracle 中有一个表:

CREATE TABLE person (
  id NUMBER PRIMARY KEY,
  given_names VARCHAR2(50),
  surname VARCHAR2(50)
);

使用这些基于函数的索引:
CREATE INDEX idx_person_upper_given_names ON person (UPPER(given_names));
CREATE INDEX idx_person_upper_last_name ON person (UPPER(last_name));

现在, given_names 没有 NULL 值,但为了论证, last_name 有。如果我这样做:
SELECT * FROM person WHERE UPPER(given_names) LIKE 'P%'

解释计划告诉我它使用索引但将其更改为:
SELECT * FROM person WHERE UPPER(last_name) LIKE 'P%'

它没有。 Oracle 文档说,只有在满足多个条件时才会使用基于函数的索引,其中之一是确保没有 NULL 值,因为它们没有被索引。

我试过这些查询:
SELECT * FROM person WHERE UPPER(last_name) LIKE 'P%' AND UPPER(last_name) IS NOT NULL


SELECT * FROM person WHERE UPPER(last_name) LIKE 'P%' AND last_name IS NOT NULL

在后一种情况下,我什至在 last_name 上添加了一个索引,但无论我尝试什么,它都使用全表扫描。假设我无法摆脱 NULL 值,如何让这个查询使用 UPPER(last_name) 上的索引?

最佳答案

可以使用索引,但优化器可能选择不将它用于您的特定示例:

SQL> create table my_objects
  2  as select object_id, object_name
  3  from all_objects;

Table created.

SQL> select count(*) from my_objects;
  2  /

  COUNT(*)
----------
     83783


SQL> alter table my_objects modify object_name null;

Table altered.

SQL> update my_objects
  2  set object_name=null
  3  where object_name like 'T%';

1305 rows updated.

SQL> create index my_objects_name on my_objects (lower(object_name));

Index created.

SQL> set autotrace traceonly

SQL> select * from my_objects
  2  where lower(object_name) like 'emp%';

29 rows selected.


Execution Plan
----------------------------------------------------------

------------------------------------------------------------------------------------
| Id  | Operation                   | Name            | Rows  | Bytes | Cost (%CPU)|
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                 |    17 |   510 |   355   (1)|
|   1 |  TABLE ACCESS BY INDEX ROWID| MY_OBJECTS      |    17 |   510 |   355   (1)|
|*  2 |   INDEX RANGE SCAN          | MY_OBJECTS_NAME |   671 |       |     6   (0)|
------------------------------------------------------------------------------------

您阅读的文档大概指出,就像任何其他索引一样,全空键不存储在索引中。

关于sql - 如何在 Oracle 10+ 中对包含 NULL 的列使用基于函数的索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/177240/

相关文章:

mysql - 根据与用户关联的项目获取数据列表

oracle - Oracle 中的日期是如何存储的?

mysql - 如何更新时间戳

sql - 如何将来自不同表的这两个查询合并为一个来计算百分比?

sql - 如何使用 SQL 减去值

java - JDBC ResultSet.getWarnings

oracle - 尝试使用 Hibernate 映射日期字段时缺少包含下划线的列

oracle - mybatis批量处理多表插入

java - JDBC 使用 where 条件在 resultSet 中返回 null 值。我尝试获取所有列,但它没有返回任何值

SQL 列引用无效