表字段的定义,null还是not null?

来源:互联网 发布:手机淘宝关注是收藏吗 编辑:程序博客网 时间:2024/05/02 01:39

一个分页查询SQL,T1表有3千多万条记录,SQL执行一次需要19秒:
SELECT  B2.* FROM
        (    SELECT  B1.*,  ROWNUM rnum
                FROM  (  SELECT  /*+ index_desc(t1 IDX_BAS_PAPPVACTINFO_0001) */
                                        T1.PA_CLINAME    AS T1__PA_CLINAME   ,
......
                                        T1.PA_OPTIME     AS T1__PA_OPTIME
                                FROM    CDMBAS.BAS_PAPPVACTINFO T1
                                WHERE   1=1   
                                ORDER BY PA_REQUNO DESC ,
                                         PA_ORDER DESC
                        ) B1
                WHERE   ROWNUM <= 21
        ) B2
WHERE   rnum > 0 ;

执行计划:


检查发现,在order by上使用的两个字段上存在联合索引,但是优化器没有使用。即使使用index的hint也没有使用索引。

再检查表结构,order by使用的两个字段都是可以为空(NULL)。Btree索引是不保存全为NULL的值,所以优化器为了保证查询结果的准确性,不可能使用索引(如果全为null的记录也是SQL的结果,那么只扫描索引就无法得出这些记录)。

跟业务人员沟通,这两个字段都不可能为空,因为,SQL可以改写为(其中红色部分也可以换成另外一个order by 的字段):

SELECT  B2.*
FROM
        (
                SELECT  B1.*,
                        ROWNUM rnum
                FROM
                        (
                                SELECT  
                                        T1.PA_CLINAME    AS T1__PA_CLINAME   ,
                                        T1.PA_REQUNO     AS T1__PA_REQUNO    ,
                                        T1.PA_CLICODE    AS T1__PA_CLICODE   ,
                                        T1.PA_STATUS     AS T1__PA_STATUS    ,
                                        T1.PA_APPVITEM   AS T1__PA_APPVITEM  ,
                                        '¨¢¡Â3¨¬?¡¤?¨²¨®?¨º¡À'   AS EA_USTIME        ,
                                        T1.PA_OPTKIND    AS T1__PA_OPTKIND   ,
                                        T1.PA_CURRKIND   AS T1__PA_CURRKIND  ,
                                        T1.PA_SUM        AS T1__PA_SUM       ,
                                        T1.PA_OPRID      AS T1__PA_OPRID     ,
                                        T1.PA_OPRNAME    AS T1__PA_OPRNAME   ,
                                        T1.PA_OPINSTCODE AS T1__PA_OPINSTCODE,
                                        T1.PA_OPINSTNAME AS T1__PA_OPINSTNAME,
                                        T1.PA_OPDATE     AS T1__PA_OPDATE    ,
                                        T1.PA_OPTIME     AS T1__PA_OPTIME
                                FROM    CDMBAS.BAS_PAPPVACTINFO T1
                                WHERE   1=1 and PA_REQUNO is not null
                                ORDER BY PA_REQUNO DESC ,
                                        PA_ORDER DESC
                        )
                        B1
                WHERE   ROWNUM <= 21
        )
        B2
WHERE   rnum > 0

这时SQL执行时间只需要几毫秒(sql monitor下面显示为0):


如果不改写SQL,而是更改表结构的定义,将两个字段其中任意一个从NULL改成NOT NULL,也是一样的效果。

看了这个案例,你还会对你的表字段的NULL还是NOT NULL随便定义吗?

顺便说一句,在使用NOT IN(select xxx from table)的SQL时,如果xxx的定义为NULL,在数据量大的时候,这个SQL的执行效率也是非常差的。NOT EXISTS不会受影响,但是这两个SQL不是等价的,NOT IN后面的结果集如果有NULL,那么整个SQL的结果为空;而NOT EXISTS不受结果集里面NULL记录的影响。


0 0