`
liulanghan110
  • 浏览: 1076679 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

关于is null和is not null

阅读更多


   
 网上有些资料说含有
null 的列不能创建索引,还有资料说因为一般的索引是 b_ 树结构,而 b+ 树不能存储 null 值,所以 is null is not null 都不能利用 索引。为了证明以上说法,我做了一下测试。

1. 测试含有 null 的列是否能创建索引

先创建测试数据 :

create table student
(
   
id int primary key not null ,
   
sid   int
)

: 定义主键时系统自动创建索引,如果 DROP 表,关于这个表的所有索引也被删除,也包括系统创建的索引。

create procedure insertDate()
BEGIN
      DECLARE v_id int;
      set v_id = 0;
      while v_id < 100000
      DO
       insert into student values(v_id,v_id );
       set v_id = v_id + 1;
      end while;
END
;

-- 插入数据

         call insertDate ()

    insert into student ( id ) values ( 100001 )

-- 创建索引

         CREATE INDEX STU_SID ON STUDENT
    
( SID    ASC
    
)
    PCTFREE
10
    ALLOW REVERSE SCANS
;

结果: 可以发现在有 null 的列式可以建立索引的。

 

2. 测试 is null is not null 能否利用索引

a. 空值很少时的情况

测试数据利用上面的数据, 特点是一共 100001 万条记录,只有1条数据的 sid null

注意 : 在一个表的数据大量修改后,要运行下面的命令:

RUNSTATS ON TABLE NBADV. STUDENT FOR INDEX  NBADV. STU_SID   SHRLEVEL REFERENCE

注:NBADV. STUDENT 是 [模式名].[表名] NBADV.STU_SID [模式名].[表名]

如下查询语句 :

SELECT * FROM STUDENT WHERE SID is null

查询计划如下:

 

       

由查询计划可以看出,该语句使用了索引。

再看如下语句:

SELECT * FROM STUDENT WHERE SID is not null

查询计划如下:

 

        

由查询计划可以看出,该语句没有使用索引。

再看如下语句:

SELECT SID FROM STUDENT WHERE SID is not null

查询计划如下:

 

        

由查询计划可以看出,该语句也没有使用了索引。

 

一般 SQL 语句,比如 SELECT * FROM STUDENT WHERE SID is null 这句,只告诉了数据库要从哪个表里找到怎样的数据。至于数据库怎样找到我们要的数据,是走索引,还是全表扫描,还是索引和扫描混合,都是 DB2 自己决定的事情。就如我们对一个人说,你从上海来北京吧。那么他是坐飞机呢,还是坐火车,或者是坐汽车,我们并没说。他会用一个标准来选择到底怎么走,比如最快的标准,就会选择飞机,比如最便宜的标准,就会选择火车(长途汽车一般比火车贵吧?)。而 DB2 里的优化器的标准就是最快,怎样最快的得到我们想要的结果。怎样最快的得要想要的结果呢,是走索引还是全表扫描, DB2 优化器收集来的统计信息,然后选择最优的方式。

下面来看上面的语句为什么会产生那样的结果:

第一个 SELECT * FROM STUDENT WHERE SID is null , 可以看到它是利用索引了的。可是 B+ 树的索引(关于 B+ 树索引,可以查询一些资料,有时间我会写些东西来分析它)是不存储 null 值的,它为什么还可以利用索引呢?这就提到了上面的优化器路的选择问题。

我们可以看到此表有 100001 数据,其中 sid 列只有一条是 null 值。也就是 sid 列的索引会存储此列的 100000 条记录的信息,只有一条没有存。在选择怎么的时候, DB2 优化器会试着用这样两种方式,第一种是从表中取出每条记录,然后看它的 sid 值是否为空。第二种是,先从索引找到 sid 列所有非空的数据在表中的位置,然后在扫描表时,如碰到这些位置,则不用取出数据判断是否为空,直接跳到下一条记录。可以看到,第一种方式进行了全表扫描(这里所谓的全表扫描,是指找出每条记录的位置,一般所说的全表扫描是指扫描表每条记录的位置并读取出每条记录的数据)和全表读取数据,第二种方式也进行了全表的扫描,但却没进行全表数据的读取,而是利用索引排除了其他数据,只读取了一条数据。所以,这两种方式分别是这样的:

第一种:全表扫描 + 全盘读取数据

第二种:全表扫描 + 索引扫描 + 读取一条数据

那么,这两种方式哪一种更快呢?

由于索引比整个表小很多,很显然,读取索引比读取整个表的数据时间会少很多,所以第二种方式效率更高。正如上面查询计划显示的那样利用索引和全表扫描共同找到记录。

 

再来分析这个语句 : SELECT * FROM STUDENT WHERE SID is not null DB2 优化器会有两种方式选择。:

第一种:索引扫描 + 读取数据

第二种:全表扫描 + 读取数据

我们平时所说的利用索引会快,主要是利用索引的有序性可以迅速筛选记录,其实扫描表或者扫描整个表,时间是差不多的。既然索引扫描和全表扫描速度差不多,那么第一种方式和第二种方式速度就一样了?其实第二种方式读取数据会快一些,因为读取数据时,第一种是一条一条的读取,而全表读数据时是一次加载一个 block 来读取 , 所以第二种效率会高一些。

         综合上面的考虑,优化器会选择第二种方式,也就是全表扫描。

        

: 如果要测试不加条件的索引扫描比全表扫描慢,可以运行这个语句:

alter table transaction_log volatile cardinality

DB2 优化器会强制使用索引

 

b. 空值很多时的情况

-- 插入数据

delete from student
   create procedure
insertDate ()
   BEGIN
      DECLARE
v_id int ;
      set
v_id = 0 ;
      while
v_id < 100000
      DO
      if
v_id < 9 0000 then
       insert into
student ( id ) values ( v_id );
      else
       insert into
student values ( v_id , v_id );
      end if
;
       set
v_id = v_id + 1 ;
      end while
;
    END
;

call insertDate ()

RUNSTATS ON TABLE NBADV. STUDENT FOR INDEX NBADV.STU_SID   SHRLEVEL REFERENCE

测试语句 :

SELECT * FROM STUDENT WHERE SID is null

 

 

这里没有使用索引

SELECT * FROM STUDENT WHERE SID is not null

这里没有使用索引

SELECT sid FROM STUDENT WHERE SID is not null

   

 

这里使用了索引。

可以看到,三个同样的语句,前后执行计划却不一样。问题就在于前后的表的数据不一样,第一个只有 1 null 值,第二个却有一半的是 null 。下面分析这三个语句。

第一个 SELECT * FROM STUDENT WHERE SID is null

同样有两种方式 :

第一种:全表扫描 + 全盘读取数据

第二种:全表扫描 + 索引扫描 + 读取十分之九数据

这里和第一次测试的区别,就是第二种方式读的数据不是一条而是90%了。从而导致这种利用索引的方式比第一种慢,而优化器选择了第一种。

第二个 SELECT * FROM STUDENT WHERE SID is not null

两种方式 :

第一种:索引扫描 + 读取数据(全表的10%)

第二种:全表扫描 + 读取数据(全表)

由于索引扫描和全表扫描速度差不多,因为读取数据时,第一种是一条一条的读取,而全表读数据时是一次加载一个 block 来读取 , 所以第二种效率会高一些。

 

第三个 SELECT sid FROM STUDENT WHERE SID is not null

两种方式:

第一种:索引扫描+ 读取数据(索引上的数据)

第二种:全表扫描+ 读取数据(全表)

由于索引扫描和全表扫描速度差不多,而第一种方法读取数据时,不用先找到数据在表的位置再去读,而是直接读取索引上的数据(索引上存有该索引列的数据),所以第一种方式快些。优化器选择第一种方式。

另外, SELECT * FROM STUDENT WHERE SID is not null SELECT sid FROM STUDENT WHERE SID is not null 的区别就是一个选择了所有行,而另一个只选择了自己需要的行,而前一个没有利用索引,速度也很慢,后一个利用了索引。所以在写查询时,要保持良好的习惯,尽量不要用 * 号,而是把自己需要的列写出来。

3. 测试 is not null 改写成其他语句效率是否提高

有些地方有这样的说法,is not null 不能利用索引,所以要将其改写成其他语句,以便能够利用索引提高效率。下面是测试情况:

数据: 第一种情况的测试数据。

SQL 语句: SELECT sid   FROM STUDENT WHERE SID is not null

改写后的SQL 语句 SELECT sid FROM STUDENT WHERE SID > 0 and sid < 100001

 
 

 

可以看到两种写法的效果完全一样,所以上面的说法是错误的。

4. 总结

我们可以看到,无论是 IS NULL 还是 IS NOT NULL ,并不是如网上所说的 is null 或者 is not null 不能利用索引,而是在不同的表数据结构环境下,有可能会利用索引有可能不利用索引,而决定如何执行查询的标准就是性能。 DB2 查询优化器会评估各种查询方式的开销之后再来做决定。而且网上流传的将 IS NOT NULL 改写成其他语句的写法,也是错的,并不能提高效率。

另外,由上面测试也可以看出,要养成良好的习惯,尽量不要写 select * 而是将需要的列写上。

 

  • 大小: 18.6 KB
  • 大小: 9 KB
  • 大小: 9 KB
  • 大小: 9.1 KB
  • 大小: 12.2 KB
  • 大小: 12.2 KB
  • 大小: 12.2 KB
  • 大小: 12.1 KB
  • 大小: 9.5 KB
  • 大小: 10.1 KB
  • 大小: 12.4 KB
分享到:
评论
2 楼 liulanghan110 2012-08-20  
这个是DB2的数据库,用的Quest Central。ORACLE的话,要其他的方式看
1 楼 SCOL_007 2012-08-14  
LZ 请问你 你用的什么工具看到查询计划

相关推荐

    oraclesql判断值为空-Oracle-sqlserver的空值(null)判断.pdf

    Oracle SQL 判断值为空OrNull 判断 Oracle SQL 中判断值为空...在 Oracle 和 SQL Server 中,我们可以使用 `NVL` 和 `ISNULL` 函数来判断值为空或 Null,並使用 `isNull` 和 `is not null` 来判断值是否为空或 Null。

    NOT EXISTS ⇔ NOT IN ⇒ NOT NULL 问题 结果不一样 疑问 如果等效

    在SQL查询语言中,`NOT EXISTS`、`NOT IN` 和 `NOT NULL` 是三种用于排除特定条件的数据记录的方法。然而,在实际应用中,这三种语法有着不同的应用场景和执行逻辑,有时初学者可能会误以为它们是等效的,但实际上...

    mysql not in、left join、IS NULL、NOT EXISTS 效率问题记录

    MySQL中的`NOT IN`, `LEFT JOIN`, `IS NULL`, 和 `NOT EXISTS` 是四种不同的SQL查询方式,它们在特定情况下可以实现相似的功能,但实际执行效率可能会有很大差异。本文主要探讨这四种方法在处理大数据量时的性能表现...

    SQL中IS NOT NULL与!=NULL的区别

    在SQL语言中,IS NOT NULL和!=NULL是用于判断字段是否为NULL的两种不同表达方式,但它们在处理NULL值时的行为有所不同。了解这些差异对于编写有效的查询至关重要,特别是当处理包含NULL值的数据时。 首先,让我们...

    Tdsadk is not null

    如果将其视为一个变量名,那么“Tdsadk is not null”意味着该变量已经赋值,并非空值。这在编程语言中是一个常见的逻辑判断条件,用于确保后续操作能够安全地访问该变量。 ### 2. COM 组件对象模型 #### 2.1 定义...

    MySQL查询空字段或非空字段(is null和not null)

    本文将深入探讨如何使用`IS NULL`和`IS NOT NULL`条件来筛选含有或不含NULL值的记录。 首先,我们要了解如何设置一个字段为NULL。在MySQL中,更新字段值为NULL时,语法非常简单直接:`SET &lt;字段名&gt;=NULL`。例如,将...

    MySQL null与not null和null与空值的区别详解

    关于性能,`NOT NULL`约束通常比`NULL`更高效,因为`NULL`值在索引和查询时需要额外的处理。在B树索引中,`NULL`值不会被存储,这可能导致索引效率下降。在进行比较操作时,`NULL`会参与计算,这可能会影响查询速度...

    parameters-is-null-proc.zip_nullproc

    在IT行业中,尤其是在数据库管理和开发领域,处理空值(NULL)是常见的...通过使用`IS NULL`和`IS NOT NULL`操作符,结合逻辑运算符,以及在存储过程中封装这些逻辑,我们可以构建出更加灵活和健壮的数据库应用程序。

    StringUtils

    与原生的 `String` 类不同的是,`StringUtils` 提供了更加丰富的字符串处理功能,并且在设计上考虑到了对 `null` 值的安全处理,避免了 `NullPointerException` 的发生。这使得开发者在进行字符串处理时能够更加灵活...

    关于sql中求平均值出现null值的解决方案

    "关于sql中求平均值出现null值的解决方案.txt"和"注释.txt"可能包含了更详细的解释和示例代码,而"更新说明.txt"则可能记录了这些解决方案的更新和改进。如果你在实际操作中遇到困难,可以查阅这些文件获取更多信息...

    mysql中is null语句的用法分享

    对null的特殊处理即是在前面的章节中,为了决定哪个动物不再是活着的,使用death is not null而不使用death != null的原因。 在group by中,两个null值视为相同。 执行order by时,如果运行 order by … asc,则null...

    Mysql实现null值排在最前/最后的方法示例

    IS NOT NULL: 当列的值不为 NULL, 运算符返回 true。 &lt;=&gt;: 比较操作符(不同于=运算符),当比较的的两个值为 NULL 时返回 true。 关于 NULL 的条件比较运算是比较特殊的。你不能使用 = NULL 或 != NULL 在列中...

    Oracle null的使用

    例如,在查询出征缴方式不为正划成功、倒扣成功的征收数据时,需要使用“is null”和“is not null”关键字。 了解 Oracle null 的使用是 Oracle 开发中非常重要的一部分。只有正确地理解和应用 null 的概念,才能...

    Python pandas库中的isnull()详解

    总之,Python pandas库中的`isnull()`函数是检测和处理缺失值的核心工具。它能帮助我们快速定位数据中的空值,结合`any()`和`sum()`等其他函数,我们可以进一步了解数据的完整性,从而为后续的数据清洗和分析打下...

    sql中null值对count的影响

    SELECT COUNT(*), COUNT(pid), COUNT(ISNULL(pid, '')) FROM tbl_user WHERE pid IS NOT NULL; ``` 结果是`(2, 2, 2)`,因为只有两行的`pid`不是`NULL`,且这两行中的`pid`被成功计数。 2. **只考虑`NULL`值的...

    数据库中复杂的Null问题

    在进行多表联接时,必须谨慎处理这些情况,可能需要使用`COALESCE`、`IFNULL`或`ISNULL`等函数来避免Null值的影响。 在编程接口中处理数据库结果时,也需要考虑Null值。例如,在.NET环境中,使用ADO.NET访问数据库...

    Java中String判断值为null或空及地址是否相等的问题

    System.out.println("value is blank but not null"); } else { System.out.println("value is \"" + value + "\""); } } } ``` 这段代码演示了如何根据字符串的状态打印不同的消息。 此外,我们还要讨论字符...

    详解MySQL中的NULL值

    总的来说,MySQL提供了`IS NULL`、`IS NOT NULL`和`&lt;=&gt;`三个工具来帮助开发者处理`NULL`值。理解和掌握这些工具,能够使你在处理含有`NULL`值的数据时更加游刃有余。在编写SQL查询时,确保正确使用这些运算符,避免...

Global site tag (gtag.js) - Google Analytics