`

oracle 查询时忽略大小写的方案研究

阅读更多

项目已经开发完毕,由于业务变动,某些查询需要忽略大小写,研究是否在不修改原来SQL语句的基础上,通过修改数据库参数满足业务。

实验如下:

SYS@huiche>conn /@huiche as sysdba;
已连接。

假如项目中有一张表 t:
SYS@huiche>create table t (name varchar2(10));

表已创建。

SYS@huiche>insert into t values ('test');

已创建 1 行。

SYS@huiche>insert into t values ('TEST');

已创建 1 行。

SYS@huiche>begin
  2  for i in 1..1000 loop
  3   insert into t values ('hello');
  4  end loop;
  5  end;
  6  /

PL/SQL 过程已成功完成。

SYS@huiche>commit;

提交完成。

SYS@huiche>begin
  2  dbms_stats.gather_table_stats(user,'t');
  3  end;
  4  /

PL/SQL 过程已成功完成。

SYS@huiche>set autotrace on;

假设业务SQL语句执行如下:
SYS@huiche>select * from t where name like 't%';

NAME
----------------------------------------
test


执行计划
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |   334 |  1670 |     2   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |   334 |  1670 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - filter("NAME" LIKE 't%')


统计信息
----------------------------------------------------------
        135  recursive calls
          0  db block gets
         18  consistent gets
          0  physical reads
          0  redo size
        417  bytes sent via SQL*Net to client
        400  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
          1  rows processed

SYS@huiche>create index t_name_index on t(name);

索引已创建。

创建索引以后走的是索引扫描。

SYS@huiche>select * from t where name like 't%';

NAME
----------------------------------------
test


执行计划
----------------------------------------------------------
Plan hash value: 837813613

---------------------------------------------------------------------------------
| Id  | Operation        | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |              |   334 |  1670 |     2   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| T_NAME_INDEX |   334 |  1670 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------

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

   1 - access("NAME" LIKE 't%')
       filter("NAME" LIKE 't%')


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          2  consistent gets
          1  physical reads
          0  redo size
        417  bytes sent via SQL*Net to client
        400  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

这张表的另一个业务SQL如下:

SYS@huiche>select * from t where name='test';

NAME
----------------------------------------
test


执行计划
----------------------------------------------------------
Plan hash value: 837813613

---------------------------------------------------------------------------------
| Id  | Operation        | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |              |   334 |  1670 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| T_NAME_INDEX |   334 |  1670 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------

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

   1 - access("NAME"='test')


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          2  consistent gets
          0  physical reads
          0  redo size
        417  bytes sent via SQL*Net to client
        400  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

现在为了忽略大小写,而修改SESSION级别的参数

SYS@huiche>alter session set nls_sort='BINARY_CI';

会话已更改。

SYS@huiche>alter session set nls_comp='LINGUISTIC';

会话已更改。

原来like的查询继续走的索引扫描(不过走的是索引全扫描)

SYS@huiche>select * from t where name like 't%';

NAME
----------------------------------------
TEST
test


执行计划
----------------------------------------------------------
Plan hash value: 3593352198

-------------------------------------------------------------------------------------
| Id  | Operation            | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |              |   334 |  1670 |     2   (0)| 00:00:01 |
|*  1 |  INDEX FAST FULL SCAN| T_NAME_INDEX |   334 |  1670 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

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

   1 - filter("NAME" LIKE 't%')


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          7  consistent gets
          2  physical reads
          0  redo size
        458  bytes sent via SQL*Net to client
        400  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          2  rows processed

原来的等于查询执行计划变成了全表扫描

SYS@huiche>select * from t where name='test';

NAME
----------------------------------------
test
TEST


执行计划
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |   334 |  1670 |     2   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |   334 |  1670 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - filter(NLSSORT("NAME",'nls_sort=''BINARY_CI''')=HEXTORAW('7465737
              400') )


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          5  consistent gets
          0  physical reads
          0  redo size
        458  bytes sent via SQL*Net to client
        400  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          2  rows processed

创建函数索引:
SYS@huiche>create index t_name_function_index on t(NLSSORT("NAME",'nls_sort=''BINARY_CI'''));

索引已创建。

like查询走的还是全索引扫描

SYS@huiche>select * from t where name like 't%';

NAME
----------------------------------------
TEST
test


执行计划
----------------------------------------------------------
Plan hash value: 3593352198

-------------------------------------------------------------------------------------
| Id  | Operation            | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |              |   334 |  1670 |     2   (0)| 00:00:01 |
|*  1 |  INDEX FAST FULL SCAN| T_NAME_INDEX |   334 |  1670 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

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

   1 - filter("NAME" LIKE 't%')


统计信息
----------------------------------------------------------
          8  recursive calls
          0  db block gets
          9  consistent gets
          0  physical reads
          0  redo size
        458  bytes sent via SQL*Net to client
        400  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          2  rows processed

相等查询走的是INDEX RANGE SCAN 扫描

SYS@huiche>select * from t where name='test';

NAME
----------------------------------------
test
TEST


执行计划
----------------------------------------------------------
Plan hash value: 4037064198

-----------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name                  | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                       |    10 |    50 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T                     |    10 |    50 |     1   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T_NAME_FUNCTION_INDEX |     4 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

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

   2 - access(NLSSORT("NAME",'nls_sort=''BINARY_CI''')=HEXTORAW('7465737400') )


统计信息
----------------------------------------------------------
         31  recursive calls
          0  db block gets
          9  consistent gets
          1  physical reads
          0  redo size
        458  bytes sent via SQL*Net to client
        400  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          2  rows processed

假设还有另一张表:业务是SQL语句根据主键查询,实验由于忽略大小写而影响其执行计划:

SYS@huiche>create table test (id number);

表已创建。

SYS@huiche>begin
  2  for i in 1..10000 loop
  3  insert into test values (i);
  4  end loop;
  5  end;
  6  /

PL/SQL 过程已成功完成。

SYS@huiche>commit;

提交完成。

SYS@huiche>create unique index test_id_index on test(id);

索引已创建。

SYS@huiche>select * from test where id=1;

        ID
----------
         1


执行计划
----------------------------------------------------------
Plan hash value: 3821046056

-----------------------------------------------------------------------------------
| Id  | Operation         | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |               |     1 |    13 |     1   (0)| 00:00:01 |
|*  1 |  INDEX UNIQUE SCAN| TEST_ID_INDEX |     1 |    13 |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

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

   1 - access("ID"=1)


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          2  consistent gets
          1  physical reads
          0  redo size
        413  bytes sent via SQL*Net to client
        400  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SYS@huiche>

看来其执行计划没有受到影响。

从以上实验可以看出,设置忽略大小写的参数以后,oracle 将根据语意来进行查询和排序,对有的执行计划是有一定的影响的,通过建立函数索引,可以使查询走向正确的执行计划。

假如在某些业务中又想使用区分大小写的查询怎么办?

可以用函数解决:

例如:

想查询t表中name为test的记录:

SYS@huiche>select * from t where nlssort(name,'nls_sort=''BINARY''')=nlssort('test','nls_sort=''BINARY''');

NAME
------------------------------
test


执行计划
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     2 |    14 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     2 |    14 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - filter("NAME"='test')

Note
-----
   - dynamic sampling used for this statement


统计信息
----------------------------------------------------------
         19  recursive calls
          0  db block gets
         20  consistent gets
          0  physical reads
          0  redo size
        411  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL>

以上查询,虽然查出结果,但是走的是全表扫描。

或者更好的方式是修改应用,等每次和数据库建立连接的时候动态设置session级别nls_sort和nls_comp的值,这样就解决了忽略大小写与不忽略大小写同时存在的问题。

思考中,未完待续。

请参考:http://dbua.iteye.com/blog/845245

1
2
分享到:
评论

相关推荐

    如何:让Oracle表及字段显示为区分大小写

    在此基础上如何使Oracle设计的表及其字段显示为区分大小写的形式,最后通过具体例子分析了使用默认全部大写和大小写混写的利弊,同时给出来不同情况在Power Desginer(PD)中的设置方案,及其在SQL Server的对比。

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    他认为对于SQL的学习是永无止境的,相信每一个查询Oracle数据库的人都需要精通SQL语言,才能写出高效的查询。他参与本书的编写就是为了帮助别人实现这一目标。 目录 封面 -11 封底 -10 扉页 -9 版权 -8 版权声明 -7...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    其一、就业面广:全球前100强企业99家都在使用ORACLE相关技术,中国政府机构,大中型企事业单位都能有ORACLE技术的工程师岗位。 其二、技术层次深:如果期望进入IT服务或者产品公司(类似毕博、DELL、IBM等),...

    Oracle9i的init.ora参数中文说明

    Oracle9i初始化参数中文说明 Blank_trimming: 说明: 如果值为TRUE, 即使源长度比目标长度 (SQL92 兼容) 更长, 也允许分配数据。 值范围: TRUE | FALSE 默认值: FALSE serializable: 说明: 确定查询是否获取表级...

    asp.net知识库

    忽略大小写Replace效率瓶颈IndexOf 随机排列算法 理解C#中的委托[翻译] 利用委托机制处理.NET中的异常 与正则表达式相关的几个小工具 你真的了解.NET中的String吗? .NET中的方法及其调用(一) 如何判断ArrayList,...

    超级有影响力霸气的Java面试题大全文档

    1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是...

    PHP基础教程 是一个比较有价值的PHP新手教程!

    你可以利用PHP连接包括Oracle,MS-Access,Mysql在内的大部分数据库。你可以在苍蝇上画图,编写程序下载或者显示e-mail。你甚至可以完成网络相关的功能。最好的是,你可以选择你的PHP安装版本需要哪些功能。引用...

    C#编程经验技巧宝典

    85 <br>0130 复制字符串中指定的字符 85 <br>0131 巧截字符串的数字 86 <br>0132 如何存储变长字符串 86 <br>0133 在进行字符串比较时忽略大小写 87 <br>0134 如何去除字符串尾空格 87 ...

    java 面试题 总结

    抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。...

    springmybatis

    以前曾经用过ibatis,这是mybatis的前身,当时在做项目时,感觉很不错,比hibernate灵活。性能也比hibernate好。而且也比较轻量级,因为当时在项目中,没来的及做很很多笔记。后来项目结束了,我也没写总结文档。已经...

    二十三种设计模式【PDF版】

    部代码研究时,这点尤其明显,因此,如果你不具备设计模式的基础知识(GoF 的设计模式),你很难快速的理解 J2EE。不能理解 J2EE,如何能灵活应用? 3.J2EE 只是适合企业计算应用的框架软件,但是 GoF 的设计模式几乎...

Global site tag (gtag.js) - Google Analytics