高性能的索引策略(上)

  高效的选择和使用索引有很多方式,其中有些事针对特殊案例的优化方法,有些则是针对特定行为的优化,使用哪个索引,以及如何评估选择不同索引性能影响的技巧,则需要持续不断的练习。接下来将介绍如何高效的使用索引。

  独立的列

  我们通常会看到一些查询不当的使用索引,或者是的MySQL无法使用已有的索引。如果查询中的列不是独立的,则MySQL就不会使用索引。“独立的列”是指索引列不能是表达式的一部分,也不能是函数的参数。

  例如,下面的这个查询无法使用actor_id的索引:

  SELECT actor_id FROM actor WHERE actor_id +1 = 5;

  凭肉眼很容易看出WHERE 中的表达式其实等价于 actor_id=4 ,但是MySQL无法自动解析这个方程式。这完全是用户的行为。我们应该养成简化WHERE条件的习惯,始终将索引列单独放在比较符合的一侧。

  下面是常见的错误:

  SELECT ... WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col) <=10;

  前缀索引和索引选择性

  有时候需要索引很长的字符列,这会让索引编的大且慢。一个策略是前面提到的模拟hash索引。蛋有时候这样做还不够,还可以做什么呢?

  通常可以索引开始的部分字符串,这样可以大大节约索引空间,从而提高索引效率。但是这样也会降低索引的选择性。索引的选择性是指,不重复索引的值(也称为基数)和数据表的记录总数(#T)的比值,范围从1/#T到1之间。索引的选择性越高,则查询效率越高,因为选择性高的索引可以让MySQL在查找时过滤掉更多的行。唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

  一般情况下某个列前缀索引的选择性也是足够高的,足以满足查询性能。对于BLOB、TEXT或者很长的VARCHAR类型的列,必须使用前缀索引,因为MySQL不允许索引这些列的完整长度。

  诀窍在于要选择足够长的前缀以保证较高的选择性,同时又不能太长(以便节约空间)。前缀应该足够长,以使得前缀索引的选择性接近于索引整个列,换句话说,前缀的“基数”应该接近于完整列的“基数”。

  为了决定前缀的合适长度,需要找到最常见的值的列表,然后和最常见的前缀列进行比较。

  前缀索引是一种能使索引更小,更快的有效办法,但另一方面也有其缺点:MySQL无法使用前缀索引做order by 和group by 操作,也无法使用前缀索引做覆盖扫描。

  一个常见的场景是针对很懂行的十六进制唯一ID使用前缀索引。在前面已经讨论了很多有效的基数来存储这类ID信息,但如果使用打包过的解决方案,因而无法修改存储结构,那该怎么办?此时如果采用长度为8的浅醉索引通常能够显著的提升性能,并且这种方法对引用层上完全透明。

  有时候后缀索引也有用途(例如,找到摸个域名的所有电子邮件地址)。MySQL原生并不支持反向索引,但是可以吧字符串反转后存储,并给予此建立前缀索引。可以通过触发器来维护这种索引。

  多列索引

  很多人对多列索引的理解都不够。一个常见的错误就是,为每个列建立独立的索引,或者按照错误的顺序创建多列索引。

  我们会在稍后的章节中单独讨论索引列的顺序问题。先来看第一个问题,为每个列床架独立的索引,从SHOW CREATE TABLE 中很容易看到这种情况:

  CREATE TABLE t(

    c1 INT,c2 INT , c3 INT ,KEY(c1),KEY(c2),KEY(c3)

  );

  这种索引策略,一般是由于人们听到一些专家诸如“把WHERE 条件里面的列都建上索引”这样模糊的建议导致的。实际上这个建议是非常错误的。这样一来最好的情况也只能是“一星”索引,其性能比起真正最有效的索引可能差几个数量级。有时如果无法设计出一个“三星”索引,那么不如忽略掉WHERE 子句,集中精力优化索引列的顺序,或者创建一个全覆盖索引。

  在多个列上奖励独立的单列索引大部分情况下不能提高MySQL的查询性能。MySQL5.0和更高的版本医用了一种叫“索引合并”策略,一定程度上可以使用表上的多个单列索引来定位指定的行。更早版本的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版本中,MySQL对于这个查询是会使用全表扫描的,除非改写成如下的两个查询UNION的方式:

  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;

  但是在MySQL5.0 和更高的版本中,产线能够同时使用者两个单列索引进行扫米昂,并将结果进行合并。这种算法有三个变种:OR条件的联合,AND条件的相交,组合前面两种情况的联合及相交。下面的查询就是使用了两个索引扫描的联合,通过EXPLAIN中的Extra列可以看出这点:

  EXPLAIN SELECT film_id,actor_id FROM film_actor WHERE actor_id=1 or film_id = 1 \G

  MySQL会使用这类技术优化负责的查询,所以在某些语句的EXTRA列中还可以看到嵌套操作。

  索引合并策略有时候是一种优化的结构,但实际上更多的时候说明了表上的索引建的很糟糕:

  当出现服务器对多个索引做相交操作(通常有多个AND条件),通常意味着需要一个包含所有相关列的多个索引,而不是独立的单列索引。

  当服务器需要对多个索引做联合操作(通常有多个OR条件),通常需要耗费大量的cpu和内存资源在算法的缓冲,排序和合并的操作上。特别是当其中有些索引的选择性不高。需要合并扫描返回大量数据的时候。

  更重要的是,优化器不会吧这些成本算到“查询成本”中,游虎丘只关心随机页面读取。这会使得查询成本被低估,导致该执行计划还不如直接走全表扫描。这样做不但会消耗更多的cup和内存资源,还可能影响查询的并发性,但如果是单独鱼腥这样的查询则往往会忽略对并发现的影响。通常来说,还不弱在MySQL4.1或更早的时代一样,将查询改写成UNION的方式往往会更好。

时间: 2024-11-06 00:48:31

高性能的索引策略(上)的相关文章

高性能的索引策略2

6 覆盖索引 [可参考博文 https://www.cnblogs.com/kerrycode/p/9909093.html] 如果一个索引包含所有需要查询的字段,则称之为“覆盖索引”. 使用覆盖索引,只需要扫描索引,而无需回表: 一般索引比数据行数少,若只需要读取索引,则mysql访问数据量会减少 索引是按照索引列值排序的,所以对于IO密集型范围查询会比随机从磁盘读取每一行数据的磁盘IO要少得多 当发起一个被索引覆盖的查询是,在EXPLAIN中的extra列可以看到 “Using index”

高性能的索引策略01---独立的列

我们通常会看到一些查询不当地使用索引,或者使得MySQL无法使用已有的索引.如果查询中的列不是独立的,则MySQL就不会使用索引."独立的列"是指索引列不能是表达式的一部分,也不能是函数的参数. 例如下面这个查询无法使用actor_id列的索引: mysql> select actor_id from sakila.actor where actor_id+1 = 5; 凭肉眼很容易看出where中的表达式其实等价于actor_id=4,但是MySQL无法自动解析这个方程式.这完

高性能的索引策略5-案例学习

mysql使用某个索引进行范围查询,也就无法使用该所有后续字段进行排序了. 1 支持多种过滤条件 2 避免多个范围条件 对于范围条件查询,mysql无法使用范围列后面的其他索引, 但是对于等“多个等只查询”没有这个限制[in (a,b,c,d...) 是等值操作] 3 优化排序 原文地址:https://www.cnblogs.com/wooluwalker/p/12237341.html

高性能的索引策略4-冗余和重复索引

如果创建了索引(A,B),再创建索引(A)就是荣誉索引,因为索引(A)是索引(A,B)的前缀索引,因此索引(A,B)可以当做索引(A)来使用[仅仅针对B Tree索引来讲] 针对InnoDB,ID为主键,索引(A)可当做 (A,ID)来使用,不用再创建索引(A,ID) 表中的索引越多,则insert .update.delete的操作会变得越慢,一般来讲,会选择扩展现有的索引,而不是 增加新的索引. 原文地址:https://www.cnblogs.com/wooluwalker/p/12237

高性能的索引策略3-使用索引扫描做排序

mysql有两种方式生成有序结果: 通过排序操作 order by 按照索引顺序扫描(explain 出来的type 为 index) 扫描索引本身是很快的,因为只需要从一条索引记录移动到下一条索引记录即可.但是如果索引不能覆盖查询所需的全部列,那就不得不每扫描一条索引记录就得回表查询一次对应的行.这基本上就是随机IO. 因此,按照索引顺序读取数据的速度通常要比顺序全表扫描慢. 尽可能设计同一个索引技能满足排序,又可用于查找行. mysql使用索引对结果排序的前提: 索引的列顺序和order b

创建高性能的索引

索引可以包含一个或多个列的值.若索引包含多个列,那么列的顺序也十分重要,因为MySQL只能高效的使用索引的最左前缀列. 在MySQL中,索引是在存储引擎层而不是服务层实现的,所以并没有统一的索引标准.不同存储引擎的索引的工作方式并不一样,也不是所有的存储引擎都支持所有类型的索引.即使多个存储引擎支持同一种类型的索引,其底层的实现也可能不同. B-Tree索引 若没有指定特定类型的索引,则一般都是指的是B-Tree索引,它使用B-Tree数据结构来存储数据.InnoDB使用的是B+Tree.MyI

《高性能MySQL》读书笔记之创建高性能的索引

索引是存储引擎用于快速找到记录的一种数据结构.索引优化是对查询性能优化的最有效手段.索引能够轻易将查询性能提高几个数量级.创建一个最优的索引经常需要重写查询.5.1 索引基础 在MySQL中,存储引擎首先在索引中找到对应值,然后根据匹配的索引记录找到对应的数据行. 索引可以包含一个或多个列的值.如果索引包含多个列,那么列的顺序也十分重要,因为MySQL只能高效地使用索引的最左前缀列. 5.1.1 索引的类型 索引有很多类型,可以为不同的场景提供更好的性能.在MySQL中,索引是在储存引擎层而不是

高性能MySQL——创建高性能的索引

索引是存储引擎用于快速查找记录的一种数据结构.索引优化是对查询性能优化最有效的手段. 1.索引的类型 在MySQL中,索引是在存储引擎层而不是服务器层实现的.所以没用统一的索引标准,不同存储引擎的索引工作方式并不相同. B-Tree索引 B-Tree索引即使用B-Tree数据结构来存储数据.B-Tree通常意味着所有值都是按顺序存储的,并且每个叶子页到根的距离相同.存储引擎已不同的方式来使用B-Tree索引,性能也各不相同. 可以使用B-Tree索引的查询类型--全键值.键值范围和键前缀查找.其

高性能MySQL--创建高性能的索引

关于MySQL的优化,相信很多人都听过这一条:避免使用select *来查找字段,而是要在select后面写上具体的字段. 那么这么做的原因相信大家都应该知道:减少数据量的传输. 但我要讲的是另外一个原因:使用select *,就基本不可能使用到覆盖索引(什么是覆盖索引,后面会说). 而将一个本该可以用覆盖索引的查询变成了不能使用覆盖索引的查询,就会导致随机I/O或回表查询(回表查询在介绍聚簇索引的时候会说). 一.索引的类型 1.B-Tree索引 大部分的MySQL引擎都支持这种索引,它是使用