• 实验:验证mysql索引失效场景


    本文主要是为了验证何种情况下索引会失效,建表使用了innoDB存储引擎
    以下是一些索引失效传言,和本人验证结果,基于5.6的版本

    1. “索引列不能出现null值”,不准确,可能会全表扫描,可能会走索引,看优化器怎么衡量查询的代价
    2. “模糊查询,只有左匹配才能走索引”,对
    3. “用了or的查询,必须or两边的条件都满足最左匹配才能走索引”,对
    4. “隐式转换会引起索引失效”,对
    5. “!= 不走索引”,不知道,我在主键和非主键索引上验证了都是不走的

    另外字段列值允许为null的情况下,查询时有些坑要注意:

    1. count(*)与count(具体列名)的区别:前者会将null值统计在内,后者不会,取舍要取决于null的业务含义
    2. sum(具体字段)=null的情况:当查询的结果集为空时,sum的结果为null
    3. count(1) 和 count(具体列) 是等效的,结果一致

    总的来说,查询是否走索引,最终看的是mysql优化器的判断,网上很多“索引失效规律”都是有前提的

    建表细节:
    在这里插入图片描述

    -- 建表语句
    CREATE TABLE `t_innodb` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '是否为空对命中索引有啥影响',
      `age` int(11) DEFAULT NULL,
      `sex` tinyint(1) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `idx_name` (`name`) USING BTREE,
      KEY `idx_age_sex` (`age`,`sex`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    
    
    -- 练习与验证
    -- 查询mysql的安装路径
    show variables like '%basedir%'
    
    -- 查询版本号
    SELECT VERSION()
    
    -- 无法看到innoDB和myisam表的文件在磁盘上的区别
    
    -- 测试模糊查询
    
    -- 单个索引字段查询
    EXPLAIN select * from t_innodb where age = 11
    -- 范围查询也可索引
    EXPLAIN select age from t_innodb where age > 11 and age <44
    
    -- != 会导致索引失效
    EXPLAIN select * from t_innodb where age != 22
    
    
    
    
    
    -- null 是特殊的,要用is null
    select * from t_innodb where age = null
    
    -- 索引字段为null并不一定会索引失效
    EXPLAIN select * from t_innodb where age is null
    
    -- varchar字段 存了数字的话,字符转换问题会影响索引
    EXPLAIN select * from t_innodb where name = '22' -- 查询结果一致,因为mysql做了隐士转换
    EXPLAIN select * from t_innodb where name = 22
    
    
    -- 不是的:!= 不走索引
    
    -- select * 偶尔会影响走索引,可能是因为全表扫描的效率更高
    EXPLAIN select name from t_innodb where name != '22'
    EXPLAIN select * from t_innodb where name != '22'
    -- 走索引
    EXPLAIN select * from t_innodb where name like '22'
    -- 走索引
    EXPLAIN select * from t_innodb where name like '22%'
    -- 右边匹配不走索引
    EXPLAIN select * from t_innodb where name like '%22'
    
    -- 查询null值不影响走索引
    EXPLAIN select * from t_innodb where name is null
    
    -- 
    EXPLAIN select name from t_innodb where name is not null
    
    
    
    -- 联合索引
    
    EXPLAIN select * from t_innodb where age = 1 or age = 22 -- 晚点测试in 和 not in
    
    -- 用了or的联合索引,无论如何一定要各自遵循最左匹配:就当做or的左右都是有隐形的括号包起来的
    EXPLAIN select * from t_innodb where age = 1 or (age = 2 and sex = 22)
    
    EXPLAIN select * from t_innodb where age = 1 and sex != 22
    
    EXPLAIN select * from t_innodb where age = 11 and sex != 22
    
    
    
    -- 怎么从解析计划中看到查询是否有回表操作,看extra字段
    
    
    -- 关于null的一些坑
    SELECT count(name) from t_innodb
    SELECT count(*) from t_innodb  -- 共10条
    
    -- 含null列,查询结果不含null,
    -- 所以如果对于业务而言null是有意义的话,这种写法容易查漏数据
    SELECT * from t_innodb where name != 'zk'
    -- 含null列,如果需要查到null
    SELECT * from t_innodb where name != 'zk' or ISNULL(name)
    
    
    -- sum() 对可能为null的字段使用sum
    
    -- 没有结果集的时候返回null
    SELECT sum(age) from t_innodb where id = 10
    
    -- 直接统计的话,为null的值不参与统计
    
    SELECT sum(age) from t_innodb
    
    -- 结果为null
    select 1 + null
    
    
     select SQL_NO_CACHE  * from t_innodb where name != 'zk' or ISNULL(name)
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    举个栗子说明为啥是否走索引

  • 相关阅读:
    Spring多线程事务处理
    Java设计模式之桥接模式
    ROS2在RVIZ2中加载机器人urdf模型
    我和“愚蠢代码”的那些日子
    面试那些题(1)
    MySQL学习(4):SQL语句之数据操作语言:DML
    I.MX6ULL ARM驱动开发---块设备驱动
    element table多级表头
    C++初阶(运算符重载汇总+实例)
    repo使用 git使用
  • 原文地址:https://blog.csdn.net/xianyu_x/article/details/126371343