zoukankan      html  css  js  c++  java
  • mysql组合索引与字段顺序

    很多时候,我们在mysql中创建了索引,但是某些查询还是很慢,根本就没有使用到索引!
    一般来说,可能是某些字段没有创建索引,或者是组合索引中字段的顺序与查询语句中字段的顺序不符。

    看下面的例子:
    假设有一张订单表(orders),包含order_id和product_id二个字段。
    一共有31条数据。符合下面语句的数据有5条。

    执行下面的sql语句:
    select product_id 
    from orders
    where order_id in (123, 312, 223, 132, 224);

    这条语句要mysql去根据order_id进行搜索,然后返回匹配记录中的product_id。

    所以组合索引应该按照以下的顺序创建:
    create index orderid_productid on orders(order_id, product_id)
    mysql> explain select product_id from orders where order_id in (123, 312, 223, 132, 224) G
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: orders
             type: range
    possible_keys: orderid_productid
              key: orderid_productid
          key_len: 5
              ref: NULL
             rows: 5
            Extra: Using where; Using index
    1 row in set (0.00 sec)

    可以看到,这个组合索引被用到了,扫描的范围也很小,只有5行。

    如果把组合索引的顺序换成product_id, order_id的话,
    mysql就会去索引中搜索 *123 *312 *223 *132 *224,必然会有些慢了。
    mysql> create index orderid_productid on orders(product_id, order_id);                                                       
    Query OK, 31 rows affected (0.01 sec)
    Records: 31  Duplicates: 0  Warnings: 0

    mysql> explain select product_id from orders where order_id in (123, 312, 223, 132, 224) G

    *************************** 1. row ***************************

               id: 1
      select_type: SIMPLE
            table: orders
             type: index
    possible_keys: NULL
              key: orderid_productid
          key_len: 10
              ref: NULL
             rows: 31
            Extra: Using where; Using index
    1 row in set (0.00 sec)

    这次索引搜索的性能显然不能和上次相比了。

    rows:31,我的表中一共就31条数据。

    索引被使用部分的长度:key_len:10,比上一次的key_len:5多了一倍。

    不知道是这样在索引里面查找速度快,还是直接去全表扫描更快呢?
    mysql> alter table orders add modify_a char(255) default 'aaa';
    Query OK, 31 rows affected (0.01 sec)
    Records: 31  Duplicates: 0  Warnings: 0

    mysql> 
    mysql> 
    mysql> explain select modify_a from orders where order_id in (123, 312, 223, 132, 224) G          
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: orders
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 31
            Extra: Using where
    1 row in set (0.00 sec)

    这样就不会用到索引了。 刚才是因为select的product_id与where中的order_id都在索引里面的。

    为什么要创建组合索引呢?这么简单的情况直接创建一个order_id的索引不就行了吗?
    如果只有一个order_id索引,没什么问题,会用到这个索引,然后mysql要去磁盘上的表里面取到product_id。

    如果有组合索引的话,mysql可以完全从索引中取到product_id,速度自然会快。

    再多说几句组合索引的最左优先原则:
    组合索引的第一个字段必须出现在查询组句中,这个索引才会被用到。
    如果有一个组合索引(col_a,col_b,col_c)

    下面的情况都会用到这个索引:
    col_a = "some value";
    col_a = "some value" and col_b = "some value";
    col_a = "some value" and col_b = "some value" and col_c = "some value";
    col_b = "some value" and col_a = "some value" and col_c = "some value";

    对于最后一条语句,mysql会自动优化成第三条的样子~~。

    下面的情况就不会用到索引:
    col_b = "aaaaaa";
    col_b = "aaaa" and col_c = "cccccc";


    下列转自:http://hi.baidu.com/liuzhiqun/blog/item/4957bcb1aed1b5590823023c.html

    通过实例理解单列索引、多列索引以及最左前缀原则

    实例:现在我们想查出满足以下条件的用户id:
    mysql>SELECT `uid` FROM people WHERE lname`='Liu'  AND `fname`='Zhiqun' AND `age`=26
    因为我们不想扫描整表,故考虑用索引。

    单列索引:
    ALTER TABLE people ADD INDEX lname (lname);
    将lname列建索引,这样就把范围限制在lname='Liu'的结果集1上,之后扫描结果集1,产生满足fname='Zhiqun'的结果集2,再扫描结果集2,找到 age=26的结果集3,即最终结果。

    由 于建立了lname列的索引,与执行表的完全扫描相比,效率提高了很多,但我们要求扫描的记录数量仍旧远远超过了实际所需 要的。虽然我们可以删除lname列上的索引,再创建fname或者age 列的索引,但是,不论在哪个列上创建索引搜索效率仍旧相似。

    2.多列索引:
    ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);
    为了提高搜索效率,我们需要考虑运用多列索引,由于索引文件以B-Tree格式保存,所以我们不用扫描任何记录,即可得到最终结果。

    注:在mysql中执行查询时,只能使用一个索引,如果我们在lname,fname,age上分别建索引,执行查询时,只能使用一个索引,mysql会选择一个最严格(获得结果集记录数最少)的索引。

    3.最左前缀:顾名思义,就是最左优先,上例中我们创建了lname_fname_age多列索引,相当于创建了(lname)单列索引,(lname,fname)组合索引以及(lname,fname,age)组合索引。

    注:在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。

  • 相关阅读:
    hbase源码分析.客户端.预备知识.ExecutorService
    Dijkstra for MapReduce (1)
    [leetcode]Palindrome.Partitioning
    CSS3兼容性写法
    C#延时
    python学习日记180823
    2012年11月11日 本周随笔
    2012年11月20日 上周回顾 && 疯狂的程序员书摘
    2012年11月27日 上周回顾
    hadoop loadBalance源码分析
  • 原文地址:https://www.cnblogs.com/gide/p/4829704.html
Copyright © 2011-2022 走看看