高性能MySQL--索引 笔记




索引概述

  • 索引即key

  • 在存储引擎层实现,不同引擎工作方式不同

  • 索引优化--最好的查询优化手段,可提效几个数量级

  • 两步查找数据:

磁盘查找索引节点(页),将其调入内存;
内存内业内查找数据

一. 索引类型

B-Tree
Hash
R-Tree空间数据索引
全文索引

1. B-tree索引

  • 支持引擎:InnoDB,MyISAM,Memory
  • 所有叶子值顺序存储,且到root高度一样
  • InnoDB,MyISAM B-tree工作方式异同:

InnoDB按原格式存储数据,MYISAM用前缀压缩技术
InnoDB用主键key索引数据行,MyISAM用物理位置索引数据行

  • 加速:存储引擎从root节点扫描,代替全表扫描
  • 叶节点指针-->被索引数据(data record)

1)B-Tree适用场景

1 全值匹配查询

所有列都匹配

2 最左前缀匹配

组合索引第一列

3 列前缀匹配

某列值开头

4 范围值匹配
5 一列精确一列范围匹配
6 覆盖索引查询

只访问索引即可取data,无须访问数据行

7 Order by排序

2) B-Tree不适用场景

  • 非最左列
  • 跳列

A C

  • 某列进行范围查询,其右边所有列无法再用索引

2. Hash索引

  • 访问哈希索引的数据很快
哈希表结构

f(key)=slot

1) 支持引擎

Memory,NDB集群

2) 适用场景

索引全列匹配

3) 不适用场景

  • 不能从索引直接取data

哈希索引=哈希值+行指针,不存储字段值

  • 不能用于排序

哈希值有序,但索引数据无序

  • 不支持部分索引列匹配
  • 不支持范围查询

仅支持等值匹配 =,<=>,IN()

<=> NULL安全等于----操作数可为NULL

4) InnoDB自适应Hash索引

某些索引值被引用很频繁,InnoDB自动在内存B-Tree索引上创建一个Hash索引
用户无法控制和配置,但可关闭

5) 自定义hash索引

存储引擎不支持时,模拟创建hash

如何创建?

B-tree上创建伪hash索引

  • 仍在Btree上查找,但用hash索引值代替原Key(伪hash)
  • 须在where指定hash函数,不要用MD5(),SHA1()
select id from url
where url="www.mysql.com"
and
url_crc=CRC32("www.mysql.com")

其中urc_crc列为索引列

6) 处理Hash冲突

使用hash索引查询时,须在where指定常量

select id from url
where 
url_crc=CRC32("www.mysql.com")
and
url="www.mysql.com"
select word,crc from words
where 
crc=CRC32("gnu")
and
word="gnu"
@birthday problem

In probability theory, the birthday problem or birthday paradox concerns the
probability that,
in a set of {\displaystyle n} n randomly chosen people, some pair of them will have the same birthday.
By the pigeonhole principle, the probability reaches 100% when the number of people reaches 367 (since there are only 366 possible birthdays, including February 29). However, 99.9% probability is reached with just 70 people, and 50% probability with 23 people.

3. 空间数据索引 R-Tree

支持引擎:MyISAM
用作地理数据存储,如美团,滴滴定位服务
任意维度组合查询
须使用GIS函数维护数据,MySQL做的不好

4. 全文索引

  • 查找文本关键字,非比较索引键值
  • 类似搜索引擎
  • 相同列创建全文索引和B-Tree索引,不冲突

5. 其他索引

第三方引擎TokuDB

二. 索引好处

1. 好处

1) 减少扫描数据量

2) 避免排序和临时表

3) 随机IO转为顺序IO

2. 索引三星评价

评价索引是否适合某查询
第一星

索引将相关data行放到一起

第二星

索引的data行按查询所需顺序排序

第三星

索引含 查询全部列

三 .高性能索引策略

1. 独立的列

独立

索引列非表达式子式,或函数参数

两个错误:

