[20170516]nvl与非NULL约束.txt

--前几天做的测试http://blog.itpub.net/267265/viewspace-2137853/,实际上差异没有这个大,因为第2个多数是常量.
--今天测试nvl与非NULL约束的问题.

1.环境:

SCOTT@book> @ &r/ver1
PORT_STRING                    VERSION        BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx            11.2.0.4.0     Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

SCOTT@book> create table t as select rownum id,'test' name , 0 flag_num ,lpad('0',1,'0') flag_varchar from dual connect by level<=2e4;
Table created.

SCOTT@book> update t set flag_num=1, flag_varchar='1' where id=1e4 or id=2e4;
2 rows updated.

SCOTT@book> commit ;
Commit complete.

--//分析表略.
--//选择lpad函数,这样数据类型varchar2.
SCOTT@book> @ &r/desc t
           Name           Null?    Type
           -------------- -------- -------------
    1      ID                      NUMBER
    2      NAME                    CHAR(4)
    3      FLAG_NUM                NUMBER
    4      FLAG_VARCHAR            VARCHAR2(1)

--//首先我一直建议开发对于表示状态的字段最好选择varchar2(1).因为选择数字除了0占用1个字节长度外,其他至少是2.这样建立对于磁盘空间,以及建立的
--//索引都会减少空间占用.
--//我还见过使用-1表示状态的,实际上许多开发不太了解oracle一些数字类型的存储结构.-1占3个字节

SCOTT@book> select dump(-1,16) from dual ;
DUMP(-1,16)
---------------------
Typ=2 Len=3: 3e,64,66

2.首先讲我遇到的常见错误.

SCOTT@book> alter session set statistics_level=all ;
Session altered.

