暂无图片
暂无图片
3
暂无图片
暂无图片
3
暂无图片

Oracle 和 Mysql 的索引在Null字段上处理的异同

原创 陈晓辉 2021-10-21
611

ORACLE:

	SQL> create table tab2(c1 number, c2 number, c3 varchar2(10));
	表が作成されました。

	SQL> declare
	  a number;
	begin
	  a := 1;
	  for i in 1 .. 500 loop
		for j in 1 .. 1000 loop
		  insert into tab2 values(a,j,'a');
		  commit;
		  a := a+1;
		end loop;
	  end loop;
	end;
	/
	PL/SQLプロシージャが正常に完了しました。

	SQL> create index ind2_2 on tab2(c2);
	索引が作成されました。

	SQL> insert into tab2 values(9999,null,'test');
	1行が作成されました。

	SQL> commit;
	コミットが完了しました。

	SQL> exec dbms_stats.gather_table_stats(ownname=>'TEST',tabname=>'TAB2',cascade=>TRUE);
	PL/SQLプロシージャが正常に完了しました。

	SQL> set lin 150 pages 9999
	SQL> set autot traceonly exp
	SQL> select count(*) from tab2 where c2 is null;

	実行計画
	----------------------------------------------------------
	Plan hash value: 2781695375
	---------------------------------------------------------------------------
	| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
	---------------------------------------------------------------------------
	|   0 | SELECT STATEMENT   |      |     1 |     4 |   310   (1)| 00:00:01 |
	|   1 |  SORT AGGREGATE    |      |     1 |     4 |            |          |
	|*  2 |   TABLE ACCESS FULL| TAB2 |     1 |     4 |   310   (1)| 00:00:01 |
	---------------------------------------------------------------------------
	Predicate Information (identified by operation id):
	---------------------------------------------------
	   2 - filter("C2" IS NULL)

	SQL> select count(*) from tab2 where c2=10;

	実行計画
	----------------------------------------------------------
	Plan hash value: 3563712581
	----------------------------------------------------------------------------
	| Id  | Operation         | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
	----------------------------------------------------------------------------
	|   0 | SELECT STATEMENT  |        |     1 |     4 |     4   (0)| 00:00:01 |
	|   1 |  SORT AGGREGATE   |        |     1 |     4 |            |          |
	|*  2 |   INDEX RANGE SCAN| IND2_2 |   500 |  2000 |     4   (0)| 00:00:01 |
	----------------------------------------------------------------------------
	Predicate Information (identified by operation id):
	---------------------------------------------------
	   2 - access("C2"=10)
复制

Mysql(Innodb):

	mysql> create table tab2(c1 int, c2 int, c3 varchar(10));
	Query OK, 0 rows affected (0.01 sec)

	mysql> delimiter //
	mysql> create procedure my_procedure()
	-> begin
	-> DECLARE n int DEFAULT 1;
	-> WHILE n < 1001 DO
	-> insert into tab2(c1,c2,c3) value (n,n,'desc');
	-> set n = n + 1;
	-> END WHILE;
	-> end
	-> //
	Query OK, 0 rows affected (0.01 sec)

	mysql> delimiter ;
	mysql> call my_procedure;
	Query OK, 1 row affected (0.84 sec)

	mysql> create index ind2_2 on tab2(c2);
	Query OK, 0 rows affected (0.02 sec)
	Records: 0  Duplicates: 0  Warnings: 0

	mysql> insert into tab2 values(9999,null,'test');
	Query OK, 1 row affected (0.00 sec)

	mysql> explain select count(*) from tab2 where c2=10;
	+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
	| id | select_type | table | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra       |
	+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
	|  1 | SIMPLE      | tab2  | NULL       | ref  | ind2_2        | ind2_2 | 5       | const |    1 |   100.00 | Using index |
	+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
	1 row in set, 1 warning (0.00 sec)

	mysql> explain select count(*) from tab2 where c2 is null;
	+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+--------------------------+
	| id | select_type | table | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra                    |
	+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+--------------------------+
	|  1 | SIMPLE      | tab2  | NULL       | ref  | ind2_2        | ind2_2 | 5       | const |    1 |   100.00 | Using where; Using index |
	+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+--------------------------+
	1 row in set, 1 warning (0.00 sec)
复制

结论:

Oracle的B-tree索引不存储Null,所以“c2 is null”条件的检索不能从索引中受益。
Mysql的B+tree索引也不直接不存储Null,但是“c2 is null”条件的检索能从索引中受益。

https://dev.mysql.com/doc/ref...

ref_or_null works by first doing a read on the reference key, 
    and then a separate search for rows with a NULL key value.
复制
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
1人已赞赏
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

筱悦星辰
暂无图片
1年前
评论
暂无图片 0
一个家最好的投资,就是陪伴。愿你我都能珍惜眼前的幸福,经营好我们的家庭,让日子越过越红火。
1年前
暂无图片 点赞
评论
wzf0072
暂无图片
1年前
评论
暂无图片 0
Oracle的B-tree索引不存储Null,所以“c2 is null”条件的检索不能从索引中受益。 Mysql的B+tree索引也不直接不存储Null,但是“c2 is null”条件的检索能从索引中受益。
1年前
暂无图片 点赞
评论
Uncopyrightable
暂无图片
3年前
评论
暂无图片 0
数据无国界呀,日版数据库环境
3年前
暂无图片 点赞
评论