mysql 高级优化之 理解索引使用

45
www.2345.co m MySQL 高 高高高高—— 高高高高高高 高高高高高高高高高高高高高高高高 高高高高高高高 高高高 2014-01- 14

Upload: nigel889

Post on 30-Jun-2015

894 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: mysql 高级优化之 理解索引使用

www.2345.com

MySQL 高级优化之—— 理解索引使用

上海二三四五网络科技股份有限公司

互联网研发中心

王德玖

2014-01-14

Page 2: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品议程

• Mysql 信息查看• 联合索引,最左索引,覆盖索引• 介绍松散索引及紧凑索引• 优化文件排序• 问答

2

Page 3: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品实例数据库安装

• 本 ppt 后半部分使用 airport 数据库为事例;• 下载地址:http://www.transtats.bts.gov/DL_SelectFields.asp? Table_ID=236&DB_Short_Name=On-Time安装事例数据库:[root@locahost]# unzip 441848468_T_ONTIME[root@locahost]# sed -i s/,$/$/g 441848468_T_ONTIME.csvmysql> load data infile "/opt/shell/441848468_T_ONTIME.csv" into table ontime_2012 FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"';• 内网 ip : 172.16.0.230 已经安装此测试库

3

Page 4: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品索引信息:

• root@localhost: dianying_2345 >show index from dy_data_new\G• *************************** 1. row ***************************• Table: dy_data_new• Non_unique: 0• Key_name: PRIMARY• Seq_in_index: 1• Column_name: id• Collation: A• Cardinality: 90715• Sub_part: NULL• Packed: NULL• Null: • Index_type: BTREE• Comment: • *************************** 2. row ***************************• Table: dy_data_new• Non_unique: 1• Key_name: search• Seq_in_index: 3• Column_name: region• Collation: A• Cardinality: 18143• Sub_part: NULL• Packed: NULL• Null: • Index_type: BTREE• Comment:

表名索引不能包括重复值为 0 ,如果可以,则为 1索引名索引中的列序列号,从 1 开始列名称列以什么方式存储在索引中索引中唯一值的数目的估计值列如果是前缀索引,则为被编入索引的字符的数目。如果整列被编入索引,则为 NULL 。指关键字如何被压缩,没有被压缩,为 NULL列含有 NULL ,为 YES ,如果没有,则该列为 NO使用的索引方法: BTREE, FULLTEXT, HASH, RTREE评注

Page 5: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品创建实例表:

CREATE TABLE City (ID int(11) NOT NULL AUTO_INCREMENT,Name char(35) NOT NULL DEFAULT '',CountryCode char(3) NOT NULL DEFAULT '',District char(20) NOT NULL DEFAULT '',Population int(11) NOT NULL DEFAULT '0',PRIMARY KEY (ID),KEY CountryCode (CountryCode)

) Engine=InnoDB;

Page 6: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品索引实例

• 使用一个索引的情况(这也是最好的情况)

mysql> explain select * from City where ID = 1;+-------+-------+-------------------+------------+-----------+----------+-------+-------+| table | type | possible_keys | key | key_len | ref | rows | Extra |+-------+-------+-------------------+-------------+-----------+---------+-------+-------+| City | const | PRIMARY | PRIMARY | 4 | const | 1 | |+-------+-------+-------------------+-------------+-----------+---------+-------+-------+

mysql> explain select * from City where CountryCode = 'USA';+-------+------+------------------+-----------------+----------+--------+---------+-----------------+| table | type | possible_keys | key | key_len| ref | rows | Extra |+-------+------+------------------+-----------------+----------+--------+----------+-----------------+| City | ref | CountryCode | CountryCode | 3 | const | 274 | Using where |+-------+------+------------------+------------------+---------+---------+---------+-----------------+

Page 7: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品联合索引

• 最左联合索引mysql> alter table City add key

comb(CountryCode, District, Population), drop key CounryCode;

Page 8: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品联合索引实例一

• 最左联合索引

