NULL值是关系型数据库系统中比较特殊的一种值,通常称为UNKNOWN或空值,即是未知的,不确定的。由于NULL存在着无数的可能,因此NULL值也不等于NULL值。
Oracle在创建索引时,不会存储NULL值,而KingbaseES在创建索引时则会存储NULL值.在查询时,如使用Column is null这样的条件查询,Oracle不会使用索引而KingbaseES则会使用索引。
oracle
SQL> create table tb1(id int); Table created. SQL> insert into tb1 select rownum from dba_objects; 86988 rows created. SQL> commit; Commit complete. SQL> create index i_tb1 on tb1(id); Index created. SQL> insert into tb1 values(null); 1 row created. SQL> commit; Commit complete. SQL> exec dbms_stats.gather_table_stats('TEST','TB1',cascade=>true); --这里收集统计信息 PL/SQL procedure successfully completed. SQL> select count(*) from tb1; COUNT(*) ---------- 86989 SQL> select index_name,index_type,num_rows,status,distinct_keys from dba_indexes where table_name='TB1'; INDEX_NAME INDEX_TYPE NUM_ROWS STATUS DISTINCT_KEYS ---------- ---------- ---------- ---------------- ------------- I_TB1 NORMAL 86988 VALID 86988 这里可以看到统计信息收集后,索引统计信息中只有86988行记录,而表的数据是86989行。可以看出索引并没有存储null值,所以少了1行记录。 SQL> set autotrace on explain; SQL> select * from tb1 where id is null; ID ---------- Execution Plan ---------------------------------------------------------- Plan hash value: 3226679318 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 5 | 68 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| TB1 | 1 | 5 | 68 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("ID" IS NULL) SQL> select * from tb1 where id = 9999; ID ---------- 9999 Execution Plan ---------------------------------------------------------- Plan hash value: 3913851163 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 5 | 1 (0)| 00:00:01 | |* 1 | INDEX RANGE SCAN| I_TB1 | 1 | 5 | 1 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("ID"=9999) 查询普通数据时能够走索引扫描,当查询条件为is null时走的是全表扫描。
KingbaseES
test=# create table tb1(id int); CREATE TABLE test=# insert into tb1 select generate_series(1,100000); INSERT 0 100000 test=# insert into tb1 values (null); INSERT 0 1 test=# create index i_tb1 on tb1(id); CREATE INDEX test=# analyze tb1; ANALYZE test=# select relname,reltuples from sys_class where relname ~ 'tb1'; relname | reltuples ---------+----------- tb1 | 100001 i_tb1 | 100001 (2 行记录) 可以看出表和索引记录是一样的,即索引是存了null的记录。 test=# explain analyze select * from tb1 where id is null; QUERY PLAN ---------------------------------------------------------------------------------------------------------------- Index Only Scan using i_tb1 on tb1 (cost=0.29..4.31 rows=1 width=4) (actual time=0.048..0.061 rows=1 loops=1) Index Cond: (id IS NULL) Heap Fetches: 1 Planning Time: 0.204 ms Execution Time: 0.134 ms (5 行记录) 查询条件为is null时KingbaseES是可以走索引扫描的