zoukankan      html  css  js  c++  java
  • 索引优化

    唯一索引

    主键就是唯一索引,但是唯一索引不一定是主键,唯一索引可以为空,但是空值只能有一个,主键不能为空。
    普通唯一索引:单个字段上建立唯一索引,需要此字段所在的列上不能有重复的值,属于二级索引。
    复合唯一索引:多个字段上联合建立唯一索引,属于二级索引。

    聚集索引

    表数据按照索引的顺序来存储的。对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页。

    在一张表上只能创建一个聚集索引,因为真实数据的物理顺序只可能是一种。如果一张表没有聚集索引,那么它被称为“堆集”(Heap)。这样的表中的数据行没有特定的顺序,所有的新行将被添加到表的末尾位置。

    非聚集索引

    表数据存储顺序与索引顺序无关。对于非聚集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,该层紧邻数据页,其行数量与数据表行数据量一致。 

    建索引的几大原则

    1. 最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

    2. =和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。

    3. 尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录。

    4. 索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);

    5. 尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。

    6. 查询只能使用索引的最左前缀,直到遇到第一个范围条件列。尽可能将需要做范围查询的列放到索引的后面,以便优化器能使用尽可能多的索引列。

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

    案例

    1 优化排序

    使用文件排序对小数据集是很快的,但如果一个查询匹配的结果有上百万行的话会怎样?例如如果WHERE子句只有sex列,如何排序?
    对于那些选择性非常低的列,可以增加一些特殊的索引来做排序。例如,可以创建(sex, rating)索引用于下面的查询:

    SELECT <cols> FROM profiles WHERE sex='M' ORDER BY rating LIMIT 10;

    这个查询同时使用了ORDER BY和LIMIT,如果没有索引的话会很慢。
    即使有索引,如果用户界面上需要翻页,并且翻页到比较靠后时查询也可能非常慢。下面这个查询就通过ORDER BY和LIMIT偏移量的组合翻页到很后面的时候:

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

    无论如何创建索引,这种查询都是个严重的问题。因为随着偏移量的增加,MySQL需要花费大量的时间来扫描需要丢弃的数据。优化这类索引的另一个比较好的策略是使用延迟关联,通过使用覆盖索引查询返回需要的主键,再根据这些主键关联原表获得需要的行。这可以减少MySQL扫描那些需要丢弃的行数。下面这个查询显示了如何高效地使用(sex,rating)索引进行排序和分页:

    SELECT <cols> FROM profiles INNER JOIN (
    SELECT <primary key cols> FROM profiles 
    where x.sex='M' ORDER BY rating LIMIT 100000,10
    )AS x USING(<primary key cols>);

    2. 以%开头的LIKE查询不能够利用B-tree索引

    explain select * from actor where last_name like '%NI%'

    解决办法

    先扫描索引 last_name获取满足条件的%NI%的主键actor_id列表,之后根据主键回表去检索记录,这样访问避开了全表扫描actor表产生的大量IO请求。

    explain select * from (select actor_id from actor where last_name like '%NI%') a,actor b where a.actor_id = b.actor_id; 

    慢查询优化基本步骤

    0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE
    1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
    2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
    3.order by limit 形式的sql语句让排序的表优先查
    4.了解业务方使用场景
    5.加索引时参照建索引的几大原则
    6.观察结果,不符合预期继续从0分析

    查询优化神器 - explain命令

    关于explain命令相信大家并不陌生,具体用法和字段含义可以参考官网explain-output,这里需要强调rows是核心指标,绝大部分rows小的语句执行一定很快(有例外,下面会讲到)。所以优化语句基本上都是在优化rows。

     参考资料

    索引的一些总结:http://www.cnblogs.com/rush/archive/2012/04/22/2465683.html

    MySQL索引原理及慢查询优化:https://tech.meituan.com/mysql-index.html

    数据库-索引(概念,优缺点,分类):http://blog.csdn.net/zdplife/article/details/48033919

  • 相关阅读:
    无法重用Linq2Entity Query
    The Joel Test
    MSBuilder directly instead of default VSComplie with keyborad shotcut 原创
    客户端缓存(Client Cache)
    关于代码重构和UT的一些想法,求砖头
    ExtJS2.0实用简明教程 应用ExtJS
    Perl information,doc,module document and FAQ.
    使用 ConTest 进行多线程单元测试 为什么并行测试很困难以及如何使用 ConTest 辅助测试
    史上最简单的Hibernate入门简介
    汽车常识全面介绍 传动系统
  • 原文地址:https://www.cnblogs.com/junzi2099/p/8340303.html
Copyright © 2011-2022 走看看