在oracle中,命令和对象名称都是大小写不敏感的,因为oracle在处理语句时,将所有的名称和命令全部转化为大写。但是对于字符串中
在oracle中,命令和对象名称都是大小写不敏感的,因为oracle在处理语句时,将所有的名称和命令全部转化为大写。
但是对于字符串中的字符,无论是比较还是排序,都是大小写敏感的。这在oracle是默认方式,但不是唯一的方式。
下面看一个简单的例子:
sql> create table t (name varchar2(30));
表已创建。
sql> insert into t values ('a');
已创建 1 行。
sql> insert into t values ('a');
已创建 1 行。
sql> insert into t values ('b');
已创建 1 行。
sql> commit;
提交完成。
sql> create index ind_t_name on t(name);
索引已创建。
看一下默认情况下的排序和查询结果:
sql> select * from t order by name;
name
------------------------------
a
b
a
sql> select * from t where name = 'a';
name
------------------------------
a
这是最正常不过的结果了,下面修改会话默认的排序方式:
sql> alter session set nls_sort = binary_ci;
会话已更改。
sql> select * from t order by name;
name
------------------------------
a
a
b
sql> select * from t where name = 'a';
name
------------------------------
a
可以看到,通过设置排序方法为binary_ci,已经实现了对排序的大小写不敏感,但是查询语句中仍然是大小写敏感的,下面进一步修改比较方式:
sql> alter session set nls_comp = linguistic;
会话已更改。
sql> select * from t order by name;
name
------------------------------
a
a
b
sql> select * from t where name = 'a';
name
------------------------------
a
a
现在已经达到了大小写不敏感查询的目的了,这是由于设置比较方式是基于语义的,而不是基于二进制的,而语言方式下a和a是没有区别的。
虽然目的达到了,但是还是要说明一下,,这里虽然实现了对大小写不敏感的查询,但是这个结果的实现与表面看到的现象并不完全相同。
从查询语句上看,似乎只是对name进行一下判断就可以了,并未对列进行任何的操作,而实际上并非如此,下面看看这种情况下的执行计划:
sql> set autot on exp
sql> select * from t where name = 'a';
name
------------------------------
a
a
执行计划
----------------------------------------------------------
plan hash value: 1601196873
--------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time |
--------------------------------------------------------------------------
| 0 | select statement | | 1 | 17 | 3 (0)| 00:00:01 |
|* 1 | table access full| t | 1 | 17 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
1 - filter(nlssort(name,'nls_sort=''binary_ci''')=hextoraw('6100')
)
note
-----
- dynamic sampling used for this statement
oracle居然对列进行了操作,将name进行了nlssort操作,然后判断是否与目标值进行判断。不过oracle也没有其他的好方法进行处理,对等号右边的常量进行转换固然代价较低,但是sql的判断条件就由等于变成了in,这种转换恐怕变化更大。而且还要找到所有其他所有可能转换为目标值的常量,这个操作要比对列进行转换复杂得多。
不过这种方法就存在一个问题,就是oracle无法使用索引了,一方面是由于对列进行了操作,另一方面是由于oracle的索引是按照binary方式编码存储的。因此这种查询会采用全表扫描的方式。
sql> select /*+ index(t ind_t_name) */ * from t where name = 'a';
name
------------------------------
a
a
执行计划
----------------------------------------------------------
plan hash value: 1601196873
--------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time |
--------------------------------------------------------------------------
| 0 | select statement | | 1 | 17 | 3 (0)| 00:00:01 |
|* 1 | table access full| t | 1 | 17 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
1 - filter(nlssort(name,'nls_sort=''binary_ci''')=hextoraw('6100')
)
note
-----
- dynamic sampling used for this statement
这个情况,可以考虑建立一个函数索引来解决问题:
sql> create index ind_t_l_name on t(nlssort(name, 'nls_sort=binary_ci'));
索引已创建。
sql> select * from t where name = 'a';
name
------------------------------
a
a
执行计划
----------------------------------------------------------
plan hash value: 242883967
--------------------------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time |
--------------------------------------------------------------------------------------------
| 0 | select statement | | 1 | 17 | 2 (0)| 00:00:01 |
| 1 | table access by index rowid| t | 1 | 17 | 2 (0)| 00:00:01 |
|* 2 | index range scan | ind_t_l_name | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
predicate information (identified by operation id):
---------------------------------------------------
2 - access(nlssort(name,'nls_sort=''binary_ci''')=hextoraw('6100') )
note
-----
- dynamic sampling used for this statement