MySQL 独立索引和联合索引的选择

 更新时间:2021年05月17日 11:02:53   作者:岛上码农  
为了提高数据库效率,建索引是家常便饭;那么当查询条件为2个及以上时,我们是创建多个单列索引还是创建一个联合索引好呢?他们之间的区别是什么?哪个效率高呢?本文将详细测试分析下。

通常会对多列索引缺乏理解,常见的错误是将很多列设置独立索引,或者是索引列使用错误的次序。我们在下一篇讨论索引列次序的问题,首先看一下多列独立索引的情况,以下面的表结构为例:

CREATE TABLE test (
  c1 INT,
  c2 INT,
  c3 INT,
  KEY(c1),
  KEY(c2),
  KEY(c3),
);

使用这种索引策略通常是一些权威的建议(例如在WHERE条件中用到的条件列增加索引)的结果。事实上,这是大错特错的,要评分的话顶多给1颗星。这种方式的索引与真正优化的索引相比,要慢上几个数量级。有时候当你不能设计三星以上的索引时,去关注优化行次序或者创建覆盖索引都比忽略WHERE条件强。

覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。 当一条查询语句符合覆盖索引条件时,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率。 如,表covering_index_sample中有一个普通索引 idx_key1_key2(key1,key2)。当我们通过SQL语句:select key2 from covering_index_sample where key1 = ‘keytest';的时候,就可以通过覆盖索引查询,无需再从数据表找数据行。

对很多列创建独立的索引在很多情况下,并不能帮助MySQL改善性能。MySQL 5.0及更新的版本可以使用索引合并策略对这类设计进行些许的优化 —— 这种方式允许在有多列索引的数据表中的查询中限制在索引的使用去定位所需的数据行。

index merge 是对多个索引分别进行条件扫描,然后将它们各自的结果进行合并(intersect/union)

早期的MySQL版本只能使用一个索引,因此当没有索引辅助时,MySQL通常进行全表扫描。例如在film_actor表有一个film_id和actor_id索引,但是在WHERE条件中同时使用这两个索引并不是一个好的选择:

SELECT film_id, actor_id FROM film_actor WHERE actor_id = 1 OR film_id = 1;

在早期的MySQL版本中,除非你像下面的语句一样将两个查询联合起来,否则这个查询会导致全表扫描。

SELECT film_id, actor_id FROM film_actor WHERE actor_id = 1 UNION ALL 
SELECT film_id, actor_id FROM film_actor WHERE film_id = 1 AND actor_id <> 1;

在MySQL 5.0之后的版本中,查询会同时使用两个索引并且合并最终的结果。需要三个变体的算法实现这个过程:

  1. 使用OR条件获取并集(union)数据
  2. 使用AND条件获取交集数据
  3. 将上面两个步骤的数据的交集再取并集。

上面有点费解,其实应该是分布使用单个条件(以便使用索引)查出全部数据,然后再组合数据。下面使用EXPLAIN查看一下。

EXPLAIN SELECT `film_id`,`actor_id` FROM `film_actor` WHERE `actor_id`=1 OR `film_id`=1

可以看到查询方式是全表扫描,但是使用了Extra做优化。MySQL在处理负责查询时会使用这种技巧,因此你可能会在Extra中看到嵌套操作。这种索引合并的策略有些时候会发挥很好的作用,但更多的时候应该当作是对差劲索引使用的一个指示:

  1. 当服务器使用交集索引(通常是使用AND条件),通常意味着你需要一个索引包含所有相关的列,而不是独立的索引列再组合。
  2. 当服务器使用并集索引(通常是使用OR条件),有时候缓存、排序和合并操作会占用很多的CPU和内存资源,尤其是索引并不都是具备筛选的时候,这会导致扫描返回大量的数据行供合并操作。
  3. 记住优化器并不承担这些成本——它仅仅是优化随机页读取的数量。这会使得查询“掉价”,导致全表扫描造成事实上更慢。CPU和内存的高占用会影响并发查询,但这些影响在你单独运行查询语句时并不会发生。因此,有时候像在MySQL 4.1版本那样重写那些使用UNION的查询会得到更优的效果。

当你使用EXPLAIN分析的时候看到了索引合并,你应该检查查询语句和表结构,看看是不是最优的方式。你可以使用optimizer_switch(优化开关)禁用索引合并来检查。

再将film_actor的索引改为联合索引(删除原先的两列独立索引film_id和actor_id)看一下效果,可以看到此时避免了全表查询。

ALTER TABLE film_actor ADD INDEX `sindex` (`film_id`,`actor_id`);

以上就是MySQL 独立索引和联合索引的选择的详细内容,更多关于MySQL 独立索引和联合索引的资料请关注脚本之家其它相关文章!

相关文章

  • MySQL ibdata1文件减肥过程解析

    MySQL ibdata1文件减肥过程解析

    这篇文章主要为大家介绍了MySQL ibdata1文件减肥过程解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • mysql当中怎么执行sql脚本文件

    mysql当中怎么执行sql脚本文件

    这篇文章主要给大家介绍了关于mysql当中怎么执行sql脚本文件的相关资料,需要的朋友可以参考下
    2023-08-08
  • linux服务器清空MySQL的history历史记录 删除mysql操作记录

    linux服务器清空MySQL的history历史记录 删除mysql操作记录

    mysql历史记录上可能留下了很多敏感信息,比如密码什么的,需及时清空历史记录,下面分享一下inux服务器清空MySQL的history历史记录的方法
    2014-01-01
  • MySQL慢查询现象解决案例

    MySQL慢查询现象解决案例

    这篇文章主要介绍了MySQL慢查询现象解决案例,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下,希望对你的学习有所帮助
    2022-08-08
  • CentOS 7搭建多实例MySQL8的详细教程(想要几个搞几个)

    CentOS 7搭建多实例MySQL8的详细教程(想要几个搞几个)

    这篇文章主要介绍了CentOS 7搭建多实例MySQL8的详细教程(想要几个搞几个),本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • mysql5.6.8源码安装过程

    mysql5.6.8源码安装过程

    这篇文章主要介绍了mysql5.6.8源码安装过程,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-01-01
  • MySQL EXPLAIN执行计划解析

    MySQL EXPLAIN执行计划解析

    本文主要介绍了MySQL EXPLAIN执行计划解析,通过MySQL EXPLAIN执行计划的各个字段的含义以及使用方式。感兴趣的小伙伴可以参考一下
    2022-08-08
  • MySQL数据库中外键(foreign key)用法详解

    MySQL数据库中外键(foreign key)用法详解

    这篇文章主要给大家介绍了关于MySQL数据库中外键(foreign key)的相关资料,MySQL 外键约束可以用来保证表与表之间的关系完整性,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • MySQL查看版本的五种方法总结

    MySQL查看版本的五种方法总结

    在日常项目开发过程中,我们经常要连接自己的数据库,此时不知道数据库的版本是万万不可的,下面这篇文章主要给大家介绍了关于MySQL查看版本的五种方法,需要的朋友可以参考下
    2023-02-02
  • 在SpringBoot中实现WebSocket会话管理的方案

    在SpringBoot中实现WebSocket会话管理的方案

    在构建实时通信应用时,WebSocket 无疑是一个强大的工具,SpringBoot提供了对WebSocket的支持,本文旨在探讨如何在 Spring Boot 应用中实现 WebSocket 会话管理,我们将通过一个模拟的场景一步步展开讨论,需要的朋友可以参考下
    2023-11-11

最新评论