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";

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

实例:现在我们想查出满足以下条件的用户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子句中使用最频繁的一列放在最左边。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容

  • pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类: pyspark.sql...
    mpro阅读 9,451评论 0 13
  • MYSQL 基础知识 1 MySQL数据库概要 2 简单MySQL环境 3 数据的存储和获取 4 MySQL基本操...
    Kingtester阅读 7,811评论 5 116
  • 观其大纲 page 01 基础知识 1 MySQL数据库概要 2 简单MySQL环境 3 数据的存储和获取 4 M...
    周少言阅读 3,157评论 0 33
  • 昨晚跟牛娃做了中考前的最后一次长谈,因为她这几天状态不佳。前几天,体育中考结束了,但是她自己发现没有尽全力...
    寒香的蕊阅读 302评论 0 0
  • 1 从巨大的虚空中醒来已是七点四十九分,她调的七点十五的闹钟没有动静,可能是她迷迷糊糊中按掉了,但是已经没有这个动...
    子瑜曰阅读 157评论 0 0