1)索引列为表达式
select id from actor
where id + 1 = 5
2)
select ...
where 
TO_DAYS(Current_DATE) - TO_DAYS(date_col) <= 10;

2. 前缀索引和索引选择性

1) 前缀索引

很长字符串,可索引开始的部分字符串

适用场景

BLOB,TEXT,很长的VARCHAR列

2) 优缺点

优点

节约索引空间

缺点

无法使用之做order by,Group by
无法使用做覆盖索引

3) 索引选择性

=不重复索引值/数据表记录总数
  • 不重复索引值<-->基数<-->cardinality
  • 记录总数<-->#T
  • 取值范围 [1/#T ,1]
  • 越高越好

选择性越高,过滤掉的行越多

4) 如何找到 前缀索引长度

思想

足够长(接近完整列),又不能太长(节约空间)

方法1 试验法

先算完整列频次,然后一个一个前缀试验

计算完整列频次
试验前3前缀
方法2 计算完整列选择性

使前缀选择性接近完整列选择性


完整列选择性

前缀长度为7接近完整列

5) 如何创建前缀索引

ALTER TABLE sakila
ADD KEY(city(7));

KEY(city(7))

3. 多列索引

1) 常见错误

每个列都创建单独索引,导致索引合并

create table t(
c1 int,
c2 int,
KEY(c1),
KEY(c2)
);

2) 索引合并表示索引建的不好,待优化

  • 多个索引相交(AND)不如组合索引好
  • 多个索引联合(OR)耗费CPU和内存资源
  • 优化器不计算(耗费CPU和内存资源)到查询成本中

4. 选择合适的索引列顺序

仅适用于BTree索引(按顺序存储数据)
Btree索引按从左到右顺序,依次扫描
索引可按升、降序扫描,满足Order by,Group by,Distinct

如何选择合适的索引列顺序

经验法则

无order by和Group by时,选择性最高的列放在前面

select * from payment 
where staff_id=2 and customer_id=584;

key(staff_id,customer_id)还是key(customer_id,staff_id)?

5. 聚簇索引(clustered index)

InnoDB支持,MyISAM为非聚簇

聚簇

数据行,键值存储在一起
一个表只能有一个聚簇索引

聚簇特点

  • InnoDB通过主键聚集数据

主键未定义,用唯一非空索引聚集
无唯一非空索引,则隐式定义主键

  • 只聚集同一页面记录

聚簇优点

  • 相关数据保存在一起,如电子邮件(用户ID和全部邮件)
  • 数据访问更快(索引和数据都在BTree中)
  • 覆盖索引查询直接取页节点键值

聚簇缺点

数据全放内存时无优势(访问顺序不再重要)
插入速度依赖于插入顺序

InnoDB按主键顺序插入最快(否则插入后用optimize table优化表)

更新聚簇索引列代价很高

强制将每个更新行移动到新位置

页分裂问题

插入新行或,主键更新导致需移动行时

全表扫描慢
二级索引需两次索引查找

二级索引(secondary index,辅助索引)

叶节点保存行主键值,非指向data行的物理记录的指针


二级索引查找行步骤
  1. 叶子节点找到主键值
  2. 在聚簇索引找数据行

1 . InnoDB和MyISAM数据分布对比

InnoDB数据分布

InnoDB就是表,不用再像Myisam用单独列存储
聚簇索引叶子节点包含:
主键值
事物ID
回滚指针(用于事物和MVCC)
其他剩余列

聚簇和非聚簇表对比

2. InnoDB表按主键顺序插入行

无数据聚集,使用AUTO INCREMENT作为主键--保证按顺序写入
避免使用UUID(universal unique identifier)聚簇索引--导致插入变得随机

6. 覆盖索引

索引直接包含所需查询数据行,不需要回记录表(数据表)
只能用BTree做覆盖索引
支持InnoDB,myisam
Explain显示 Extra:Using index

覆盖索引优点

  • 索引条目小于数据行,减少了数据访问量
  • 范围查询IO少(索引列值顺序存储)
  • 对InnoDB表(聚簇索引)特别有用