mysql> explain select * from City where CountryCode = 'USA'\G********************** 1. row ****************** table: City type: refpossible_keys: comb key: comb key_len: 3 ref: const rows: 273

使用了 comb 的最左一列索引

Page 9: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品联合索引实例二

Key_len = 被使用到的索引总大小 ( 字符长度 b)

Index: comb(CountryCode, District, Population)

列 :CountryCode char(3)District char(20) Population int(11)

Explain:key: combkey_len: 3

3 char(3) comb 的第一列 CountyCode char(3) 被使用

Page 10: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品联合索引实例三

• 最左两列索引被使用

mysql> explain select * from City where CountryCode = 'USA' and District = 'California'\G********************** 1. row ****************** table: City type: refpossible_keys: comb key: comb key_len: 23 ref: const,const rows: 68

索引 `Comb` 最左两列索引被使用CountryCode = 3 chars District = 20 chars Total = 23

Page 11: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品联合索引实例四

• 三列索引同事被使用

mysql> explain select * from City where CountryCode = 'USA' and District = 'California’and population > 10000\G

********************** 1. row ****************** table: City type: rangepossible_keys: comb key: comb key_len: 27 ref: NULL rows: 68

这里使用到了 comb 索引的所有列:CountryCode = 3 chars/bytes District = 20 chars/bytes Population = 4 bytes (INT) Total = 27

Page 12: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品联合索引实例五

• 无法使用联合索引的情况——没有最左部分

mysql> explain select * from City where District = 'California' and population > 10000\G********************** 1. row ******************

table: City type: ALL

possible_keys: NULL key: NULL

key_len: NULL ref: NULL rows: 3868

CountryCode 列没有出现在 where 子句里,所以无法使用到 comb 这个联合索引

Page 13: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品覆盖索引实例:一

• 覆盖索引: 索引里包含查询所使用的列select name from City where CountryCode = 'USA‘ and District = 'Alaska' and population > 10000

mysql> alter table City add key cov1(CountryCode, District, population, name);

索引里包含查询所使用的列规则:1. Where 部分2. Group By/Order (上面例子中未使用)3. Select 部分 ( 这里为 : name)

Page 14: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品覆盖索引实例:二

• Explain 信息

mysql> explain select name from City where CountryCode ='USA' and District = 'Alaska' and population > 10000\G*************************** 1. row *********** table: City type: rangepossible_keys: cov1 key: cov1 key_len: 27 ref: NULL rows: 1 Extra: Using where; Using index

Using index : 这信息表明使用了覆盖索引MySQL 将仅使用索引获取数据,不再直接去读取数据文件

Page 15: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品索引列规则:一

Range 和 “ const” 扫描 : 有效的索引基数cardinality

• select * from City where district = 'California' and population > 30000• 索引 (district, population) • 经验法则 : “Const” 最好 , “Range” 次之 —— 根据具体查询判断

Page 16: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品索引列规则:二

• mysql> alter table City add key comb1(district, population);

mysql> explain select name from City where district = 'California' and population > 10000\G********************** 1. row *************************** table: City type: rangepossible_keys: comb1 key: comb1 key_len: 24 ref: NULL rows: 68

这是比较理想的情况,索引起到限制读取行数的作用Key_len = 24 – 使用到两列索引 20 + 4

Page 17: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品索引列规则:二

• mysql> alter table City add key comb2(population, district);

mysql> explain select name from City where district = 'California' and population > 3000\G

table: City type: ALLpossible_keys: comb2 key: NULL key_len: NULL ref: NULL rows: 4162 Extra: Using where

这种是较糟糕的情况, mysql 优化器选择不使用索引Why?MySQL 仅能使用到 “ population” 部分population > 3000 的城市太多, mysql认为使用索引反而会影响效率

Page 18: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品索引选择度实例

• 索引选择( Cardinality ) = 记录列唯一值的数量,这是个预估值

mysql> alter table City add key comb2(population, District);

explain select name from City where District = 'California' and population > 1000000\G*********************** 1. row ***************************table: Citytype: rangepossible_keys: comb2key: comb2key_len: 4ref: NULLrows: 237Extra: Using where

