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百万数据表加索引优化的方法

    mysql百万数据表加索引优化的方法

    在大数据时代,随着数据量的快速增长,对数据库的索引优化变得尤为重要,本文主要介绍了mysql百万数据表加索引优化的方法,感兴趣的可以了解一下
    2024-02-02
  • centos上安装mysql并设置远程访问的操作方法

    centos上安装mysql并设置远程访问的操作方法

    这篇文章主要介绍了centos上安装mysql并设置远程访问的操作方法,需要的朋友可以参考下
    2017-11-11
  • mysql触发器实时检测一条语句进行备份删除思路详解

    mysql触发器实时检测一条语句进行备份删除思路详解

    遇到过这样一个需求,在一张表里会不时出现 “违规” 字样的字段,需要在出现这个字段的时候,把整行的数据删掉,针对这个需求我们该如何操作呢,下面跟随小编看下mysql触发器实时检测一条语句进行备份删除的解决思路,一起看看吧
    2021-09-09
  • MySQL8.0连接协议及3306、33060、33062端口的作用解析

    MySQL8.0连接协议及3306、33060、33062端口的作用解析

    这篇文章主要介绍了MySQL8.0连接协议及3306、33060、33062端口的作用解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • 同时运行多个MySQL服务器的方法

    同时运行多个MySQL服务器的方法

    在同一台机器上运行多个有些情况下你可能想要在同一台机器上运行多个服务器。例如,你可能想要测试一个新的MySQL版本而让你现有生产系统的设置不受到干扰, 或你可能是想要为不同的客户提供独立的MySQL安装一个因特网服务供应商。
    2008-05-05
  • 一文带你玩转MySQL获取时间和格式转换各类操作方法详解

    一文带你玩转MySQL获取时间和格式转换各类操作方法详解

    最近在开发中常常使用时间的转换函数,所以一直都想整理一下这些函数,下面这篇文章主要给大家介绍了关于MySQL获取时间和格式转换各类操作方法的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • SQL实现LeetCode(183.从未下单订购的顾客)

    SQL实现LeetCode(183.从未下单订购的顾客)

    这篇文章主要介绍了SQL实现LeetCode(182.从未下单订购的顾客),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • mysql创建表添加字段注释的实现方法

    mysql创建表添加字段注释的实现方法

    这篇文章主要介绍了mysql创建表添加字段注释的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • mysql数据库从服务器移植到个人PC的方法

    mysql数据库从服务器移植到个人PC的方法

    有时候本地也需要数据库进行测试,那么就需要将服务器的东西移植到本地,如果有服务器控制权限,可以直接复制mysql的目录(windows下),如果是别的那么就需要下面的方法了。
    2011-08-08
  • MySQL8新特性之降序索引底层实现详解

    MySQL8新特性之降序索引底层实现详解

    这篇文章主要介绍了MySQL8新特性之降序索引底层实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05

最新评论