首页 > 数据库技术 > 详细

mysql笔记02 创建高性能的索引

时间:2016-01-22 02:57:38      阅读:170      评论:0      收藏:0      [点我收藏+]

创建高性能的索引

1. 索引(在MySQL中也叫做"键(key)")是存储引擎用于快速找到记录的一种数据结构。

2. 索引可以包含一个或多个列的值。如果索引包含多个列,那么列的顺序也十分重要,因为MySQL只能高效低使用索引的最左前缀列。

3. B-Tree索引:当人们谈论索引的时候,如果没有特别执行索引类型,那多半说是B-Tree索引,它使用B-Tree数据结构来存储数据。

    1). 可以使用B-Tree索引的查询类型:

         a. 全职匹配:全值匹配指的是和索引中的所有列进行匹配。

         b. 匹配最左前缀:即只使用索引的第一列。

         c. 匹配列前缀:也可以值匹配某一列的值的开头部分。

         d. 匹配范围值

         e. 精确匹配某一列并范围匹配另外一列

         f. 只访问索引的查询:覆盖索引

    2). 因为索引树中的节点是有序的,所以除了按值查找之外,索引还可以用于查询中的ORDER BY操作(按顺序查找)。一般来说,如果B-Tree可以按照某种方式查找到值,那么也可以按照这种方式用于排序。

    3). B-Tree索引的限制

         a. 如果不是按索引的最左列开始查找,则无法使用索引。

         b. 不能跳过索引中的列。

         c. 如果查询中有某个列的范围查询,则最右边的所有列都无法使用索引优化查询。如果范围查询列值的数量有限,那么可以通过使用多个等于条件来代替范围查找。

4. 哈希索引(hash index):哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才有效。结构十分紧凑,查询速度非常快。

    InnoDB引擎有一个特殊的功能叫做"自适应哈希索引"。当InnoDB注意到某个索引值被使用得非常频繁时,它会在内存中基于B-Tree索引之上再创建一个哈希索引,这样B-Tree索引也就有哈希索引的一些优点。

5. 空间数据索引,全文索引,其他索引类别

6. 索引的优点:索引可以让服务器快速定位到表的指定位置。最常见的B-Tree索引,按照顺序存储数据,所以MySQL可以用来做ORDER BY 和 GROUP BY操作。总结下来,索引有如下三个优点:

    1). 索引大大减少了服务器需要扫描的数据量

    2). 索引可以帮助服务器避免排序和临时表

    3). 索引可以将随机IO变为顺序IO。

7. 三星系统:索引将相关的记录放到一起则获得一星;如果索引中数据顺序和查找中的排序顺序一致则获得二星;如果索引中的列包含了查询中需要的全部列则获得三星。

8. 索引是最好的解决方案吗?对于非常小的表,大部分情况下简单的全表扫描更高效。对于中到大型的表,索引就非常有效。但对于特大型的表,建立和使用索引的代价将随之增长。这种情况下,则需要一种技术

    可以直接区分出查询需要的一组数据,而不是一条记录一条记录的匹配。

    如果表的数量特别多,可以建立一个元数据信息表,用来查询需要用到的某些特性。例如:记录"哪个用户信息存储在哪个表里面"。

