35 | MySQL调优之索引:索引的失效与优化
35 | MySQL调优之索引:索引的失效与优化
讲述:李良
时长12:46大小11.69M
MySQL 索引存储结构
1. 覆盖索引优化查询
2. 自增字段作主键优化查询
3. 前缀索引优化
4. 防止索引失效
总结
思考题
赞 6
提建议
精选留言(39)
- QQ怪2019-08-10回答老师问题: 按照老师的操作了一遍,实验小部分区间是会走order_id索引的,但是查询范围继续增大 ,反而不走索引而是全表扫描,大概我估摸着的是小于全表5分之一区间能够走索引,超过5分之一会全表扫描,可以使用force index(索引名)强制使用该索引,这就是有些sql表开始跑的挺快的,后面越来越慢的原因吧。。但不清楚mysql优化器为啥要这样选择,希望老师解惑?展开
作者回复: 因为order_id索引不能覆盖我们要查询的信息,所以在对order_id查询之后还需要一次回表来查找到整行数据,虽然order_id索引是顺序存放的,但是相对于主键id存放的数据顺序是不一致的,所以存在每次回表都是随机获取整行数据,如果在获取大量数据时,通过这种方式获取数据性能肯定是不理想的。 所以mysql一般判断在查询超过整个表20%的数据时,就会考虑使用聚族索引来查找数据,这种方式顺序读取数据的可能性要大于使用辅助索引的随机读。 在查询少量数据的情况下,使用辅助索引性能更加,而查询大量数据时,就未必了。 如果我们发现在查询一定量数据使用辅助索引要比主键索引快,而数据库又没有按照我们期望的去使用辅助索引,则我们可以通过子查询或force index来强制使用辅助索引。
共 5 条评论72 - CCC2019-08-10对索引进行函数操作或者表达式计算也会导致索引的失效
作者回复: 对的,点赞补充
22 - Loubobooo2019-08-11我的想法是,可以利用子查询去减少回表操作,既然有主键自增id,便可以利用聚簇索引的优势来强制走索引。代码方法如下:select * from order_detail where id in (select id from order_detail where order_id between 5000 and 10000)
作者回复: 思路是对的,这种方式可以解决。
共 3 条评论17 - 张三丰2019-10-04”如果不存在辅助索引,此时会通过查询聚簇索引来统计行数,如果此时正好存在一个辅助索引,则会通过查询辅助索引来统计行数,减少 I/O 操作。“ 这有什么区别吗?都是通过索引统计行数
作者回复: 区别在于聚簇索引存储了其他数据,而辅助索引只保存了索引列和主键,所以通过查询辅助索引统计行检索的数据量会更少,I/O操作会更少
共 2 条评论13 - 张学磊2019-08-10由于是select *操作,所以每条记录都需进行回表,当server层分析器发现between的范围太大时,使用辅助索引存在大量回表操作,所以觉得得不偿失,故而直接使用主键索引。如果想使用我们期望的索引,需要给server层分析器一个hint,force index(idx_order_id)
作者回复: 分析到位,答案正确。
13 - man1s2019-09-16走主键索引,优化器认为5000数据+回表5000次性能消耗要大于全表扫描 force index
作者回复: 👍
7 - 考休2020-03-10为什么innodb存储引擎没有支持哈希索引?
作者回复: innodb不能手动设置哈希索引,但有自适应哈希索引的功能,也就是如果发现树的查询路径太长时,会记录到一个哈希缓存中,这个时候会用到哈希索引。 哈希索引在关键字查询时非常快,但也有很多缺点,例如无法进行范围查询、无法排序等。
共 2 条评论6 - 某、 2019-12-05使用某个字段中字符串的前几个字符建立索引?这句不是很明白,能否细讲一下,能否以身份证这个字段作个栗子?
作者回复: 身份证前几位一般在相同城市或省都是一样的,所以作为前缀索引区分度不大,如果倒序存储,以原来后六位作为首位区分度更大,alert table xxx add index index_idno(idno(6));
共 2 条评论5 - Charles2019-08-14想问下老师为什么回表查询的速度会慢于直接用主键查询,因为回表也是使用主键ID去查询的,就算查询的数据量大,用不用子查询都是使用主键ID去回表或是查询,速度应该一样吧
作者回复: 回表就相当于两次索引树扫描操作了,而主键查询只有一次。
共 3 条评论5 - 天天向上2020-01-16如果查询条件中使用 or,且 or 的前后条件中有一个列没有索引,那么涉及的索引都不会被使用到。想知道为什么涉及到的索引都不会被用到,原理是什么呢?
作者回复: 如果其中有一个没有索引,这个没有索引的列就会涉及到全表扫描
4 - 张振宇2020-03-10老师,没明白开头那段,为什么要添加 create_time 这列进行组合索引啊
作者回复: 为了避免文件排序的发生。因为查询时我们只能用到status索引,如果要对create_time进行排序,则需要使用文件排序filesort。 filesort是通过相应的排序算法将取得的数据在内存中进行排序,如果内存不够则会使用磁盘文件作为辅助。虽然在一些场景中,filesort并不是特别消耗性能,但是我们可以避免filesort就尽量避免。
共 2 条评论4 - 天天向上2020-01-14order 表中建立一个复合索引 idx_user_order_status(order_no, status, user_id),使用 order_no+user_id 组合查询,只有order_no会用到索引,user_id并不会共 1 条评论2
- 行者2020-01-03索引失效一句话总结,字段a有索引,那么只能匹配字段a,除此之外均会导致索引失效,比如所有对字段a的函数计算(如reverse、crc32),类型转换(如bigint转vachar,也就是SQL中有没有单引号),前置模糊搜索(like "%张三",因为后置模糊匹配可以使用前缀索引),where子句的多条件组合不当(需要根据情况的分析是否会用索引)
作者回复: 赞
2 - Geek__ad4af7fe01f42019-08-27请问老师,既然使用辅助索引效率低,mysql默认超出20%又使用主键索引优化,而优化的效果又变低,为何还要强制使用辅助索引? 这里强制使用辅助索引的优化 和下面您的描述不是冲突吗? 因为order_id索引不能覆盖我们要查询的信息,所以在对order_id查询之后还需要一次回表来查找到整行数据,虽然order_id索引是顺序存放的,但是相对于主键id存放的数据顺序是不一致的,所以存在每次回表都是随机获取整行数据,如果在获取大量数据时,通过这种方式获取数据性能肯定是不理想展开
作者回复: 这个跟具体场景有关系,在数据量非常大的情况下,可能使用辅助索引会效率更高些。
2 - 天天向上2020-01-15SELECT COUNT(*) 时,如果不存在辅助索引,此时会通过查询聚簇索引来统计行数,如果此时正好存在一个辅助索引,则会通过查询辅助索引来统计行数,减少 I/O 操作。 这里说的正好存在一个辅助索引,指的是where条件中正好存在辅助索引吗?
作者回复: 这里指的是无条件搜索,如果有条件搜索,则会根据搜索条件的索引来统计行数。
2 - 传传传传传传奇2019-11-05来晚了 有一事不明,通过创建覆盖索引(如文中将商品编码、名称、价格作为一个组合索引)在某些情况下可以避免回表。但是非主键索引存储的却是主键的值,并以此来作为指向行的指针。在查询商品编码的时候,怎么理解避免回表吗?
作者回复: 覆盖索引中的叶子节点是主键索引,但是非叶子节点中包含了覆盖索引的值,所以不需要进行回表操作
1 - 尔冬橙2019-09-07老师,你这个表里的order id和id不是一起递增的么?如果orderid也是递增的,那情况又是怎呢
作者回复: 如果与id索引的排序是一致的,会走索引,可以动手实践一下
共 2 条评论1 - 我行我素2019-08-13老师,想请问下InnoDB引擎下使用HASH索引也可以啊,但是文中的图InnoDB索引Hash是no
作者回复: 官网给出的是不支持自创建hash数据结构的索引,但是它是自适应的,也就是我们不能人为的干预使用hash索引。具体的可以参考官网:https://dev.mysql.com/doc/refman/8.0/en/create-index.html
1 - Geek_9269212022-07-10索引实现可以分为以下几种 1. 没有遵循最左前缀原则 2. 使用破坏索引的函数 3. 组合索引失效 4. 字段存储为null,这个比较特殊,null是不走索引的,这也是为什么很多DBA让我们设计表的时候给默认值。一是节省存储空间,二是走索引. 5. 还有比较特殊的一个函数,in ,这里测试过,in里面的参数超过5个好像就不走索引了,不知道为什么。展开
- KaitoShy2022-03-05老师,你好。看了文章收益匪浅。但我看到”在创建表时,无论使用 InnoDB 还是 MyISAM 存储引擎,默认都会创建一个主键索引,而创建的主键索引默认使用的是 B+Tree 索引。”时,想到 MySQL 官方文档中说,每个 InnoDB 的表都会创建一个聚簇索引,通常来说聚簇索引就是主键索引。但是有种情况是,我创建表的时候不指定主键就不会就主键索引了,那么在这种情况下,聚簇索引就是第一个非空的唯一索引,如果主键索引和合适的唯一索引的话,就会创建一个隐藏的聚簇索引。所以的描述是不是不太妥当?请老师指点。https://dev.mysql.com/doc/refman/5.7/en/innodb-index-types.html展开