索引的三星原则

1.索引将相关的记录放到一起,则获得一星

2.如果索引中的数据顺序和查找中的排列顺序一致则获得二星

3.如果索引中的列包含了查询中的需要的全部列则获得三星

多列索引

1.1、多个单列索引

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

  我们会在稍后的章节中单独讨论索引列的顺序问题。先来看第一个问题,为每个列创建独立的索引,从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条件的联合(union),AND条件的相交(intersection),组合前面两种情况的联合及相交。下面的查询就是使用了两个索引扫描的联合,通过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的方式往往会更好。

如果在Explain语句中看到索引合并,应该好好检查一下查询和表的结构。也可以通过参数optimizer_switch来关闭索引合并功能。也可以使用IGNORE_INDEX提示让优化器忽略掉某些索引。

==========================================================================================

为了提高搜索效率,我们需要考虑运用多列mysql数据库索引。如果为firstname、lastname和age这三个列创建一个多列索引,MySQL只需一次检索就能够找出正确的结果!下面是创建这个复合索引的SQL命令:

ALTER TABLE people ADD INDEX fname_lname_age (firstname,lastname,age); 

由于索引文件以B-树格式保存,MySQL能够立即转到合适的firstname,然后再转到合适的lastname,最后转到合适的age。在没有扫描数据文件任何一个记录的情况下,MySQL就正确地找出了搜索的目标记录!

那么,如果在firstname、lastname、age这三个列上分别创建单列索引,效果是否和创建一个firstname、lastname、age的多列MySQL数据库索引一样呢?答案是否定的,两者完全不同。当我们执行查询的时候,MySQL只能使用一个索引。如果你有三个单列的MySQL数据库索引,MySQL会试图选择一个限制最严格的索引。

但是,即使是限制最严格的单列索引,它的限制能力也肯定远远低于firstname、lastname、age这三个列上的多列索引。

索引是快速搜索的关键。MySQL索引的建立对于MySQL的高效运行是很重要的。

1.2、复合索引

联合索引又叫复合索引。对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key index (a,b,c)。 可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效。两个或更多个列上的索引被称作复合索引。

见《mysql索引之四:复合索引之最左前缀原理,索引选择性,索引优化策略之前缀索引

 

最新文章

  1. Spill data to tempdb
  2. ERROR ITMS-90682: Invalid Bundle - The asset catalog at 'Payload/XXXXX/Assets.car' can't contain 16-bit or P3 assets if the app supports iOS 9.3 or earlier.
  3. 【Java每日一题】201612015
  4. SQL SERVER数据库的表中修改字段的数据类型后,不能保存
  5. canvas实践小实例一 —— 画板工具
  6. debug 使用lldb
  7. linux mv命令
  8. EnCase v.s. FTK - find out Chinese characters writing in different direction
  9. CentOS7 安装 scala 2.11.1
  10. 认识solr结构,了解核心的文件目录
  11. js大小写转换
  12. JavaSE之认识java
  13. .net c#将数据库数据对象转换为实体值对象
  14. 【HNOI2016】大数
  15. Qt 立体水晶按键实现
  16. 多线程下载文件,ftp文件服务器
  17. 关于微信分享到朋友圈(Thinkphp-tp3.2框架下实现)
  18. OAuth2.0 Owin 授权问题
  19. UESTC--1267
  20. python是如何进行内存管理的?

热门文章

  1. Singleton单例类模式
  2. LeetCode OJ:Merge Intervals(合并区间)
  3. 网络编程的基本概念,TCP/IP协议简介
  4. 使用Apache的ab工具进行网站性能测试
  5. 第6课:datetime模块、操作数据库、__name__、redis、mock接口
  6. html 实体和htmlspecialchars()
  7. Caused by: java.lang.AbstractMethodError: org.hibernate.validator.internal.engine.ConfigurationImpl
  8. Photon——Feature Overview 功能概述
  9. Qt QScrollArea and layout in code
  10. javascript 小代码