gpt4 book ai didi

oracle - 为什么此查询不使用 NLSSORT 索引?

转载 作者:行者123 更新时间:2023-12-02 08:42:44 25 4
gpt4 key购买 nike

在我们的应用程序中,我们在 session 级别配置了不区分大小写的语义:

alter session set NLS_COMP=LINGUISTIC;
alter session set NLS_SORT=BINARY_AI;

但是我想要一个包含具有二进制语义的 NAME 列的表,因此我相应地定义了一个基于函数的索引:

create table RAW_SCREEN (
ID number(10) constraint RSCR_PK primary key,
NAME nvarchar2(256) not null
);
create unique index RSCR_IDX on RAW_SCREEN (nlssort(NAME, 'NLS_SORT=BINARY'));

我希望下面的查询能够利用基于函数的索引:

select * from RAW_SCREEN where 
nlssort(NAME, 'NLS_SORT=BINARY') = nlssort(N'raw_screen1', 'NLS_SORT=BINARY');

但事实并非如此。查询计划显示表扫描。在实验过程中,我发现 NAME 上的简单索引可以解决问题:

create unique index RSCR_IDX2 on RAW_SCREEN (NAME);

再次运行查询时,RSCR_IDX2 索引已成功使用。

现在,这并不奇怪,但我不明白为什么优化器没有使用第一个基于函数的索引。索引表达式与 WHERE 条件中使用的表达式完全匹配。您知道为什么没有使用它吗?

注意:这是在 Oracle 10.2 上运行的

如果您想尝试一下,这里有一个完整的测试脚本:

alter session set NLS_COMP=LINGUISTIC;
alter session set NLS_SORT=BINARY_AI;

create table RAW_SCREEN (
ID number(10) constraint RSCR_PK primary key,
NAME nvarchar2(256) not null
);

create unique index RSCR_IDX on RAW_SCREEN (nlssort(NAME, 'NLS_SORT=BINARY'));
--create unique index RSCR_IDX2 on RAW_SCREEN (NAME);

begin
for i in 1..10000
loop
insert into RAW_SCREEN values (i, 'raw_screen' || i);
end loop;
end;
/
commit;

select * from RAW_SCREEN where nlssort(NAME, 'NLS_SORT=BINARY') = nlssort(N'raw_screen1000', 'NLS_SORT=BINARY');

最佳答案

表达式会在 DML 中转换为 NLS session 设置,但不会在 DDL 中转换。

这可以说是 NLSSORT(char, 'NLS_SORT=BINARY') 行为的错误。
来自 the manual :“如果指定 BINARY,则此函数返回 char。”但对于索引来说,情况并非如此。通常索引表达式不进行任何变换是非常方便的;如果它取决于 session 设置比 DBMS_METADATA.GET_DDL 这样的工具必须返回许多 alter session 语句。但在这种情况下,这意味着您可以创建一个永远不会的索引被使用。

解释计划显示了真实表达式。以下是 Oracle 如何在 session 中使用 nlssort(无需显式使用):

alter session set nls_comp=linguistic;
alter session set nls_sort=binary_ai;
drop table raw_screen;
create table raw_screen (
id number(10) constraint rscr_pk primary key,
name nvarchar2(256) not null
);
create unique index idx_binary_ai
on raw_screen (nlssort(name, 'nls_sort=binary_ai'));
explain plan for select * from raw_screen where name = n'raw_screen1000';
select * from table(dbms_xplan.display(format=>'basic predicate'));

Plan hash value: 2639454581

-----------------------------------------------------
| Id | Operation | Name |
-----------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS BY INDEX ROWID| RAW_SCREEN |
|* 2 | INDEX UNIQUE SCAN | IDX_BINARY_AI |
-----------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access(NLSSORT("NAME",'nls_sort=''BINARY_AI''')=HEXTORAW('0072006
10077005F00730063007200650065006E003100300030003000'))

此示例显示 nlssort(char, 'nls_sort=binary') 被 DML 删除:

alter session set nls_comp=linguistic;
alter session set nls_sort=binary_ai;
drop table raw_screen;
create table raw_screen (
id number(10) constraint rscr_pk primary key,
name nvarchar2(256) not null
);
create unique index idx_binary_ai on
raw_screen (nlssort(name, 'nls_sort=binary_ai'));
explain plan for select * from raw_screen where
nlssort(name,'nls_sort=binary') = nlssort(N'raw_screen1000','nls_sort=binary');
select * from table(dbms_xplan.display(format=>'basic predicate'));

Plan hash value: 237065300

----------------------------------------
| Id | Operation | Name |
----------------------------------------
| 0 | SELECT STATEMENT | |
|* 1 | TABLE ACCESS FULL| RAW_SCREEN |
----------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("NAME"=U'raw_screen1000')

总之 - 索引 DDL 需要与转换表达式完全匹配,这可能取决于 session 设置和二进制的异常行为。

关于oracle - 为什么此查询不使用 NLSSORT 索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20533547/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com