ITPub博客

首页 > 数据库 > Oracle > NULL与索引

NULL与索引

原创 Oracle 作者:luisedalian 时间:2014-01-15 11:47:09 0 删除 编辑

B-Tree索引不会存储全为NULL的列(B-Tree聚簇索引可以存储全为NULL的列),

但复合索引中如果有非NULL的列,就可以存储。

因为B-Tree索引不存储全为NULL的列,有时会导致SQL语句不走索引而影响效率。

点击(此处)折叠或打开

  1. DROP TABLE t;

  2. CREATE TABLE t(a NUMBER, b NUMBER);
  3. CREATE UNIQUE INDEX uidx_t_a_b ON t(a, b);
  4. INSERT INTO t VALUES(NULL, NULL);
  5. INSERT INTO t VALUES(1, NULL);
  6. INSERT INTO t VALUES(NULL, 1);
  7. COMMIT;

  8. BEGIN
  9.   dbms_stats.gather_table_stats(ownname => USER, tabname => \'T\');
  10.   dbms_stats.gather_index_stats(ownname => USER, indname => \'UIDX_T_A_B\');
  11. END;
  12. /

  13. --查看索引中存储的数据的行数. 结论: NULL, NULL所对应的行并没有存储在索引中.(3个记录,索引中只存储了2个)
  14. SELECT index_name, num_rows FROM user_indexes WHERE index_name = \'UIDX_T_A_B\';
  15. INDEX_NAME NUM_ROWS
  16. ------------------------------ ----------
  17. UIDX_T_A_B 2
  18. DROP TABLE t;


  19. --给列b添加NOT NULL约束
  20. CREATE TABLE t(a NUMBER, b NUMBER NOT NULL);
  21. CREATE UNIQUE INDEX uidx_t_a_b ON t(a, b);

  22. INSERT INTO t VALUES(1, 1);
  23. INSERT INTO t VALUES(NULL, 2);
  24. COMMIT;

  25. BEGIN
  26.   dbms_stats.gather_table_stats(ownname => USER, tabname => \'T\');
  27.   dbms_stats.gather_index_stats(ownname => USER, indname => \'UIDX_T_A_B\');
  28.   
  29. END;
  30. /

  31. --查看索引中存储的数据的行数
  32. SELECT index_name, num_rows FROM user_indexes WHERE index_name = \'UIDX_T_A_B\';
  33. INDEX_NAME NUM_ROWS
  34. ------------------------------ ----------
  35. UIDX_T_A_B 2

  36. --此时执行查询, where条件中包含is null和is not null都可以走索引了
  37. SET AUTOTRACE ON
  38. SELECT * FROM t WHERE a IS NULL;


点击(此处)折叠或打开

  1. SELECT * FROM t WHERE a IS NOT NULL;


点击(此处)折叠或打开

  1. SET AUTOTRACE OFF

  2. --场景:某列有一些NULL值,但占的比例很少, 希望IS NULL条件可以走索引.
  3. -- 但又不想建立复合索引或增加NOT NULL约束.

  4. DROP TABLE t;
  5. CREATE TABLE t(a NUMBER, b NUMBER);
  6. INSERT INTO t VALUES(NULL, 1);
  7. INSERT INTO t VALUES(NULL, NULL);
  8. INSERT INTO t VALUES(NULL, NULL);
  9. INSERT INTO t VALUES(NULL, 2);
  10. INSERT INTO t VALUES(3, NULL);
  11. COMMIT;

  12. --再多插入一些非NULL值
  13. BEGIN
  14.   FOR i IN 1..10000 LOOP
  15.     INSERT INTO t VALUES(i, i);
  16.   END LOOP;
  17.   COMMIT;
  18. END;
  19. /

  20. CREATE INDEX idx_t_a_0 ON t(a, 0);
  21. BEGIN
  22.   dbms_stats.gather_table_stats(ownname => USER, tabname => \'T\');
  23.   dbms_stats.gather_index_stats(ownname => USER, indname => \'IDX_T_A_0\');
  24. END;
  25. /

  26. SELECT index_name, num_rows FROM user_indexes WHERE index_name = \'IDX_T_A_0\';

  27. INDEX_NAME NUM_ROWS
  28. ------------------------------ ----------
  29. IDX_T_A_0 10005

  30. SET autotrace ON
  31. SELECT * FROM t WHERE a IS NULL;
  32.            A B
  33. ---------- ----------
  34.                          1


  35.                          2


点击(此处)折叠或打开

  1. SET autotrace OFF

  2. --场景: 一个工单系统, 列status只有处理和未处理2种状态. 未处理的很少,最多10%; 已经处理的很多, 90%.
  3. -- 经常查询未处理的,对已处理的查询很少.
  4. -- 为了节省维护索引的开销、降低索引的存储空间,可以对未处理的记录索引,已处理的不存储在索引中.

  5. DROP TABLE t;
  6. --列a只可以取2个值(0-未处理, 1-已处理)
  7. CREATE TABLE t(a NUMBER, b NUMBER);
  8. INSERT INTO t VALUES(0, 1)

  9. --大量插入已经处理的数据
  10. BEGIN
  11.   FOR i IN 1..10000 LOOP
  12.     INSERT INTO t VALUES(1, i);
  13.   END LOOP;
  14.   COMMIT;
  15. END;
  16. /

  17. --列a不为0的都转换为NULL,不会存储到索引中(函数索引)
  18. CREATE INDEX idx_t_a ON t(DECODE(a, 0, 0, NULL));

  19. BEGIN
  20.   dbms_stats.gather_table_stats(ownname => USER, tabname => \'T\');
  21.   dbms_stats.gather_index_stats(ownname => USER, indname => \'IDX_T_A\');
  22. END;
  23. /

  24. --确定索引中存储的行数
  25. SELECT index_name, num_rows FROM user_indexes WHERE index_name = \'IDX_T_A\';
  26. INDEX_NAME NUM_ROWS
  27. ------------------------------ ----------
  28. IDX_T_A 0


  29. SET autotrace ON EXPLAIN
  30. SELECT * FROM t WHERE DECODE(a, 0, 0, NULL) = 0;

  31.          A B
  32. ---------- ----------
  33.          0 1


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/17013648/viewspace-1070819/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: 用>=替代>
下一篇: WHERE IN LIST
请登录后发表评论 登录
全部评论

注册时间:2012-02-06

  • 博文量
    1986
  • 访问量
    6040856