二级主键能覆盖查询可避免对主键索引的二次查询

MyISAM覆盖索引可能会导致系统问题

MyISAM引擎内存只缓存索引,数据由OS缓存

ICP索引条件推送(index condition pushdown)

MySQL5.6开始支持
条件过滤推到存储引擎层完成,减少IO访问


7. 用索引扫描做排序

MySQL生成有序结果的两种方式

  • 排序
  • 按顺序扫描索引

Exlain Type:Using index

为何索引扫描比全表扫描慢?

如果索引不能覆盖查询全部列,则每扫一条索引记录必须回表(随机IO)

同一索引,既满足排序,又满足查找是最好的

何时能用索引进行排序?

  • 索引列序和order by顺序一致时
  • 且所有列排序方向一样

不能使用索引进行排序的场景

  • order by出现不同排序方向
  • order by引用非索引列
  • where和order by中的列无法组合为最左前缀
  • where第一列是范围条件
  • where出现IN(多个相等条件视为范围)

8. 压缩(前缀压缩)索引

MyISAM使用
减少索引大小(1/10磁盘空间)让更多索引进入内存
默认只压缩字符串,也可设置整数
只能从头开始扫描,无法二分
随机扫描导致适用于IO密集型(OLTP),不适用CPU密集型(OLAP)?

index1:perform
index2:performance-->7,ance

9. 冗余和重复索引

应删除重复索引

1) 重复索引

相同列创建多个索引



三个重复索引--unique,primary限制均通过索引实现

2) 冗余索引

应该删除冗余索引

两种冗余

已有key(A,B),再建key(A)
ID为主键,扩展索引为(A,ID)

建议

尽量扩展现有索引,而不是创建新索引,那样会导致冗余索引

10.删除未使用的索引

percona Toolkit--
pt-index-usage工具

11. 索引和锁

InnoDB存储引擎层完成条件过滤时(ICP--MySQL 5.6及以后),索引可减少访问行数,从而减少加锁数量
否则全表扫描并锁住所有行

覆盖索引失效:

  • InnoDB二级索引上用共享(读)锁,访问主键索引需要排他(写)锁
  • select for update比lock in share mode或非锁定查询慢


四. 索引和表维护

维护表三目的

找到并修复损坏的表
维护准确的索引统计信息
减少碎片

1. 找到并修复表

1) MyISAM表

check table--检查表
repair table--修复损坏的表

2) InnoDB表使用no-op ALTER

Alter TABLE innodb_tb ENGINE=INNODB;

2. 维护索引统计信息

优化器有时用索引统计信息估算扫描行数

ANALYZE TABLE更新统计信息避免错误

memory引擎不存储统计信息
MyISAM引擎存储统计信息在磁盘

Show Index from table查看索引基数(cardinality,索引列不同取值个数)

触发索引统计信息更新的三种情形

SHOW TABLE STATUS
SHOW INDEX
打开某些INFORMATION_SCHEMA表

3.减少索引和数据碎片

1)BTree索引会碎片化,降低查询效率

BTree随机访问是必须的,因为从root节点随机磁盘访问才能定位到叶子节点

2)三种数据碎片

行碎片

数据行存储在多个地方多个碎片中

行间碎片

逻辑上顺序的页或行,在磁盘上非顺序存储

剩余空间碎片

数据页中有大量不用的空余空间

MyISAM三种碎片都有,InnoDB无小碎片

3)如何消除碎片?

  • OPTIMIZE TABLE
  • ALTER TABLE tb ENGINE=<engine>;
  • 删除所有索引-->重建表 -->重建索引

五. 总结

索引三原则

1.单行访问很慢

最好一个数据块读取多行

2. 按顺序访问范围行很快

  • 顺序IO无需多次磁盘寻道,比随机IO快很多
  • 服务器按顺序读取数据,则不需要额外排序

3. 索引覆盖查询很快

避免了大量单行访问

2017-4-10 sz

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

推荐阅读更多精彩内容