InnoDB索引允许NULL对性能有影响吗(2)

简介: InnoDB索引允许NULL对性能有影响吗


这次的查询需要扫描12个page,除去1个根节点外,还需要扫描12个叶子节点,只是为了返回一条数据而已,这代价有点大。

如果把SQL微调改成下面这样

[root@yejr.run]> select id,c1 from t_sk where c1 is null limit 10000,1;
+-------+------+
| id    | c1   |
+-------+------+
| 99671 | NULL |
+-------+------+



可以看到还是需要扫描12个page。

InnoDB_pages_distinct: 12

...
select id,c1 from t_sk where c1 is null limit 10000,1;



SQL3, 查询 c1 任意非NULL值

如果把 c1列条件改成正常的int值,结果就不太一样了

[root@yejr.run]> select id, c1 from t_sk where c1  = 907299016;
+--------+-----------+
| id | c1 |
+--------+-----------+
| 365115 | 907299016 |
+--------+-----------+
1 row in set (0.00 sec)

slow log是这样的

InnoDB_pages_distinct: 2
...
select id, c1 from t_sk where c1 = 907299016;



可以看到,只需要扫描2个page,这个看起来就正常了。

结论1,存储大量的NULL值,除了计算更复杂之外,数据扫描的代价也会更高一些


另外,如果要查询的c1值正好介于两个page的临界位置,那么需要多读取一个page。

扫描第31号page,确认该数据页中的最小和最大物理记录

[root@yejr.run]# innodb_space -s ibdata1 -T test/t_sk -p 31 page-dump
...
records:
{:format=>:compact,
:offset=>126,
:header=>
{:next=>9996,
:type=>:conventional,
:heap_number=>2,
:n_owned=>0,
:min_rec=>false,
:deleted=>false,
:nulls=>[],
:lengths=>{},
:externs=>[],
:length=>6},
:next=>9996,
:type=>:secondary,
:key=>[{:name=>"c1", :type=>"INT UNSIGNED", :value=>1531865685}],
:row=>[{:name=>"id", :type=>"INT UNSIGNED", :value=>1507}],
:sys=>[],
:length=>8}
...
{:format=>:compact,
:offset=>5810,
:header=>
{:next=>112,
:type=>:conventional,
:heap_number=>408,
:n_owned=>0,
:min_rec=>false,
:deleted=>false,
:nulls=>[],
:lengths=>{},
:externs=>[],
:length=>6},
:next=>112,
:type=>:secondary,
:key=>[{:name=>"c1", :type=>"INT UNSIGNED", :value=>1536700825}],
:row=>[{:name=>"id", :type=>"INT UNSIGNED", :value=>361382}],
:sys=>[],
:length=>8}



指定c1的值为 1531865685、1536700825 执行查询,查看slow log,确认都需要扫描3个page,而如果换成介于这两个值之间的数据,则只需要扫描2个page。

InnoDB_pages_distinct: 3
...
select id, c1 from t_sk where c1 = 1531865685;

InnoDB_pages_distinct: 3
...
select id, c1 from t_sk where c1 = 1536700825;

InnoDB_pages_distinct: 2
...
select id, c1 from t_sk where c1 = 1536630003;

InnoDB_pages_distinct: 2
...
select id, c1 from t_sk where c1 = 1536575377;



这是因为辅助索引是非唯一的,即便是在等值查询时,也需要再读取下一条记录,以确认已获取所有符合条件的数据。

还有,当利用辅助索引读取数据时,如果要读取整行数据,则需要回表。

也就是说,除了扫描辅助索引数据页之外,还需要扫描聚集索引数据页。

来个例子看看就知道了。

#无需回表时
InnoDB_pages_distinct: 2
...
select id, c1 from tnull where c1 = 1536630003;

#需要回表时
InnoDB_pages_distinct: 5
...
select * from t_sk where c1 = 1536630003;

需要回表时,除了扫描辅助索引页2个page外,还需要回表扫描聚集索引页,而聚集索引是个3层树,因此总共需要扫描5个page。


            </div>
相关文章
|
存储 关系型数据库 MySQL
MySQL中'' ' ' NULL在Innodb存储的区别
MySQL中'' ' ' NULL在Innodb存储的区别
102 0
|
存储 SQL 关系型数据库
InnoDB索引允许NULL对性能有影响吗(1)
InnoDB索引允许NULL对性能有影响吗
|
3月前
|
机器学习/深度学习 SQL 关系型数据库
【MySQL进阶之路丨第十一篇】一文带你精通MySQL NULL值处理、正则表达式
【MySQL进阶之路丨第十一篇】一文带你精通MySQL NULL值处理、正则表达式
40 0
|
3月前
|
SQL 关系型数据库 MySQL
总结 vue3 的一些知识点:MySQL NULL 值处理
总结 vue3 的一些知识点:MySQL NULL 值处理
|
5月前
|
SQL 关系型数据库 MySQL
MySQL NULL 值处理
MySQL NULL 值处理
|
2月前
|
SQL 关系型数据库 MySQL
python在mysql中插入或者更新null空值
这段代码是Python操作MySQL数据库的示例。它执行SQL查询从表`a_kuakao_school`中选取`id`,`university_id`和`grade`,当`university_id`大于0时按升序排列。然后遍历结果,根据`row[4]`的值决定`grade`是否为`NULL`。若不为空,`grade`被格式化为字符串;否则,设为`NULL`。接着构造UPDATE语句更新`university`表中对应`id`的`grade`值,并提交事务。重要的是,字符串`NULL`不应加引号,否则更新会失败。
27 2
|
5月前
|
存储 关系型数据库 MySQL
Flink CDC中mysql cdc 抽取这个时间字段的值为null 有什么好的解决方案吗 ?
Flink CDC中mysql cdc 抽取这个时间字段的值为null 有什么好的解决方案吗 ?
107 0
|
1月前
|
关系型数据库 MySQL
mysql中判断NULL和空字符串
mysql中判断NULL和空字符串
12 0
|
2月前
|
移动开发 关系型数据库 MySQL
mysql删除为NULL或者空字符串‘‘或者‘null’的或者删除空格的
mysql删除为NULL或者空字符串‘‘或者‘null’的或者删除空格的
15 1
|
2月前
|
SQL 关系型数据库 MySQL
总结 vue3 的一些知识点:MySQL NULL 值处理
总结 vue3 的一些知识点:MySQL NULL 值处理