数字加大后,使用到了索引但是 :key_len = 4 (INT)仅仅 population 部分被使用

Page 19: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品处理低效查询

… Group By …… Order By …Select distinct …

Temporary tables

Filesort

Page 20: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品GROUP BY 及临时表

• 每个国家有各多少城市mysql> explain select CountryCode, count(*) from City group by CountryCode\G id: 1 select_type: SIMPLE table: City type: ALLpossible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4079 Extra: Using temporary; Using filesort

出现临时表,这样的查询效率就比较低

Page 21: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品临时表:一

主要的性能问题• 当使用到下列查询时 MySQL 将创建临时表 :• GROUP BY• 范围扫描 + ORDER BY• 其他表达式

存在两种类型临时表:• MEMORY• On-disk

Page 22: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品临时表 : 二

• 首先 mysql 会试图在内存中创建临时表• MySQL 配置参数 : -- tmp_table_size :允许mysql 在内存中创建临时表的最大值 -- max_heap_table_size :配置内存表的最大值

Page 23: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品临时表:三

• 磁盘上的临时表转换关系

temp table >tmp_table_size

MySQLtemp table >max_heap_table_size

在磁盘上转换为MyISAM临时表

OR

Page 24: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品临时表 : 五

•MEMORY 存储引擎不支持 BLOB/TEXT > select blob_field from table group by field1 > select concat(...string>512 chars) group by field1

• 上面两种情况都会在磁盘上创建临时表

注意: Percona mysql 及 MariaDB 服务器使用新的 MEMORY 存储引擎来支持 BLOB/TEXT但是 : 它不是用来创建临时表

Page 25: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品临时表实践:

CREATE TABLE ontime_2012 ( YearD int(11) DEFAULT NULL, MonthD tinyint(4) DEFAULT NULL, DayofMonth tinyint(4) DEFAULT NULL, DayOfWeek tinyint(4) DEFAULT NULL, Carrier char(2) DEFAULT NULL, Origin char(5) DEFAULT NULL, DepDelayMinutes int(11) DEFAULT NULL,) ENGINE=InnoDB DEFAULT CHARSET=latin1

Page 26: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品分组查询实例:一

• 查找星期天航班的最大延迟时间• 以航空公司分组( group by )

>SELECT max(DepDelayMinutes), carrier, dayofweek FROM ontime_2012 WHERE dayofweek = 7 GROUP BY Carrier;

Page 27: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品分组查询实例:二

• Explain select max(DepDelayMinutes), carrier, dayofweek from ontime_2012 where dayofweek = 7 group by Carrier type: ALLpossible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 951353 Extra: Using where; Using temporary; Using filesort

全表扫描使用临时表

Page 28: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品添加索引 : 修正全表扫描

mysql> alter table ontime_2012 add key (dayofweek);mysql> explain select max(DepDelayMinutes), Carrier, dayofweek from ontime_2012 where dayofweek =7 group by Carrier\G type: refpossible_keys: DayOfWeek key: DayOfWeek key_len: 2 ref: const rows: 195112 Extra: Using where; Using temporary; Using filesort

很好的使用了索引但是依然使用到临时表

Page 29: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品Group by :添加覆盖索引

mysql> alter table ontime_2012 add key covered(dayofweek, Carrier, DepDelayMinutes);mysql> explain select max(DepDelayMinutes), Carrier, dayofweek from ontime_2012 where dayofweek =7 group by Carrier\G...possible_keys: DayOfWeek,covered key: covered key_len: 2 ref: const rows: 905138 Extra: Using where; Using index

这种情况成为 “ tight index scan” (紧凑所以扫描)

Mysql 没有使用到临时表,通过索引获取数据

Page 30: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品用覆盖索引不理想的情况

mysql> explain select max(DepDelayMinutes), Carrier, dayofweek from ontime_2012 where dayofweek > 3 group by Carrier, dayofweek\G... type: rangepossible_keys: covered key: covered key_len: 2 ref: NULL rows: 2441781 Extra: Using where; Using index; Using temporary;Using filesort

