newhappy的专栏

高级系统分析师,专注于对SOA,Ajax以及J2EE架构的研究,欢迎大家与我交流.Email:pleasechess@126.com

用户操作
[即时聊天] [发私信] [加为好友]
牛海彬ID:newhappy2008
489693次访问,排名93好友62人,关注者70
吉林大学软件工程硕士;一汽启明CPDM项目组软件工程师;
newhappy2008的文章
原创 187 篇
翻译 24 篇
转载 99 篇
评论 295 篇
newhappy的公告
非常感谢CSDN提供了这么好的一个平台,过去的一年为生活而忙忙碌碌,博客更新的不多,在新的一年里,我会勤快一点,多学一些技术,多交一些技术上的朋友.
最近评论
bingg:呵呵,任何事情都是发展的,变化的,楼主喜欢给事物下定义是不对的.鄙视一下
bingg:呵呵,任何事情都是发展的,变化的,楼主喜欢给事物下定义是不对的.鄙视一下
bjthemost:没什么没有人关心 Berkeley DB?
sz_haitao:上面这么多人重复发帖,看来本blog系统发完回复没有及时显示的bug是普遍存在的啊
VistaKobe:看完了,但不怎么样。数据库是很贵的!
文章分类
收藏
    相册
    友情连接
    114社区
    SOA-中间件
    张孝祥(RSS)
    杨洪波(RSS)
    沈东良
    许式伟(RSS)
    谭振林(RSS)
    银狐999(RSS)
    阿蒙专栏(RSS)
    存档
    订阅我的博客
    XML聚合  FeedSky

    转载 在Oracle中进行大小写不敏感的查询 收藏

    新一篇: FIRST_ROWS优化模式语言排序模糊匹配问题  | 旧一篇: 安装SQLSERVER2000时出现以前的某个程序安装已在安装计算机上创建挂起的文件操作

    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

    现在已经达到了大小写不敏感查询的目的了,这是由于设置比较方式是基于语义的,而不是基于二进制的,而语言方式下Aa是没有区别的。

    虽然目的达到了,但是还是要说明一下,这里虽然实现了对大小写不敏感的查询,但是这个结果的实现与表面看到的现象并不完全相同。

    从查询语句上看,似乎只是对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
     

    发表于 @ 2008年04月22日 19:55:00|评论(loading...)|收藏

    新一篇: FIRST_ROWS优化模式语言排序模糊匹配问题  | 旧一篇: 安装SQLSERVER2000时出现以前的某个程序安装已在安装计算机上创建挂起的文件操作

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © newhappy