现在的位置: 首页 > 综合 > 正文

oracle sql中涉及is null时如何优化(索引创建和直方图)

2018年02月06日 ⁄ 综合 ⁄ 共 3510字 ⁄ 字号 评论关闭

适用场景

试想下面的sql

Select*

fromBD_INVMANDOC_bak 
t

where t.negallowed
is null

or 
t.negallowed='N'

如果negallowed列只有两个值:YN,并且存在NULL

那么我们在negallowed列创建一个索引,这个语句仍然不能走索引,原因为索引中不存储null值。

BD_INVMANDOC_bak106万数据,其中5万行值为N100万行为Y,其余为null

如何走索引

需要创建一个包含虚拟列的复合索引,这样可以实现索引中包含negallowed列的null

创建索引如下:

CREATEINDEX ID_BD_INVMANDOC_bak_negallowed ON BD_INVMANDOC_bak (negallowed,1);

查询执行计划变为了走索引:

SQL> set autotrace trace

SQL>

SQL>

SQL> select-- /*+ INDEX(T  ID_BD_INVMANDOC_bak_negallowed) */

   2  *

   3  from BD_INVMANDOC_bak  t where

   4  t.negallowed is null or 

   5  t.negallowed ='N'

   6  ;

 

61399 rows selected.

 

 

Execution Plan

----------------------------------------------------------

 

--------------------------------------------------------------------------------

---------------

 

| Id   | Operation                    |  Name                           |  Rows  |

Bytes | Cost  |

 

--------------------------------------------------------------------------------

---------------

 

|    0 | SELECT STATEMENT              |                                | 58559 |

 9492K|   1774 |

 

|    1 |  CONCATENATION               |                                |       |

       |       |

 

|    2 |   TABLE ACCESS BY INDEX  ROWID| BD_INVMANDOC_BAK               |  49153 |

 7968K|   1475 |

 

|    3 |    INDEX RANGE SCAN          | ID_BD_INVMANDOC_BAK_NEGALLOWED |  49153 |

       |   113 |

 

|    4 |   TABLE ACCESS BY INDEX  ROWID| BD_INVMANDOC_BAK                |  9406 |

 1524K|    299 |

 

|    5 |    INDEX RANGE SCAN          | ID_BD_INVMANDOC_BAK_NEGALLOWED  |  9867 |

       |    25 |

 

--------------------------------------------------------------------------------

---------------

 

分析:

当索引中包含了查询列存在null的时候,语句可以顺利走索引,语句执行代价也明显降低了。

但是通过进一步测试,发现在negallowed ='N'negallowed ='Y'时均走索引,执行计划在negallowed ='Y'时非最优,所以需要采取直方图信息,以便执行计划更准确。

 

直方图histogram的影响

这个表的negallowed列只包含YN,并且存在null,那么直方图是不是对这列存在影响呢

 

使用如下语句收集,没有直方图

execdbms_stats.gather_table_stats(user,'BD_INVMANDOC_BAK',method_opt => 'FOR ALLINDEXED COLUMNS SIZE 1');

 

执行计划:

Execution Plan

----------------------------------------------------------

 

----------------------------------------------------------------------

| Id | Operation         | Name             | Rows  | Bytes | Cost  |

----------------------------------------------------------------------

|   0| SELECT STATEMENT  |                  |   530K|   84M|  7750 |

|   1|  TABLE ACCESS FULL| BD_INVMANDOC_BAK|   530K|    84M| 7750 |

----------------------------------------------------------------------

可以看到执行计划为全表扫描

 

统计直方图

execdbms_stats.gather_table_stats(user,'BD_INVMANDOC_BAK',method_opt => 'FOR ALLINDEXED COLUMNS SIZE auto');

 

执行计划:

Execution Plan

----------------------------------------------------------

 

--------------------------------------------------------------------------------

---------------

 

| Id | Operation                    |Name                           |Rows  |

Bytes | Cost  |

 

--------------------------------------------------------------------------------

---------------

 

|   0| SELECT STATEMENT             |                                | 64950 |

  10M|  1969 |

 

|   1|  CONCATENATION               |                                |       |

     |       |

 

|   2|   TABLE ACCESS BY INDEX ROWID|BD_INVMANDOC_BAK               | 55605 |

 9014K| 1670 |

 

|   3|    INDEX RANGE SCAN          | ID_BD_INVMANDOC_BAK_NEGALLOWED |55605 |

     |   128 |

 

|   4|   TABLE ACCESS BY INDEX ROWID|BD_INVMANDOC_BAK               |  9345 |

 1514K|  299 |

 

|   5|    INDEX RANGE SCAN          | ID_BD_INVMANDOC_BAK_NEGALLOWED|  9867 |

     |    25 |

 

--------------------------------------------------------------------------------

---------------

--执行计划走索引

 

总结

当一个查询中涉及IS NULL的情况,我们需要在此列上创建适合的复合索引,如果没有好的候选列,可以添加虚拟列创建复合索引,以达到语句执行计划走索引的目的。

当这一列的值只有少数几个唯一值,并且每个值涉及的行数多少严重倾斜时,建议收集直方图,以便达到正确走索引的目的。

抱歉!评论已关闭.