mysql 使用了范围扫描

Page 31: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品GROUP BY: 松散索引扫描

• 松散索引( loose index )扫描 : 当 MySQL 完全利用索引扫描来实现 GROUP BY 的时候,仅使用部分索引键即可完成操作得出结果

• 要使用松散索引,最少需满足一下条件 : 查询针对一个单表 GROUP BY 条件字段必须在同一个索引中最前面的连续位置 在使用 GROUP BY 的同时,如果有聚合函数,只能使用 MAX 和 MIN

这两个聚合函数,并且它们均指向相同的列 如果 where条件中引用到了该索引中 GROUP BY 条件之外的字段条件

的时候,必须以常量形式存在,但 MIN()或MAX() 函数的参数例外 如果查询中有 where条件,则条件必须为索引,不能包含非索引的字段

Page 32: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品松散索引扫描实例:

mysql> alter table ontime_2012 add key loose_index_scan (Carrier, dayofweek, DepDelayMinutes);mysql> explain select max(DepDelayMinutes), Carrier, dayofweek from ontime_2012 where dayofweek > 5 group by Carrier, dayofweek\G ...select_type: SIMPLE table: ontime_2012 type: rangepossible_keys: DayOfWeek key: loose_index_scan key_len: 5 ref: NULL rows: 359 Extra: Using where; Using index for group-by

这是一个很快的松散索引扫描 ,“ Range” 类型工作 !

Page 33: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品GROUP BY :紧凑索引扫描

• 紧凑索引扫描:全索引扫描或者是范围索引扫描 松散索引扫描不可用时,使用紧凑索引扫描 扫描索引,并且避免创建临时表扫描所有满足条件的索引 -- 相当于覆盖索引: Covered index

Page 34: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品松散索引扫描 vs. 紧凑 索引扫描 : 一

CREATE TABLE `ontime_2012` ( `YearD` int(11) DEFAULT NULL, `MonthD` tinyint(4) DEFAULT NULL, `DayofMonth` tinyint(4) DEFAULT NULL, `DayOfWeek` tinyint(4) DEFAULT NULL, `Carrier` char(2) DEFAULT NULL, `Origin` char(5) DEFAULT NULL, `DepDelayMinutes` int(11) DEFAULT NULL, KEY `DayOfWeek` (`DayOfWeek`), KEY `loose_index_scan` (`Carrier`,`DayOfWeek`,`DepDelayMinutes`), KEY `covered` (`DayOfWeek`,`Carrier`,`DepDelayMinutes`)) ENGINE=InnoDB DEFAULT CHARSET=latin1

添加两个索引进行查询对比

Page 35: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品松散索引扫描 vs. 紧凑 索引扫描

mysql> explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012where dayofweek = 5 group by Carrier, dayofweek\G

table: ontime_2012 type: rangepossible_keys: DayOfWeek,covered key: loose_index_scan key_len: 5 ref: NULL rows: 19 Extra: Using where; Using index for group-bymysql> select ...+-------+----------+----------------+| ddm | Carrier | dayofweek |+-------+----------+----------------+| 803 | AA | 5 || 432 | AS | 5 | …15 rows in set (0.00 sec)

使用松散索引扫描:loose_index_scan(`Carrier`,`DayOfWeek`,`DepDelayMinutes`),

Page 36: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品松散索引扫描 vs. 紧凑 索引扫描 : 二 ——松散索引扫描

mysql> explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012where dayofweek > 5 group by Carrier, dayofweek\G

table: ontime_2012 type: rangepossible_keys: DayOfWeek,covered key: loose_index_scan key_len: 5 ref: NULL rows: 19 Extra: Using where; Using index for group-bymysql> select max(DepDelayMinutes) as ddm …+-------+----------+--------------+| ddm | Carrier | dayofweek |+-------+----------+--------------+| 1443 | AA | 6 || 1364 | AA | 7 |…30 rows in set (0.00 sec)