--首先就是隐式转换的问题
SCOTT@book> select dump(nvl(1,'1'),16) from dual ;
DUMP(NVL(1,'1'),1
-----------------
Typ=2 Len=2: c1,2

SCOTT@book> select dump(nvl('1',1),16) from dual ;
DUMP(NVL('1',1)
---------------
Typ=1 Len=1: 31

--//你可以发现类型向第1个参数类型转换.

SCOTT@book> select * from t where nvl(flag_varchar,0)=1;
        ID NAME                   FLAG_NUM F
---------- -------------------- ---------- -
     10000 test                          1 1
     20000 test                          1 1

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  0vv5wtp6q8ay5, child number 0
-------------------------------------
select * from t where nvl(flag_varchar,0)=1
Plan hash value: 1601196873
--------------------------------------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |       |    17 (100)|          |      2 |00:00:00.01 |      55 |
|*  1 |  TABLE ACCESS FULL| T    |      1 |    200 |  2600 |    17   (0)| 00:00:01 |      2 |00:00:00.01 |      55 |
--------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1 / T@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(TO_NUMBER(NVL("FLAG_VARCHAR",'0'))=1)
23 rows selected.

--//你可以发现这样情况在开发中很常见.如果写成如下:

SCOTT@book> select * from t where nvl(flag_varchar,0)='1';
        ID NAME                   FLAG_NUM F
---------- -------------------- ---------- -
     10000 test                          1 1
     20000 test                          1 1

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  9y06mwu7wncxx, child number 0
-------------------------------------
select * from t where nvl(flag_varchar,0)='1'
Plan hash value: 1601196873
--------------------------------------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |       |    17 (100)|          |      2 |00:00:00.01 |      55 |
|*  1 |  TABLE ACCESS FULL| T    |      1 |  10000 |   126K|    17   (0)| 00:00:01 |      2 |00:00:00.01 |      55 |
--------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1 / T@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(NVL("FLAG_VARCHAR",'0')='1')
--//你仔细看实际上oracle filter变成了 (NVL("FLAG_VARCHAR",'0')='1'),注意0变成'0'.建立开发统一类型这种表示状态的最好选择varchar2.
--//这样在编程时就知道是字符类型,带入参数,以及最后的等于数值选择字符类型.看看我们的开发团队就明白这个问题的严重性!!而不
--//会出现这样的情况

3.应用不统一:
--//你可以看到程序在谓词中两种情况的出现.
where FLAG_VARCHAR='1'
或者
where nvl(FLAG_VARCHAR,'0')='0'
where nvl(FLAG_VARCHAR,'0')=:B1

--//这样就必须建立2个索引.实际上如果能使用非空约束,就可以解决这个问题.

SCOTT@book> alter table t modify  FLAG_VARCHAR not null;
Table altered.

SCOTT@book> select * from t where nvl(flag_varchar,0)='1';
        ID NAME                   FLAG_NUM F
---------- -------------------- ---------- -
     10000 test                          1 1
     20000 test                          1 1

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  9y06mwu7wncxx, child number 0
-------------------------------------
select * from t where nvl(flag_varchar,0)='1'
Plan hash value: 1601196873
--------------------------------------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |       |    17 (100)|          |      2 |00:00:00.01 |      55 |
|*  1 |  TABLE ACCESS FULL| T    |      1 |  10000 |   126K|    17   (0)| 00:00:01 |      2 |00:00:00.01 |      55 |
--------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1 / T@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("FLAG_VARCHAR"='1')

--//你可以发现非空约束改变了过滤条件,变成了("FLAG_VARCHAR"='1').这样在真正的应用仅仅建立flag_varchar索引就ok了.

SCOTT@book> create index i_t_flag_varchar on t(flag_varchar);
Index created.

--//在flag_varchar字段建立直方图:

SCOTT@book> execute sys.dbms_stats.gather_table_stats ( OwnName => nvl('',user),TabName => 't',Estimate_Percent => NULL,Method_Opt => 'FOR ALL COLUMNS SIZE 1 for columns flag_varchar size 254 ',Cascade => True ,No_Invalidate => false)
PL/SQL procedure successfully completed.

SCOTT@book> select * from t where nvl(flag_varchar,0)='1';
        ID NAME                   FLAG_NUM F
---------- -------------------- ---------- -
     10000 test                          1 1
     20000 test                          1 1

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  9y06mwu7wncxx, child number 0
-------------------------------------
select * from t where nvl(flag_varchar,0)='1'
Plan hash value: 932711470
------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name             | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                  |      1 |        |       |     2 (100)|          |      2 |00:00:00.01 |       5 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T                |      1 |      1 |    13 |     2   (0)| 00:00:01 |      2 |00:00:00.01 |       5 |
|*  2 |   INDEX RANGE SCAN          | I_T_FLAG_VARCHAR |      1 |      1 |       |     1   (0)| 00:00:01 |      2 |00:00:00.01 |       3 |
------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1 / T@SEL$1
   2 - SEL$1 / T@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("FLAG_VARCHAR"='1')

--//能很好的使用索引.

4.在需要的数据上建立索引:
--//实际上这个需要dba与开发很好的配合,开发要了解oracle的Btree索引不索引全部是NULL的字段.利用这个特性索引仅仅需要的数据.例子.

SCOTT@book> create index if_t_flag_varchar on t(decode(flag_varchar,'1','1'));
Index created.

--//这样仅仅索引flag_varchar='1'的记录.
SCOTT@book> validate index if_t_flag_varchar;
Index analyzed.

SCOTT@book> @ &r/i
    HEIGHT     BLOCKS NAME          LF_ROWS    LF_BLKS LF_ROWS_LEN LF_BLK_LEN    BR_ROWS    BR_BLKS BR_ROWS_LEN BR_BLK_LEN DEL_LF_ROWS DEL_LF_ROWS_LEN DISTINCT_KEYS
---------- ---------- ---------- ---------- ---------- ----------- ---------- ---------- ---------- ----------- ---------- ----------- --------------- -------------
         1          8 IF_T_FLAG_          2          1          26       7996          0          0           0          0           0               0             1
                      VARCHAR

MOST_REPEATED_KEY BTREE_SPACE USED_SPACE   PCT_USED ROWS_PER_KEY BLKS_GETS_PER_ACCESS   PRE_ROWS PRE_ROWS_LEN OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
----------------- ----------- ---------- ---------- ------------ -------------------- ---------- ------------ -------------- ----------------
                2        7996         26          1            2                  2.5          0            0              0                0

SCOTT@book> validate index i_t_flag_varchar;
Index analyzed.

SCOTT@book> @ &r/i
    HEIGHT     BLOCKS NAME          LF_ROWS    LF_BLKS LF_ROWS_LEN LF_BLK_LEN    BR_ROWS    BR_BLKS BR_ROWS_LEN BR_BLK_LEN DEL_LF_ROWS DEL_LF_ROWS_LEN DISTINCT_KEYS
---------- ---------- ---------- ---------- ---------- ----------- ---------- ---------- ---------- ----------- ---------- ----------- --------------- -------------
         2         48 I_T_FLAG_V      20000         37      260000       7996         36          1         540       8028           0               0             2
                      ARCHAR

MOST_REPEATED_KEY BTREE_SPACE USED_SPACE   PCT_USED ROWS_PER_KEY BLKS_GETS_PER_ACCESS   PRE_ROWS PRE_ROWS_LEN OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
----------------- ----------- ---------- ---------- ------------ -------------------- ---------- ------------ -------------- ----------------
            19998      303880     260540         86        10000               5002.5          0            0              1               15

--//上下对比索引的BLOCKS,LF_ROWS,LF_BLKS等数值就明白,函数索引很小.这样写语句时写成如下:
SCOTT@book> select * from t where decode(flag_varchar,'1','1')='1';
        ID NAME         FLAG_NUM F
---------- ---------- ---------- -
     10000 test                1 1
     20000 test                1 1

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  g0dff6822sga3, child number 0
-------------------------------------
select * from t where decode(flag_varchar,'1','1')='1'
Plan hash value: 4162935806
-------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name              | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                   |      1 |        |       |     3 (100)|          |      2 |00:00:00.01 |       4 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T                 |      1 |    200 |  2600 |     3   (0)| 00:00:01 |      2 |00:00:00.01 |       4 |
|*  2 |   INDEX RANGE SCAN          | IF_T_FLAG_VARCHAR |      1 |      2 |       |     1   (0)| 00:00:01 |      2 |00:00:00.01 |       2 |
-------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1 / T@SEL$1
   2 - SEL$1 / T@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("T"."SYS_NC00005$"='1')

--//当然这需要开发这样写sql语句.

总结:
--//本来想写nvl与非NULL约束的问题,迁出一堆别的问题,实际上一个好的团队需要相互交流与配合,可惜我们开发人员陷入开发项目的烂泥塘...........
--//提交修改的sql语句遥遥无期,根本没时间修改..

[20170516]nvl与非NULL约束.txt相关推荐

  1. MySQL非空约束(NOT NULL)

    MySQL 非空约束(NOT NULL)可以通过 CREATE TABLE 或 ALTER TABLE 语句实现.在表中某个列的定义后加上关键字 NOT NULL 作为限定词,来约束该列的取值不能为空 ...

  2. 8、非空约束(NOT NULL)

    MySQL 非空约束(NOT NULL)指字段的值不能为空. 对于使用了非空约束的字段,如果用户在添加数据时没有指定值,数据库系统就会报错.可以通过 CREATE TABLE 或 ALTER TABL ...

  3. php mysql 非空_MySQL非空约束(NOT NULL)

    MySQL 非空约束(NOT NULL)可以通过 CREATE TABLE 或 ALTER TABLE 语句实现.在表中某个列的定义后加上关键字 NOT NULL 作为限定词,来约束该列的取值不能为空 ...

  4. MySQL 非空约束(NOT NULL)入门

    MySQL 非空约束(NOT NULL)指字段的值不能为空.对于使用了非空约束的字段,如果用户在添加数据时没有指定值,数据库系统就会报错.可以通过 CREATE TABLE 或 ALTER TABLE ...

  5. mysql建表语句非空约束默认_Navicat mysql 建表字段 默认值 空白、NULL 、empty string的区别...

    总结在最后,没啥干货 新建一张用户表CREATE TABLE `user` ( `id` bigint(20) DEFAULT NULL COMMENT '编号', `name` varchar(64 ...

  6. MySQL约束-自增长约束(auto_increment)、非空约束(not null)、唯一约束(unique)

    目录 自增长约束概念 特点 自增字段初始值 delete和truncate在删除后自增列的变化 非空约束概念 删除非空约束 唯一约束概念 文末资源推荐 每文一语 自增长约束概念 在 MySQL 中,当 ...

  7. 非空约束对数据更新的影响

    正如"非空约束"表达的意思,如果对一个字段添加了非空约束,那么我们是不能将这个字段中的值更新为NULL的.T_Debt表的FAmount字段是有非空约束的,如果我们执行下面SQL: ...

  8. [JavaWeb-MySQL]约束(非空约束,唯一约束,主键约束,外键约束_级联操作)

    约束 * 概念: 对表中的数据进行限定,保证数据的正确性.有效性和完整性. * 分类:1. 主键约束:primary key2. 非空约束:not null3. 唯一约束:unique4. 外键约束: ...

  9. SQL - 创建一个学生表,要求有主键约束和非空约束

    SQL - 创建一个学生表,要求有主键约束和非空约束 CREATE TABLE [dbo].[Student] ([ID] [int] NOT NULL,[Name] [nchar](10) NOT ...

  10. Oracle数据库:约束条件:主键约束、唯一约束、检查约束、非空约束、外键约束、默认值填写

    Oracle数据库:约束条件:主键约束.唯一约束.检查约束.非空约束.外键约束.默认值填写 2022找工作是学历.能力和运气的超强结合体,遇到寒冬,大厂不招人,可能很多算法学生都得去找开发,测开 测开 ...

最新文章

  1. SCCM 2012系列11 补丁分发下
  2. 游戏中每日刷新实现思路浅析
  3. 惊天大谎:让穷人都能上网是Facebook的殖民阴谋?
  4. 前端一HTML:十二:元素查找过程的详解
  5. Boost:boost :: bind相等运算符的测试程序
  6. Window右键添加“用vim打开”
  7. 反射例子(配置文件)
  8. DolphinDB配置
  9. python程序可以在任何安装了解释器_Windows安装多个python解释器
  10. bzoj 3379: [Usaco2004 Open]Turning in Homework 交作业(区间DP)
  11. 使用spring的JdbcTemplate进行查询的三种回调方式的比较
  12. asp.net post任何数据类型流到网站--当当网API传XML文件
  13. 海康威视ip摄像头通过网线直接连接笔记本电脑使用
  14. javaweb框架 一些底层实现
  15. 青花瓷 下载App Store上历史版本的App的ipa的包
  16. 软件开发外包平台有哪些?收集的一些备用
  17. 解决Windows 11 NumLock键盘数字灯不亮的问题
  18. ansys linux运行_ANSYS2020R1 产品Linux平台安装
  19. java读取加密excel_Java 加密和解密Excel文档
  20. android蓝牙查看电池容量_Android获取电池电量和电池容量

热门文章

  1. WPF简单实用方法(持续更新)
  2. python基础-软件目录开发规范
  3. spider RPC过滤器
  4. Python基础学习1---函数
  5. POJ 4047 Garden 线段树 区间更新
  6. Android WebView学习
  7. 实体与表映射关系XXX.hbm.xml配置详解(转)
  8. 妙用git rebase --onto指令
  9. HDU1166树状数组
  10. Java对象的强引用、软引用、弱引用和虚引用 笔记