理解索引最好的办法是结合示例,所以这里准备了一个索引的案例。

  假设要设计一个在线约会网站,用户信息表有很多列,包裹国家,地区,城市,性别,眼睛颜色,等等。完整必须支持上面这些特征的各种组合来搜索用户,还不行一些根据用户的最后在线时间,其他会员对用户的屏风等对用户进行排序并对结果进行限制。如何世界索引满足上面的负载需求呢?

  出人意料的是第一件需要考虑的事情是需要使用索引来排序,还是先检索数据再排序。使用索引排序会严格限制索引和查询的设计。例如,如果希望使用索引做根据其他会员对用户的评分排序,则WHERE 条件中的 age BETWEEN 18 AND 25 就无法使用索引。如果MySQL使用了某个索引进行范围查询,也就无法再使用另一个索引(或者是该索引的后续字段)进行排序了。如果这是很常见的where 条件,那么我们当然就会认为很多查询需要做排序操作。

  支持多种过滤条件

  现在需要看看那些列拥有很多不同的取值,那些列在where子句中出现的最繁琐。在有更多不同值的列上创建索引的选择性更好。一般来说这样都是对的,因为可以让MySQL更有效的过滤掉不需要的行。

  country的选择性通常不高,但是可能很多查询都会用到。sex列的选择性肯定很低,但也会在很多查询中用到。索引考虑到使用的频率还是建议在创建不同组合所以你的时候讲(sex,country) 作为前缀。

  但根据传统的经验,不是说不应该在选择性地的列上创建索引了吗?那么为什么这里需要将恋歌选择性都很低的字段作为索引的前缀列?我们的脑子坏了?

  我们的脑子当然没有坏。这么做有两个理由:低一点,如前面所述几乎所有的查询都会用到sex列。前面曾提到,几乎每一个查询都会用到sex列,设置会吧网站设计成每次都只能按照某一种姓名搜索用户。更重要的一点是,索引中加上这一列也没有花痴,即使查询中没有使用sex列也可以通过下面的诀窍绕过。

  这个诀窍就是:查询不限制性别,那么可以通过在查询条件中增加AND sex in ('f','m')。来让MySQL选择索引。这样写并不会过滤掉如何行,和没有这个条件时返回的结果相同。但是必须添加上这个条件,MySQL才能匹配索引最左前缀。这个诀窍这这类场景中非常有效,但如果有太多不同的值,就会让in() 列表太长,这样就不行了。

  这个案例显示了一个级别原则:考虑表上素有是选项。当时机索引时,不要指望现有的查询考虑需要哪些需哦因,还需要考虑对查询进行优化。如果发现某些查询需要创建新索引,但是这个索引优惠降低另一些查询的效率,那么应该想一想释放能优化原来的查询,那么应该想一想释放能优化原来的查询。应该同时优化查询和索引以找到最贱的平衡,而不是闭门造车去设计完美的索引。

  接下来,需要考虑其他常见where的组合,并需要了解哪些组合在没有合适索引的情况下就会很慢。(sex,country,age)上的索引就是一个很明显的选择,另外恒友可能还需要(sex,country,region,age)和(sex,country,region,city,age)这样的组合索引。

  这样就会要要大量的索引。如果想尽可能重用索引而不是建立大量的索引组合,可以使用前面提到的IN()来巧妙的避免同时需要(sex,country,age)和(sex,country,region,age)的索引。如果没有指定这个字段所说,就需要定义一个全部国家列表,或国家的全部地区列表,来确保前缀索引有同样的约束(组合所有的国家,地区,性别)将是一个非常庞大的条件。

  这些索引将满足大部分最常见的查询,但是如何为一些生怕的所说条件(比如说has_pictures,eye_color,hair_color和education)来设计索引呢。这些列的选择性高,使用也不频繁,可以选择忽略掉他们,让MySQL多扫描一些额外的行即可。另一个可选的地方是在age列的前面上加上这些列,在查询时使用前面提到过的in()技术来处理所说是没有指定这些场景。

  你可能已经注意到了,我们一直讲age列放在索引的最后面。age列有什么特殊的地方吗?为什么要放在索引的最后?我们总是尽可能让MySQL使用更多的索引列,因为在查询中只能使用索引的最左前缀,直到遇到第一个范围条件列。前面提到的列在WHERE 子句中都是等于条件,但是age列则多半是范围查询(例如,18-25岁之间的人)。

  当然也可以使用in来代替范围查询,例如年龄条件改为in(18,19...25),但不是所有的查询都可以转换。这里秒数的原则是,金坑能将需要做范围查询的列放在索引的最后面,以便游虎丘能使用更多的索引列。

  前面提到的可以在索引中加入更多的列,并通过in()的方式覆盖奈尔不在where子句中的列。但这种技巧也不能滥用,否则可能会带来麻烦。因为每额外添加一个in()条件,优化器需要做的组合将会以指数的形势增加,最终可能会极大的降低查询性能。

  考虑下面WHERE 子句:

  WHERE eye_color in('brown','blue','hazel')AND hair_colr in ('black','red','blonde','borwn') AND sex in ('f','m') 优化器会转成3*4*2=24种组合,执行计划需要价差where子句中所有的24种组合。对于MySQL来说,24种组合并不是很夸张,但如果组合数达到上千个则需要特别小心。老板吗的MySQL在in()组合条件过多时就会有很多问题。查询优化可能花很多时间,并消耗大量的内存。新版本的MySQL在组合数超过一定数量后就不再进行执行计划评估了,可能会导致MySQL不能很好的利用索引。

  避免多个范围条件

  假设我们有一个last_online列并希望通过下面的查询显示在过去几周上限过的用户:

  WHERE eye_color in('brown','blue','hazel')

      AND hair_colr in ('black','red','blonde','borwn')

      AND sex in ('f','m')

      AND last_online > DATE_SUB(NOW(),INTERVAL 7 DAY)

      AND age between 18 and 25

  这个查询有一个问题:他有两个范围条件 last_online 和age列,MySQL可以使用last_onlie 列索引或者age列索引,但无法同时使用它们。

  如果条件中只有last_onlie而没有age,那么我们可能考虑在索引的后面加上last_onlie列。这里考虑如果我们无法把age字段转换成一个in()列表,并且人要求对于同时有last_onlie和age这两个维度的范围查询的速度很快,那么该怎么办?答案是,很遗憾,没有一个直接的办法能够解决这个问题。但是我们能够将其中一个范围查询转换成一个简单的等值比较。为了实现这一点,我们需要事先计算好一个active列,这个字段由地市任务来维护。党用户每次登陆时,将对应值设为1,并且将过去连续7天未曾登陆的用户的值置为零。

  这个方法可以让MySQL使用(active,sex,country,age)索引。active并不是完全精确的,但是对于这个查询来说,对精度的要求没有那么高。如果需要精确的数据,可以吧last_online 列放在where子句中,但不加入到索引中。这和之前通过计算urlhash值来实现url的快速查找类似。所以这个查询无法使用任何索引,但因为这个条件的过滤性不高,即使在索引中加入了该列也没有太大的帮助。换个角度说,缺乏合适的索引对该查询影响也不明显。

  到目前位置,我们可以看到:如果用户希望同时看到活跃和不活跃的用户,可以在查询中使用in()列表。我们已经加入了很多这样的列表,但另一个可选的方案只能是位不同组合列创建单独的索引。至少需要建立如下索引(active,sex,country,age),(active,country,age),(sex,country,age) 和(country,age).这些索引对某个具体的查询来说可能都是更优化的,但是考虑到索引的维护和额外的空间占用的代价,这个可选方案就不是一个好的策略了。

  这这个案例中,优化器的特性是影响索引策略的一个很重要的因素。如果未来办吗的MySQL能够实现松松索引扫描,就能在一个索引上使用多个范围条件,那也就不需要为上面考虑这类型使用in()列表了。

  优化排序

  在这个学习案例中,最后要介绍的是排序。使用文件排序对小数据集是很快的,但如果一个查询的结果又上百万行的话会怎样?例如where子句中只有sex列,如何排序?

  对于那些选择性非常低的列,可以增加一些特殊的索引来做排序。例如可以创建(sex,rating)索引用于如下的查询:

  SELECCT <cols> FROM  profiles WHERE sex='M' ORDER BY rating limit 10;

  这个查询同时使用了order by 和limit ,如果没有索引的话,会很慢。

  即使有索引,如果yoghurt界面上需要翻页,并且翻页到比较靠后时,查询也可能非常慢。

  下面这个查询就可以通过ORDER BY 和LIMIT偏移量的组合翻页到很后面的时候。

  SELECCT <cols> FROM  profiles WHERE sex='M' ORDER BY rating limit 100000,10;

  无论如何创建索引,这种查询都是个严重的问题。因为随着偏移量的增加,MySQL需要花费大量的 时间来扫描需要丢弃的数据。反范式化、预先计算和缓存可能是解决这类查询的仅有策略。一个更好的办法是限制用户能够翻页的数量,实际上这对用户的体验不大,因为用户很少真正在乎搜索过的低10000页。

  优化这类索引的另一个比较好的策略是使用延迟关联,通过使用腹杆索引查询返回需要的主键,在根据这些主键关联原表格所需要的行。这可以减少MySQL扫描那些需要丢弃的行数。下面这个查询显示了如何高效的使用(sex,rating)索引进行排序和分页

  SELECT <cols> FROM profiles INNER JOIN (SELECT <primary key cols> FROM profiles WHERE x.sex = 'M' ORDER BY rating 10000,10) AS X using (<primary key cols>);

  

  