9. 高性能的索引策略:

    1). 独立的列:独立的列是指索引列不能是表达式的一部分,也不能是函数的参数。如果查询中的列不是独立的,则MySQL就不会使用索引。

    2). 前缀索引和索引选择性:有时候需要索引很长的字符列,这会让索引变得很大且慢。通常可以索引开始部分的字符,这样可以大大节约索引空间,从而提高索引效率。但这样会降低索引的选择性。

         a. 索引的选择性是指,不重复的索引值(也称为基数)和数据表的记录总数(#T)的比值,范围从1/#T到1之间。索引的选择性越高则查询效率越高,因为选择性高的索引可以让MySQL在查找时过滤掉更多的行。

             唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

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

         c. 诀窍在于要选择足够长的前缀以保证较高的选择性,同时又不能太长(以便节省空间)。计算合适的前缀长度的一个方法是计算完整列的选择性,并使前缀的选择性接近于完整列的选择性。

            下面是如何计算完整列的选择性:SELECT COUNT(DISTINCT city)/COUNT(*) FROM sakila.city_demo;        查询结构值为:0.031

            通常来说,这个例子中如果前缀的选择性能够接近于0.031,基本上就可以用了。可以在一个查询中针对不同前缀长度进行计算,这对于大表非常有用。

            下面给出了如何在同一个查询中计算不同前缀长度的选择性:

             SELECT COUNT(DISTINCT LEFT(city,3)) AS sel3,COUNT(DISTINCT LEFT(city,4)) AS sel4,COUNT(DISTINCT LEFT(city,5)) AS sel5,

                         COUNT(DISTINCT LEFT(city,6)) AS sel6,COUNT(DISTINCT LEFT(city,7)) AS sel7 FROM sakila.city_demo;

             查询结果值,按顺序为:0.0238 ,  0.0293, 0.0305,0.0309,0.0310

             查询显示当前前缀长度到达7的时候,再增加前缀长度,选择性提升的幅度已经很小了。

         d. 只看平均选择性是不够的,也有例外的情况,需要考虑最坏情况下的选择性。

         e. 前缀索引是一种能使索引更小、更快的有效办法,但另一方面也有其缺点:MySQL无法使用前缀索引做ORDER BY和GROUP BY , 也无法使用前缀索引做覆盖扫描。

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

    3). 多列索引:在MySQL或更新的版本中,会使用"索引合并"策略,查询能同时使用两个单列索引进行扫描,并将结果进行合并。这种算法有三个变种:OR条件的联合(union),AND条件的相交,

         组合前两种情况的联合及相交。

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

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

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

         c. 优化器不会把这些计算到"查询成本"(cost)中,优化器值关系随机页面读取。这样不仅消耗更多的CPU和内存资源,还会影响查询的并发性。

         d. 如果在EXPLAIN中看到有索引合并,应该好好检查一下查询和表的结构,看是不是已经最优的。也可以哦太难过参数optimizer_switch来关闭索引合并功能。也可以使用IGNORE INDEX提示让优化器

             忽略掉某些索引。

    4). 选择合适的索引列顺序:正确的索引顺序依赖于使用该索引的查询,并同时满足需要考虑如何更好地满足排序和分组的需要。

         a. 在一个多列的B-Tree索引中,索引列的顺序意味着索引首先按照最左列进行排序,其次是第二列,等等。所以,索引可以按照升序或者降序进行全表扫描,以满足符合列顺序的ORDER BY,GROUP BY和

             DISTINCT等字句的查询需求。

         b. 当不需要考虑排序和分组时,将选择性最高的列放在前面通常是很好的。这时候索引的作用只是用于优化WHERE条件查询。

         c. 更具运行频率最高的查询来调整索引的顺序,让这种情况下索引的选择性最高。

         d. 如果是从诸如pt-query-digest这样的工具的报告中提起"最差"查询,那么再按上面办法选定索引顺序往往是非常高效的。如果没有类似的具体查询来运行,那么最好还是按经验法则来做,因为全局法则考

             滤的是全局基数和选择性,而不是某个具体查询。

             SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,COUNT(DISTINCT customer_id)/COUNT(*) AS customer_id_selectivity, count(*) from payment

             查询结果值为:staff_id_selectivity  0.0001,customer_id_selectivity  0.0373, count(*)  16049 

             customer_id 的选择性更高,所以答案是将其作为索引列的第一列

         e. 尽管关于选择性和基数的经验法则值得去研究和分析,但一定要记住别忘了WHERE字句中的排序、分组和范围条件等其他因素,这些因素可能对查询的性能造成非常大的影响。

10. 聚簇索引:InnoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。它的数据实际上存储在索引的叶子页中。"聚簇"表示把数据行和相邻的键值紧凑地存储在一起。因为无法同时把数据行存放在

      两个不同的地方,所以一个表只能有一个聚簇索引。

      1). InnoDB将通过主键聚集数据。如果没有定义主键,InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB会隐式定义一个主键作为聚簇索引。InnoDB只聚集在同一个页面中的记录。包

           含相邻键值的页面可能会相距甚远。

      2). 聚簇索引的优点:

           a. 可以把相关的数据保存在一起。

           b. 数据访问更快。

           c. 使用覆盖索引扫描的查询可以直接使用叶节点中的主键值。

      3). 聚簇索引的缺点:

           a. 更新聚簇索引列的代价很高,因为会强制将每个被更新的行移动到新的位置。

           b. 可能会导致页分裂。

           c. 导致全表扫描变慢,尤其是行比较稀疏。

           e. 二级索引(非聚簇索引)可能比想象的要更大,因为在二级索引的叶子节点包含了引用行的主键列。

           f. 二级索引访问需要两次索引查询,而不是一次。这是因为二级索引叶子节点保存的不是指向行的物理位置的指针,而是行的主键值。这意味着通过二级索引查找行,存储引擎需要找到二级索引的叶子

              节点获得对应的主键值,然后根据这个值去聚簇索引中查找到对应的行。这里做了重复工作:两次B-Tree查找而不是一次。

      4). 最好避免随机的(不连续且值的分布范围非常大)聚簇索引,特别是对于IO密集型的应用。例如:从性能角度考虑,使用UUID作为聚簇索引会很糟糕:它使得聚簇索引的插入变得完全随机,这是最坏的情况,

           是的数据没有任何聚集。向UUID主键插入行不仅花费更长的时间,而且索引占用的空间也更大。这一方面是由于主键字段更长,另一方面毫无疑问是由于页分裂和碎片导致的。

      5). 使用InnoDB时应该尽可能地按主键顺序插入数据,并且尽可能地使用单调增加的聚簇键的值插入新行。这样可以顺序地写入数据,减少随机IO,减少碎片和减少分页。

           但对于高并发工作负载,按主键顺序插入可能造成明显的争用。

 

  

mysql中每个表都有一个聚簇索引(clustered index ),除此之外的表上的每个非聚簇索引都是二级索引,又叫辅助索引(secondary indexes)。

 

索引的优点:快速定位,避免排序

mysql笔记02 创建高性能的索引

原文:http://www.cnblogs.com/Jtianlin/p/5150104.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!