使用松散索引扫描:loose_index_scan(`Carrier`,`DayOfWeek`,`DepDelayMinutes`),

Page 37: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品

松散索引扫描 vs. 紧凑 索引扫描 : 三 ——松散索引扫描

mysql>explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012 where dayofweek > 5 group by Carrier, dayofweek order by ddm desc\G… table: ontime_2012 type: rangepossible_keys: DayOfWeek,covered key: loose_index_scan key_len: 5 ref: NULL rows: 19 Extra: Using where; Using index for group-by; Using temporary; Using filesortmysql>select max(DepDelayMinutes) as ddm,…+------+---------+-----------+| ddm | Carrier | dayofweek |+------+---------+-----------+| 1443 | AA | 6 || 1364 | AA | 7 |…30 rows in set (0.00 sec)

使用松散索引扫描:loose_index_scan(`Carrier`,`DayOfWeek`,`DepDelayMinutes`),

Page 38: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品

松散索引扫描 vs. 紧凑索引扫描 —— 使用临时表

mysql>explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012ignore index(loose_index_scan) where dayofweek > 5 group by Carrier, dayofweek\G… table: ontime_2012 type: rangepossible_keys: DayOfWeek,covered key: covered key_len: 2 ref: NULL rows: 407712 Extra: Using where; Using index; Using temporary; Using filesort10:13:16> select max(DepDelayMinutes) as ddm …+------+-----------+--------------+| ddm | Carrier | dayofweek |+------+-----------+--------------+| 1443 | AA | 6 || 1364 | AA | 7 |…30 rows in set (0.37 sec)

1. 范围扫描2. 使用临时表,并且使用 40万条数据排序

Page 39: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品

松散索引扫描 vs. 紧凑索引扫描 —— 紧凑索引扫描

mysql>explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012 ignore index(loose_index_scan) where dayofweek = 5 group by Carrier, dayofweek\G…

table: ontime_2012 type: refpossible_keys: DayOfWeek,covered key: covered key_len: 2 ref: const rows: 170856 Extra: Using where10:23:00> select max(DepDelayMinutes) as ddm+------+---------+-----------+| ddm | Carrier | dayofweek |+------+---------+-----------+| 803 | AA | 5 || 432 | AS | 5 |15 rows in set (0.14 sec)

1. 使用 Covered index :covered(`DayOfWeek`,`Carrier`,`DepDelayMinutes`)

2. 没有使用临时表3. 但是需要扫描 17万行数据

Page 40: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品其他聚合函数不支持松散索引

AVG() + Group By —— 不支持 loose index scan

mysql> explain select avg(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012 where dayofweek >5 group by Carrier, dayofweek \G

table: ontime_2012 type: rangepossible_keys: DayOfWeek,covered key: covered key_len: 2 ref: NULL rows: 407712 Extra: Using where; Using index; Using temporary; Using filesortmysql> select avg(DepDelayMinutes) as ddm,…+---------+---------+---------------+| ddm | Carrier | dayofweek |+---------+---------+---------------+| 7.7223 | AA | 6 || 7.6131 | AA | 7 |…30 rows in set (0.50 sec)

1. No loose index scan2. Filter by key3. Group by filesort

Page 41: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品ORDER BY and filesort

ORDER BY 及 filesort

Page 42: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品

mysql> explain select district, name, population from Citywhere CountryCode = 'USA' order by population desc limit 10\Gtable: Citytype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 4079Extra: Using where; Using filesort

有文件排序

Page 43: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品解决文件排序:添加索引

mysql> alter table City add key my_sort2 (CountryCode, population);mysql> explain select district, name, population from Citywhere CountryCode = 'USA' order by population desc limit 10\Gtable: Citytype: refkey: my_sort2key_len: 3ref: constrows: 207Extra: Using where

无文件排序

Page 44: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品结束

Q&A

44

Page 45: mysql 高级优化之 理解索引使用

www.2345.com

王德玖作品 谢谢

45