MySQL索引的使用

一、索引对查询效率的提升

这是一个拥有300万行数据的表格:


image.png

表的大概结构:


image.png

查询id:


image.png

用了很短的执行时间,如果查询title字段:


image.png

用了4.6秒的时间,查询效率比较低,原因是id字段是主键,有主键索引,而title字段没有索引,所以查询效率比较低。

要解决这个问题,可以对title字段建立索引。
create index idx_item_title on tb_item(title);

创建成功:


image.png

大概花费了一分钟的时间。

再次查询:


image.png

查询效率大大提升了。

二、避免索引失效

创建一张新的表:

image.png

对这个表的三个字段创建联合索引:
create index idx_seller_name_sta_addr on tb_seller(name,status,address);

1.全值匹配

对索引中所有列都指定具体值。


image.png

三个查询的值都为联合索引中的字段。

这时候用explain来查看它的执行计划:


image.png

走了索引。

2.最左前缀法则

创建索引的时候的语句是:
create index idx_seller_name_sta_addr on tb_seller(name,status,address);

这个联合索引对name、status、address三个字段建立了索引,按照最左前缀法则,查询的时候,如果想使用这个索引,查询条件中要包含name字段,并且不能够跳过status字段,也就是如果想使用这个索引查询name和address,那么在查询条件中,也必须包含status字段,不能跳过它。

  • 只查询name字段:


    image.png

    走了索引。

  • 查询name和status字段:


    image.png

    也走了索引。

  • 查询name、status和address字段:


    image.png

    可以看到走了索引。

  • 只查询status和address字段:


    image.png

    没有走索引。

  • 查询address字段:


    image.png

    没有走索引。

  • 如果查询条件中包含name、status和address字段,但是打乱顺序:


    image.png

    可以看到也走了索引。

所以只要查询条件中包含索引的最左字段(name),不跳过字段,那么这个索引就没有失效,可以使用。

  • 如果查询的是name字段和address字段,也就是中间跳过了status字段:


    image.png

    可以看到还是走了索引,但是索引的长度是403,和只查询name字段时的索引长度一样,所以可以推断出,name字段走了索引,而address字段没有走索引。

3.范围查询右边的列,不能使用索引 。

通过一组对比:


image.png

第二次查询的status字段是范围查找,可以看到两次查找索引的长度发生了变化,也就是第一个和第二个字段使用了索引,范围查询右边的列的索引失效了。

4.在索引列上进行运算操作, 索引将失效

image.png

可以看到,进行的是全表扫描,索引失效了。

5.字符串不加单引号,造成索引失效

如果是字段是varchar类型,不加单引号也可以查询出来:


image.png

加不加单引号索引长度发生了变化,没加单引号的时候,只有name字段走了索引,因为数据库检测到status是varchar类型,会自动进行隐式类型转换,这时候索引就失效了。

6.尽量使用覆盖索引,避免select *

覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。

也就是说,如果要查询的字段是name,status和address,(select name,status,address from ....)这时候就尽量不使用select * from

image.png

可以看到如果是select * from也使用了索引,但是extra给出的信息不同,在select * from中,using index condition是指:查找使用了索引,但是需要回表查询数据,所以select * from 相对于select name,status,address from ....查询效率还是慢了的。

  • using index :使用覆盖索引的时候就会出现
  • using where:在查找使用索引的情况下,需要回表去查询所需的数据
  • using index condition:查找使用了索引,但是需要回表查询数据
  • using index ; using where:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据


    image.png

    如果查询的字段有不包含在联合索引中的,需要回表查询:


    image.png

7.用or分割开的条件

如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
索引失效,走的是全表扫描:


image.png

如果换成and:


image.png

8.以%开头的Like模糊查询,索引失效。

以%开头,索引失效:


image.png

要解决这个问题可以使用覆盖索引(sellerid有索引):


image.png

password没有索引:
image.png

9.如果MySQL评估使用索引比全表更慢,则不使用索引。

对address字段创建单列索引:


image.png

这时候查询,查询北京市没有走索引,而查询西安市走了索引:


image.png

查看一下表:
image.png

在表中,共有12条数据,11条都包含了北京市,查询的又是select * from,需要回表,所以走索引还不如全表扫描快,所以索引就失效了。

10.is NULL , is NOT NULL 有时索引失效

image.png

在表中,address字段所有的行都是非空的,所以is null的情况没有或基本没有,这时候就会走索引。

而每个字段都是is not null的,所以就不走索引了。
同理(name字段有索引):


image.png

11.in 走索引, not in 索引失效。

image.png

12.单列索引和复合索引

尽量使用复合索引,而少使用单列索引 。

create index idx_name_sta_address on tb_seller(name, status, address);
创建一个这样的复合索引相当于创建了三个索引:
name
name + status
name + status + address

如果创建单列索引:
create index idx_seller_name on tb_seller(name);
create index idx_seller_status on tb_seller(status);
create index idx_seller_address on tb_seller(address);
如果数据库中只有这三个单列索引,那么对name、status、address字段进行联合查询的时候,数据库只会选这三个单列索引中的一个最优索引(辨识度最高的索引),不会使用全部索引。
使用复合索引:


image.png

使用三个单列索引,只是用了一个索引:


image.png

image.png

三、查看索引的使用情况

show status like 'Handler_read%';
show global status like 'Handler_read%';

当前会话的索引使用情况:


image.png

全局的索引使用情况:


image.png

参数含义:
  • Handler_read_first:索引中第一条被读的次数。如果较高,表示服务器正执行大量全索引扫描(这个值越低越好)。
  • Handler_read_key:如果索引正在工作,这个值代表一个行被索引值读的次数,如果值越低,表示索引得到的性能改善不高,因为索引不经常使用(这个值越高越好)。
  • Handler_read_next :按照键顺序读下一行的请求数。如果你用范围约束或如果执行索引扫描来查询索引列,该值增加。
  • Handler_read_prev:按照键顺序读前一行的请求数。该读方法主要用于优化ORDER BY ... DESC。
  • Handler_read_rnd :根据固定位置读一行的请求数。如果你正执行大量查询并需要对结果进行排序该值较高。你可能使用了大量需要MySQL扫描整个表的查询或你的连接没有正确使用键。这个值较高,意味着运行效率低,应该建立索引来补救。
  • Handler_read_rnd_next:在数据文件中读下一行的请求数。如果你正进行大量的表扫描,该值较高。通常说明你的表索引不正确或写入的查询没有利用索引。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342