Oracle与KingbaseES的NULL在索引使用上的区别

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是可以走索引扫描的
posted @ 2022-06-18 08:41  KINGBASE研究院  阅读(88)  评论(0编辑  收藏  举报