zoukankan      html  css  js  c++  java
  • [Oracle SQL] NLS_SORT, NLS_COMP, NLSSORT, etc

    假设我有如下一张表 test_sort_comp,   注意列NAME上有一个索引。


    SQL
    > select * from test_sort_comp;

    NAME
    --------------------------------------------------
    Frank
    frank
    frAnk
    Bob
    BOB
    Candy
    candy

    7 rows selected.

    SQL
    > select index_name, table_name,column_name from user_ind_columns where table_name = 'TEST_SORT_COMP';

    INDEX_NAME                     TABLE_NAME                     COLUMN_NAME
    ------------------------------ ------------------------------ ------------------------------
    INDX_TEST_SORT_COMP            TEST_SORT_COMP                 NAME

    SQL
    >

     现在如果我需要查找Name为frank的记录,很简单,如下 (注意,设置了autotrace,方便查看执行计划)

    SQL> set autotrace on
    SQL
    > select * from test_sort_comp where name = 'frank';

    NAME
    --------------------------------------------------
    frank


    Execution 
    Plan
    ----------------------------------------------------------
    Plan hash value: 3593911111

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

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

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

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


    Statistics
    ----------------------------------------------------------
              0  recursive calls
              
    0  db block gets
              
    1  consistent gets
              
    0  physical reads
              
    0  redo size
            
    410  bytes sent via SQL*Net to client
            
    396  bytes received via SQL*Net from client
              
    2  SQL*Net roundtrips to/from client
              
    0  sorts (memory)
              
    0  sorts (disk)
              
    1  rows processed

    SQL
    >

     很显然,查询结果返回了一条记录,而且采用了index scan的方式。 

    如果现在我想得到name为frank的记录,但是不管字母的大小写,只要是f,r,a,n,k这几个字母按照这个顺序拼出来就可以,很显然表test_sort_comp中有3条记录满足条件 -- frank, Frank,  frAnk. 

    很容易想到一种方法,通过upper或lower函数,把name转成要么是大写要么是小写,但是由于在name上的index是个普通索引(不是函数索引),因此会采用全表扫描的方式,如下,

    SQL> select * from test_sort_comp where upper(name) = 'FRANK';

    NAME
    --------------------------------------------------
    Frank
    frank
    frAnk


    Execution 
    Plan
    ----------------------------------------------------------
    Plan hash value: 796376470

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

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

       
    1 - filter(UPPER("NAME")='FRANK')

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


    Statistics
    ----------------------------------------------------------
              5  recursive calls
              
    0  db block gets
             
    17  consistent gets
              
    0  physical reads
              
    0  redo size
            
    463  bytes sent via SQL*Net to client
            
    396  bytes received via SQL*Net from client
              
    2  SQL*Net roundtrips to/from client
              
    0  sorts (memory)
              
    0  sorts (disk)
              
    3  rows processed

     那么可不可以通过改变参数NLS_SORT, NLS_COMP来做呢? 可以尝试一下....

     但是如果单单设置NLS_SORT或NLS_COMP的话,是不起作用的,(NLS_COMP依赖于NLS_SORT, NLS_SORT作用于排序,

    SQL> alter session set NLS_SORT = BINARY_CI;

    Session altered.

    SQL
    > select * from test_sort_comp where name = 'frank';

    NAME
    --------------------------------------------------
    frank


    Execution 
    Plan
    ----------------------------------------------------------
    Plan hash value: 3593911111

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

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

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

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


    Statistics
    ----------------------------------------------------------
              0  recursive calls
              
    0  db block gets
              
    1  consistent gets
              
    0  physical reads
              
    0  redo size
            
    410  bytes sent via SQL*Net to client
            
    396  bytes received via SQL*Net from client
              
    2  SQL*Net roundtrips to/from client
              
    0  sorts (memory)
              
    0  sorts (disk)
              
    1  rows processed

    SQL
    >

    接着设置下参数NLS_COMP为ANSI,表示在比较的时候参照NLS_SORT的值,

    SQL> alter session set nls_comp = ansi;

    Session altered.

    SQL
    > select * from test_sort_comp where name = 'frank';

    NAME
    --------------------------------------------------
    Frank
    frank
    frAnk


    Execution 
    Plan
    ----------------------------------------------------------
    Plan hash value: 796376470

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

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

       
    1 - filter(NLSSORT("NAME",'nls_sort=''BINARY_CI''')=HEXTORAW('6672616E6B00') )

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


    Statistics
    ----------------------------------------------------------
              0  recursive calls
              
    0  db block gets
              
    8  consistent gets
              
    0  physical reads
              
    0  redo size
            
    463  bytes sent via SQL*Net to client
            
    396  bytes received via SQL*Net from client
              
    2  SQL*Net roundtrips to/from client
              
    0  sorts (memory)
              
    0  sorts (disk)
              
    3  rows processed

     虽然结果返回了三条记录,但是这条SQL语句的执行计划显示进行的是Full Table Scan. 虽然没有改变SQL语句的写法,但是ORACLE在执行SQL语句的时候,根据刚才设置的参数NLS_SORT, NLS_COMP对SQL语句进行了改写,

      1 - filter(NLSSORT("NAME",'nls_sort=''BINARY_CI''')=HEXTORAW('6672616E6B00') )

    其实相当于我们自己显示地用NLSSORT函数来查询,

    首先清楚当前session的参数设置,只需要从新connect一下就OK了,


    SQL
    > conn hr/hr;
    Connected.
    SQL
    > set autotrace on;

    SQL
    > select * from test_sort_comp where NLSSORT(NAME,'NLS_SORT=BINARY_CI'= NLSSORT('frank''NLS_SORT=BINARY_CI');

    NAME
    --------------------------------------------------
    Frank
    frank
    frAnk


    Execution 
    Plan
    ----------------------------------------------------------
    Plan hash value: 796376470

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

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

       
    1 - filter(NLSSORT("NAME",'nls_sort=''BINARY_CI''')=HEXTORAW('6672616E6B00') )

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


    Statistics
    ----------------------------------------------------------
              4  recursive calls
              
    0  db block gets
             
    17  consistent gets
              
    0  physical reads
              
    0  redo size
            
    463  bytes sent via SQL*Net to client
            
    396  bytes received via SQL*Net from client
              
    2  SQL*Net roundtrips to/from client
              
    0  sorts (memory)
              
    0  sorts (disk)
              
    3  rows processed

    SQL>

    因此通过设置NLS_SORT, NLS_COMP只是可以使得我们在不改变原有SQL的基础上来得到我们想要的结果,但是要注意SQL的执行计划会发生变化,有可能会对性能产生影响。

    [Update on 2011-1-5]

    本来打算写一篇关于NLS_SORT, NLS_COMP参数的设置的文章,结果发现之前已经写过了,记性好差:(   

    关于上面讲到的是用NLS_SORT/NLS_COMP对查询性能的影响,如果情况允许,可以通过创建一个FBI来避免full table scan的发生,比如

    create index fbi_tab on tab_name(nlssort(column_name, 'nls_sort=''binary_ci'''));

    关于NLS_SORT 和 NLS_COMP这两个参数的介绍,可以参见oracle的官方文档,如下

    NLS_SORThttp://download.oracle.com/docs/cd/B19306_01/server.102/b14237/initparams130.htm#REFRN10127

    NLS_COMP:http://download.oracle.com/docs/cd/B19306_01/server.102/b14237/initparams120.htm#REFRN10117

    需要注意的是,对NLS_SORT的介绍中有如下一段注释,

    Setting NLS_SORT to anything other than BINARY causes a sort to use a full table scan, regardless of the path chosen by the optimizer. BINARY is the exception because indexes are built according to a binary order of keys. Thus the optimizer can use an index to satisfy the ORDER BY clause when NLS_SORT is set to BINARY. If NLS_SORT is set to any linguistic sort, the optimizer must include a full table scan and a full sort in the execution plan.

    另外注意NLS_SORT和NLS_COMP 可以起修改的scope都是局限于session的,也就是只可以通过ALTER SESSION来改变这两个参数的设置。

    SQL> alter system set nls_sort=binary;
    alter system set nls_sort=binary
    *
    ERROR at line
    1:
    ORA
    -02096: specified initialization parameter is not modifiable with this option


    SQL
    > alter system set nls_comp=ansi;
    alter system set nls_comp=ansi
    *
    ERROR at line
    1:
    ORA
    -02096: specified initialization parameter is not modifiable with this option




    --------------------------------------
    Regards,
    FangwenYu
  • 相关阅读:
    eclipse用法和技巧
    eclipse常用快捷键集锦
    移动端input的虚拟键盘影响布局
    使用github page + Hexo搭建个人博客折腾记
    javascript数组的排序(sort,冒泡)
    响应式布局与媒体查询
    css属性选择器诸如Class^=,Class*= ,Class$=释义
    怎么预览 GitHub 项目里的网页或 Demo
    常见浏览器的兼容问题(一)
    jQuery常用交互效果
  • 原文地址:https://www.cnblogs.com/fangwenyu/p/1711969.html
Copyright © 2011-2022 走看看