Mysql 索引案例学习的更多相关文章

  1. MySQL索引的学习

    MySQL索引的学习 关于使用mysql索引的好处,合理的设计并使用mysql索引能够有效地提高查询效率.对于没有索引的表,单表查询可能几十万数据就是平静,在大型网站单日可能会产生几十万甚至几百万的数 ...

  2. MySQL索引知识学习笔记

    目录 一.索引的概念 二.索引分类 三.索引用法 四 .索引架构简介 五.索引适用的情况 六.索引不适用的情况 继我的上篇博客:Oracle索引知识学习笔记,再记录一篇MySQL的索引知识学习笔记,本 ...

  3. MySQL数据库索引类型、MySQL索引的优化及MySQL索引案例

    关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车.对于没有索引的表,单表查询可能几十万数据就是瓶颈,而通常大型 ...

  4. mysql实战优化之四:mysql索引优化

    0. 使用SQL提示 用户可以使用use index.ignore index.force index等SQL提示来进行选择SQL的执行计划. 1.支持多种过滤条件 2.避免多个范围条件 应尽量避免在 ...

  5. mysql 索引B-Tree类型对索引使用的生效和失效情况详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt343 当人们谈论索引的时候,如果没有特别指明类型 ,那多半说的是 B-Tre ...

  6. 重新学习MySQL数据库5:根据MySQL索引原理进行分析与优化

    重新学习MySQL数据库5:根据MySQL索引原理进行分析与优化 一:Mysql原理与慢查询 MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能 ...

  7. SQL学习笔记之MySQL索引知识点

    0x00 概述 之前写过一篇Mysql B+树学习,简单的介绍了B+数以及MySql使用B+树的原因, 有了这些基础知识点,对MySql索引的类型以及索引使用的一些技巧,就比较容易理解了. 0x01 ...

  8. 重新学习MySQL数据库4:Mysql索引实现原理

    重新学习Mysql数据库4:Mysql索引实现原理 MySQL索引类型 (https://www.cnblogs.com/luyucheng/p/6289714.html) 一.简介 MySQL目前主 ...

  9. 10 | MySQL为什么有时候会选错索引? 学习记录

    <MySQL实战45讲>10 | MySQL为什么有时候会选错索引? 学习记录http://naotu.baidu.com/file/e7c521276650e80fe24584bc9a6 ...

随机推荐

  1. 解决mongodb ISODate相差8小时问题

    服务端使用mongoose操作mongodb,其中Schema中的日期字段定义如下: date: {type:Date, default:Date.now},//操作日期 插入到mongodb中adt ...

  2. Points

    CF#19D:http://codeforces.com/contest/19/problem/D 题意:给你一个点,add x,y表示向集合中添加一个点,remove x,y,表示删除集合中的一个点 ...

  3. JAVA之序列化A

    package SwingGui.sky.com; import java.io.*; public class GameSaverTest { public static void main(Str ...

  4. LayerDrawable 资源

    与 StateListDrawable 有点类似,LayerDrawable 也可包含一个 Drawable 数组,因此系统 将会按这些 Drawable 对象的数组顺序来绘制它们,索引最大的 Dra ...

  5. 生产环境下,不建议用早期版本的Mono........

    一个BUG修复需要4年!!!!!!!!!!!!!也是醉了....不造被微软收购后的Xamarin会不会好起来

  6. POJ3349 Snowflake Snow Snowflakes(哈希)

    题目链接. 分析: 哈希竟然能这么用.检查两片雪花是否相同不难,但如果是直接暴力,定会超时.所以要求哈希值相同时再检查. AC代码: #include <iostream> #includ ...

  7. 《Ruby语言入门教程v1.0》学习笔记-01

    <Ruby语言入门教程v1.0> 编著:张开川 邮箱:kaichuan_zhang@126.com 想要学习ruby是因为公司的自动化测试使用到了ruby语言,但是公司关于ruby只给了一 ...

  8. JQuery Mobile页面的载入方式

    1.JQM页面结构 jQuery Mobile是通过data-role属性来区分渲染界面样式的,JQM里面提供的data-role如下表: 参数 说明 page 页面容器,其内部的mobile元素将会 ...

  9. STL 常用的一些容器总结

    数据结构 描述 实现头文件 向量(vector) 连续存储的元素 <vector> 列表(list) 由节点组成的双向链表 <list> 双队列(deque) 连续存储的指向不 ...

  10. [置顶] vb报表的设计

    敲机房收费系统,最难的部分应该就是关于报表的部分了.相对于学生信息管理系统,报表是新内容,在vb中添加报表需要添加第三方控件,首先我们要下载水晶报表,下面就向大家展示一下我设计报表的步骤(我用的新版本 ...