MYSQL 8 中间字段有NULL 值,还是无法走索引,所以我高估了MYSQL 的查询智商

36ce18e131743dc9476a060b32780ed5.png

开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(共800人左右 1 + 2 + 3)新人会进入3群,回复有特殊需求的会同时进2群和3群。

基于半瓶子咣当的状态,PG, MYSQL , POLARDB , MONGODB ,REDIS 还是都能舞刀弄枪几下的,但是这个弄这弄着,这记忆力就会不好,因为我一直对于MYSQL 8 的优化器的进步,表达了一个满意的记忆,虽然你比不了,oracle, sql server ,pg ,但是MYSQL 也差不太多了,实际上教育了我,版本MYSQL 8.013(生产) 试验 8.030 实际上这二者在这个问题上没有差别。当然也再次印证了, 开源数据库一定在某些方面是给你一个  disabled 的 状态,否则怎么就商业数据库卖钱呢,不同意的参见,今天一起发的 POSTGRESQL EDB 公司的文章, PG ,MYSQL 同时都能印证,不花钱的产品,你要求别太高。

废话太多,在生产上的一个表字段中包含了连续了  A  + B + C  A 为字符,B 为字符,C为日期,索引中也是这样建立的,A B C ,但是在查询中出现了 A + C (C为范围查询),虽然实际上走了我们建立的索引,但是实际上,和没走也差不多。下面用一个实例来反馈

测试数据100万

3d87cb00053ebd68525e62faaa1f16a6.png

select * from test_innodb where user_id = '00OSL5Whq664QQzaYbOp' and create_time >= '2023-04-14 10:00:00' and create_time < '2023-04-19 10:00:00';

语句很简单,另外数据中在生产系统中,user_id 的位置并不是唯一值,而测试系统中是唯一值,group_id 不是唯一值,并且里面有NULL ,时间就是我们的时间,没有空值。

索引我们先建立三个字段的,然后执行了查询语句。从图中看,我们可以看到走了三个字段的联合索引,但是基本上在选择字段部分仅仅是使用 user_id 作为实际索引使用的部分。

f3c79445ba0024e4d74c5addb301b09a.png

在我们创建了仅仅有 user_id 和 create_time 的索引,我们再次运行语句,可以看到整体的执行的中的执行计划,是走了索引的全部

3a3bc7529d9d811147ef3b1e97e2a435.png

我的问题就来了,这个为什么同样的数据库同样的语句,同样的MYSQL,执行计划中,仅仅是一个索引,中间多个一个字段,就忽略了后面的日期范围部分,WHY ,我的记忆是MYSQL 是可以跳过索引中间有字段但是查询里面没有需求的字段。

原因是为什么在 MySQL 中,当使用复合索引(包含多个字段的索引)时,如果中间字段的值为 NULL,那么将仅会走前缀。也就是说,复合索引只有在所有前面字段的值都非 NULL 时,才能被用来检索。

例如,假设我们有一个包含三个字段(a, b, c)的复合索引:

CREATE INDEX idx_example ON table_name (a, b, c);

以下查询可以使用复合索引 idx_example

SELECT * FROM table_name WHERE a = 1 AND b = 2;

但是,如果字段 b 的值为 NULL,那么复合索引将只能走前缀,即只会用到字段 a

SELECT * FROM table_name WHERE a = 1 AND b IS NULL;

此时,索引将不再涉及字段 c,因为字段 b 的值为 NULL,导致索引只能走前缀。

那么别的数据库是否也有这个问题,我们来看看 MYSQL 的死对头 POSTGRESQL 

在 PostgreSQL 中,当使用复合索引(包含多个字段的索引)时,即使中间字段的值为 NULL,该复合索引仍可以用于查询。这是因为 PostgreSQL 对 NULL 值进行了特殊处理,将其包含在索引内。这种行为与 MySQL 不同。

例如,假设我们有一个包含三个字段(a, b, c)的复合索引:

CREATE INDEX idx_example ON table_name (a, b, c);

以下查询可以使用复合索引 idx_example:

SELECT * FROM table_name WHERE a = 1 AND b = 2;

同时,当字段 b 的值为 NULL 时,PostgreSQL 也能够使用该复合索引:

SELECT * FROM table_name WHERE a = 1 AND b IS NULL;

在这个例子中,即使 b 字段的值为 NULL,索引依然可以被用来检索。

那么到此为止,同为免费数据库的POSTGRESQL 是可以在这样的情况来使用索引的,那么我们就会引发一个MYSQL 性能差另一个问题

在查询中,MYSQL 可能会由于应付上面的查询,需要建立更多的索引来满足查询的性能要求,而其他的数据库则不需要,一个索引基本上可以搞定。

最终导致MYSQL 的查询,插入,删除等性能都相对于其他的数据库低下。好吧,不能说下去,MYSQL的FUNS 已经举着刀杀来了。 

8964e0c2c6e5e133430b6ec0ca9a278b.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值