MySQL 高级优化之——

理解索引使用

上海二三四五网络科技股份有限公司
互联网研发中心
王德玖
2014-01-14

www.2345.com
议程
•
•
•
•
•

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

2

www.2345.com
实例数据库安装
• 本ppt后半部分使用 airport 数据库为事例;
• 下载地址:
http://www.transtats.bts.gov/DL_SelectFields.asp?
Table_ID=236&DB_Short_Name=...
索引信息:
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

root@localhost: dianying_2345 >show index from dy_data_newG
*...
创建实例表:
CREATE TABLE City (
ID int(11) NOT NULL AUTO_INCREMENT,
Name char(35) NOT NULL DEFAULT '',
CountryCode char(3) NOT ...
索引实例
• 使用一个索引的情况(这也是最好的情况)
mysql> explain select * from City where ID = 1;
+-------+-------+-------------------+----------...
联合索引
• 最左联合索引
mysql> alter table City add key
comb(CountryCode, District, Population),
drop key CounryCode;

www.2345.com
联合索引实例一
• 最左联合索引
mysql> explain select * from City
where CountryCode = 'USA'G
********************** 1. row **************...
联合索引实例二
Key_len = 被使用到的索引总大小(字符长度b)

Index: comb(CountryCode, District, Population)
Explain:
key: comb
key_len: 3

列:
Coun...
联合索引实例三
• 最左两列索引被使用

mysql> explain select * from City
where CountryCode = 'USA' and District = 'California'G
************...
联合索引实例四
• 三列索引同事被使用
mysql> explain select * from City
where CountryCode = 'USA' and District = 'California’
and population...
联合索引实例五
• 无法使用联合索引的情况——没有最左部分
mysql> explain select * from City where
District = 'California' and population > 10000G
****...
覆盖索引实例:一
• 覆盖索引: 索引里包含查询所使用的列
select name from City where CountryCode = 'USA‘ and
District = 'Alaska' and population > 100...
覆盖索引实例:二
• Explain 信息
mysql> explain select name from City where CountryCode =
'USA' and District = 'Alaska' and populatio...
索引列规则:一
Range 和 “const” 扫描: 有效的索引基数cardinality
• select * from City where district = 'California'
and population > 30000
•...
索引列规则:二
• mysql> alter table City add key comb1(district, population);
mysql> explain select name from City where
district...
索引列规则:二
• mysql> alter table City add key comb2(population, district);
mysql> explain select name from City where
district...
索引选择度实例
•

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

mysql> alter table City
add key comb2(population, District);
explain sele...
处理低效查询
… Group By …
… Order By …
Select distinct …

Temporary
tables

Filesort
www.2345.com
GROUP BY 及临时表
• 每个国家有各多少城市
mysql> explain select CountryCode, count(*) from City
group by CountryCodeG
id: 1
select_type: ...
临时表:一
主要的性能问题

• 当使用到下列查询时MySQL 将创建临时表:
• GROUP BY
• 范围扫描 + ORDER BY
• 其他表达式
存在两种类型临时表:
• MEMORY
• On-disk
www.2345.com
临时表:二
• 首先mysql会试图在内存中创建临时表
• MySQL 配置参数:
-- tmp_table_size
:允许mysql在内存中创建临时表的最大值

-- max_heap_table_size
:配置内存表的最大值

www....
临时表:三
• 磁盘上的临时表转换关系
temp
table
>
tmp_table
_
size

OR

MySQL
temp table
>
max_heap_
table_size

在磁盘上
转换为
MyISAM
临时表

www.2...
临时表:五
•MEMORY 存储引擎不支持 BLOB/TEXT
> select blob_field from table group by field1
> select concat(...string>512 chars) group ...
临时表实践:
CREATE TABLE ontime_2012 (
YearD int(11) DEFAULT NULL,
MonthD tinyint(4) DEFAULT NULL,
DayofMonth tinyint(4) DEFAUL...
分组查询实例:一
• 查找星期天航班的最大延迟时间
• 以航空公司分组(group by)
>SELECT max(DepDelayMinutes),
carrier, dayofweek
FROM ontime_2012
WHERE dayo...
分组查询实例:二
• Explain select max(DepDelayMinutes), carrier, dayofweek
from ontime_2012
where dayofweek = 7
group by Carrier
t...
添加索引: 修正全表扫描
mysql> alter table ontime_2012 add key (dayofweek);
mysql> explain select max(DepDelayMinutes), Carrier,
dayo...
Group by :添加覆盖索引
mysql> alter table ontime_2012
add key covered(dayofweek, Carrier, DepDelayMinutes);
mysql> explain selec...
用覆盖索引不理想的情况
mysql> explain select max(DepDelayMinutes), Carrier,
dayofweek from ontime_2012
where dayofweek > 3 group by C...
GROUP BY: 松散索引扫描
• 松散索引(loose index)扫描:
 当 MySQL 完全利用索引扫描来实现 GROUP BY 的时候,仅使用部分索引键即
可完成操作得出结果

• 要使用松散索引,最少需满足一下条件:
 查询针...
松散索引扫描实例:
mysql> alter table ontime_2012 add key loose_index_scan

(Carrier, dayofweek, DepDelayMinutes);
mysql> explain s...
GROUP BY:紧凑索引扫描
• 紧凑索引扫描:
全索引扫描或者是范围索引扫描
 松散索引扫描不可用时,使用紧凑索引扫描
 扫描索引,并且避免创建临时表
扫描所有满足条件的索引
-- 相当于覆盖索引:Covered index

ww...
松散索引扫描vs. 紧凑 索引扫描:一
CREATE TABLE `ontime_2012` (
`YearD` int(11) DEFAULT NULL,
`MonthD` tinyint(4) DEFAULT NULL,
添加两个索引进行
...
松散索引扫描vs. 紧凑 索引扫描
mysql> explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012
where dayofweek =...
松散索引扫描vs. 紧凑 索引扫描:二
——松散索引扫描
mysql> explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from
ontime_2012
where ...
松散索引扫描vs. 紧凑 索引扫描:三
——松散索引扫描
mysql>explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from
ontime_2012
where d...
松散索引扫描vs. 紧凑索引扫描
—— 使用临时表
mysql>explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from
ontime_2012
ignore ind...
松散索引扫描vs. 紧凑索引扫描
—— 紧凑索引扫描
mysql>explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012 ignore
in...
其他聚合函数不支持松散索引
AVG() + Group By ——不支持loose index scan
mysql> explain select avg(DepDelayMinutes) as ddm, Carrier, dayofweek...
ORDER BY and filesort

ORDER BY 及 filesort

www.2345.com
mysql> explain select district, name, population from City
where CountryCode = 'USA' order by population desc limit
10G
ta...
解决文件排序:添加索引
mysql> alter table City add key my_sort2
(CountryCode, population);
mysql> explain select district, name, popu...
结束

Q&A
44

www.2345.com
谢谢

45

www.2345.com
Upcoming SlideShare
Loading in …5
×

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

1,356 views

Published on

Published in: Technology, Travel

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

  1. 1. MySQL 高级优化之—— 理解索引使用 上海二三四五网络科技股份有限公司 互联网研发中心 王德玖 2014-01-14 www.2345.com
  2. 2. 议程 • • • • • Mysql 信息查看 联合索引,最左索引,覆盖索引 介绍松散索引及紧凑索引 优化文件排序 问答 2 www.2345.com
  3. 3. 实例数据库安装 • 本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.csv mysql> 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 www.2345.com
  4. 4. 索引信息: • • • • • • • • • • • • • • • • • • • • • • • • • • • root@localhost: dianying_2345 >show index from dy_data_newG *************************** 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 编入索引,则为NULL。 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,为YES,如果没有,则该列为NO 使用的索引方法:BTREE, FULLTEXT, HASH, RTREE 评注 www.2345.com
  5. 5. 创建实例表: 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; www.2345.com
  6. 6. 索引实例 • 使用一个索引的情况(这也是最好的情况) 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 | +-------+------+------------------+------------------+---------+---------+---------+-----------------+ www.2345.com
  7. 7. 联合索引 • 最左联合索引 mysql> alter table City add key comb(CountryCode, District, Population), drop key CounryCode; www.2345.com
  8. 8. 联合索引实例一 • 最左联合索引 mysql> explain select * from City where CountryCode = 'USA'G ********************** 1. row ****************** table: City 使用了comb 的最左一列索引 type: ref possible_keys: comb key: comb key_len: 3 ref: const rows: 273 www.2345.com
  9. 9. 联合索引实例二 Key_len = 被使用到的索引总大小(字符长度b) Index: comb(CountryCode, District, Population) Explain: key: comb key_len: 3 列: CountryCode char(3) District char(20) Population int(11) 3 char(3) comb  的第一列CountyCode char(3)被使用 www.2345.com
  10. 10. 联合索引实例三 • 最左两列索引被使用 mysql> explain select * from City where CountryCode = 'USA' and District = 'California'G ********************** 1. row ****************** table: City 索引`Comb`最左两列索引被使用 type: ref CountryCode = 3 chars possible_keys: comb District = 20 chars key: comb Total = 23 key_len: 23 ref: const,const rows: 68 www.2345.com
  11. 11. 联合索引实例四 • 三列索引同事被使用 mysql> explain select * from City where CountryCode = 'USA' and District = 'California’ and population > 10000G ********************** 1. row ****************** table: City type: range 这里使用到了 comb 索引的所有列: possible_keys: comb CountryCode = 3 chars/bytes District = 20 chars/bytes key: comb Population = 4 bytes (INT) key_len: 27 Total = 27 ref: NULL rows: 68 www.2345.com
  12. 12. 联合索引实例五 • 无法使用联合索引的情况——没有最左部分 mysql> explain select * from City where District = 'California' and population > 10000G ********************** 1. row ****************** table: City CountryCode 列没有出现在 type: ALL where possible_keys: NULL 子句里,所以无法使用到 comb key: NULL 这个联合索引 key_len: NULL ref: NULL rows: 3868 www.2345.com
  13. 13. 覆盖索引实例:一 • 覆盖索引: 索引里包含查询所使用的列 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) www.2345.com
  14. 14. 覆盖索引实例:二 • Explain 信息 mysql> explain select name from City where CountryCode = 'USA' and District = 'Alaska' and population > 10000G *************************** 1. row *********** table: City Using index : 这信息表明使用 type: range 了覆盖索引 possible_keys: cov1 MySQL 将仅使用索引获取数据, key: cov1 不再直接去读取数据文件 key_len: 27 ref: NULL rows: 1 Extra: Using where; Using index www.2345.com
  15. 15. 索引列规则:一 Range 和 “const” 扫描: 有效的索引基数cardinality • select * from City where district = 'California' and population > 30000 • 索引 (district, population) • 经验法则: “Const” 最好, “Range” 次之 —— 根据具体查询判断 www.2345.com
  16. 16. 索引列规则:二 • mysql> alter table City add key comb1(district, population); mysql> explain select name from City where district = 'California' and population > 10000G ********************** 1. row *************************** table: City type: range 这是比较理想的情况,索引起 possible_keys: comb1 到限制读取行数的作用 Key_len = 24 – 使用到两列索引 key: comb1 20 + 4 key_len: 24 ref: NULL rows: 68 www.2345.com
  17. 17. 索引列规则:二 • mysql> alter table City add key comb2(population, district); mysql> explain select name from City where district = 'California' and population > 3000G table: City type: ALL possible_keys: comb2 key: NULL key_len: NULL ref: NULL rows: 4162 Extra: Using where 这种是较糟糕的情况,mysql优化器选择 不使用索引 Why? MySQL 仅能使用到 “population” 部分 population > 3000 的城市太多,mysql 认为使用索引反而会影响效率 www.2345.com
  18. 18. 索引选择度实例 • 索引选择(Cardinality) = 记录列唯一值的数量,这是个预估值 mysql> alter table City add key comb2(population, District); explain select name from City where District = 'California' and population > 1000000G *********************** 1. row *************************** 数字加大后,使用到了索引 table: City 但是: type: range key_len = 4 (INT) possible_keys: comb2 仅仅 population 部分被使用 key: comb2 key_len: 4 ref: NULL rows: 237 Extra: Using where www.2345.com
  19. 19. 处理低效查询 … Group By … … Order By … Select distinct … Temporary tables Filesort www.2345.com
  20. 20. GROUP BY 及临时表 • 每个国家有各多少城市 mysql> explain select CountryCode, count(*) from City group by CountryCodeG id: 1 select_type: SIMPLE table: City 出现临时表,这样的查询效率 type: ALL 就比较低 possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4079 Extra: Using temporary; Using filesort www.2345.com
  21. 21. 临时表:一 主要的性能问题 • 当使用到下列查询时MySQL 将创建临时表: • GROUP BY • 范围扫描 + ORDER BY • 其他表达式 存在两种类型临时表: • MEMORY • On-disk www.2345.com
  22. 22. 临时表:二 • 首先mysql会试图在内存中创建临时表 • MySQL 配置参数: -- tmp_table_size :允许mysql在内存中创建临时表的最大值 -- max_heap_table_size :配置内存表的最大值 www.2345.com
  23. 23. 临时表:三 • 磁盘上的临时表转换关系 temp table > tmp_table _ size OR MySQL temp table > max_heap_ table_size 在磁盘上 转换为 MyISAM 临时表 www.2345.com
  24. 24. 临时表:五 •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 但是: 它不是用来创建临时表 www.2345.com
  25. 25. 临时表实践: 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 www.2345.com
  26. 26. 分组查询实例:一 • 查找星期天航班的最大延迟时间 • 以航空公司分组(group by) >SELECT max(DepDelayMinutes), carrier, dayofweek FROM ontime_2012 WHERE dayofweek = 7 GROUP BY Carrier; www.2345.com
  27. 27. 分组查询实例:二 • Explain select max(DepDelayMinutes), carrier, dayofweek from ontime_2012 where dayofweek = 7 group by Carrier type: ALL 全表扫描 possible_keys: NULL 使用临时表 key: NULL key_len: NULL ref: NULL rows: 951353 Extra: Using where; Using temporary; Using filesort www.2345.com
  28. 28. 添加索引: 修正全表扫描 mysql> alter table ontime_2012 add key (dayofweek); mysql> explain select max(DepDelayMinutes), Carrier, dayofweek from ontime_2012 where dayofweek =7 group by CarrierG type: ref 很好的使用了索引 possible_keys: DayOfWeek 但是依然使用到临时表 key: DayOfWeek key_len: 2 ref: const rows: 195112 Extra: Using where; Using temporary; Using filesort www.2345.com
  29. 29. 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 CarrierG ... possible_keys: DayOfWeek,covered Mysql没有使用到临时 key: covered 表,通过索引获取数据 key_len: 2 ref: const rows: 905138 Extra: Using where; Using index  这种情况成为 “tight index scan” (紧凑所以扫描) www.2345.com
  30. 30. 用覆盖索引不理想的情况 mysql> explain select max(DepDelayMinutes), Carrier, dayofweek from ontime_2012 where dayofweek > 3 group by Carrier, dayofweekG ... type: range mysql使用了范围扫 possible_keys: covered 描 key: covered key_len: 2 ref: NULL rows: 2441781 Extra: Using where; Using index; Using temporary;Using filesort www.2345.com
  31. 31. GROUP BY: 松散索引扫描 • 松散索引(loose index)扫描:  当 MySQL 完全利用索引扫描来实现 GROUP BY 的时候,仅使用部分索引键即 可完成操作得出结果 • 要使用松散索引,最少需满足一下条件:  查询针对一个单表  GROUP BY 条件字段必须在同一个索引中最前面的连续位置  在使用GROUP BY 的同时,如果有聚合函数,只能使用 MAX 和 MIN 这 两个聚合函数,并且它们均指向相同的列  如果where条件中引用到了该索引中GROUP BY 条件之外的字段条件的 时候,必须以常量形式存在,但MIN()或MAX() 函数的参数例外  如果查询中有where条件,则条件必须为索引,不能包含非索引的字段 www.2345.com
  32. 32. 松散索引扫描实例: 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, dayofweekG ... select_type: SIMPLE table: ontime_2012 这是一个很快的松散索 type: range 引扫描 ,“Range” 类型 工作! possible_keys: DayOfWeek key: loose_index_scan key_len: 5 ref: NULL rows: 359 Extra: Using where; Using index for group-by www.2345.com
  33. 33. GROUP BY:紧凑索引扫描 • 紧凑索引扫描: 全索引扫描或者是范围索引扫描  松散索引扫描不可用时,使用紧凑索引扫描  扫描索引,并且避免创建临时表 扫描所有满足条件的索引 -- 相当于覆盖索引:Covered index www.2345.com
  34. 34. 松散索引扫描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 www.2345.com
  35. 35. 松散索引扫描vs. 紧凑 索引扫描 mysql> explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012 where dayofweek = 5 group by Carrier, dayofweekG table: ontime_2012 type: range possible_keys: DayOfWeek,covered key: loose_index_scan key_len: 5 ref: NULL rows: 19 Extra: Using where; Using index for group-by mysql> select ... +-------+----------+----------------+ | ddm | Carrier | dayofweek | +-------+----------+----------------+ | 803 | AA | 5 | | 432 | AS | 5 | … 15 rows in set (0.00 sec) 使用松散索引扫描: loose_index_scan(`Carrier`,`Day OfWeek`,`DepDelayMinutes`), www.2345.com
  36. 36. 松散索引扫描vs. 紧凑 索引扫描:二 ——松散索引扫描 mysql> explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012 where dayofweek > 5 group by Carrier, dayofweekG table: ontime_2012 type: range possible_keys: DayOfWeek,covered key: loose_index_scan key_len: 5 ref: NULL rows: 19 Extra: Using where; Using index for group-by mysql> 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`,`Day OfWeek`,`DepDelayMinutes`), www.2345.com
  37. 37. 松散索引扫描vs. 紧凑 索引扫描:三 ——松散索引扫描 mysql>explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012 where dayofweek > 5 group by Carrier, dayofweek order by ddm descG … table: ontime_2012 type: range 使用松散索引扫描: possible_keys: DayOfWeek,covered loose_index_scan(`Carrier`,`Day key: loose_index_scan OfWeek`,`DepDelayMinutes`), key_len: 5 ref: NULL rows: 19 Extra: Using where; Using index for group-by; Using temporary; Using filesort mysql>select max(DepDelayMinutes) as ddm,… +------+---------+-----------+ | ddm | Carrier | dayofweek | +------+---------+-----------+ | 1443 | AA | 6| | 1364 | AA | 7| … 30 rows in set (0.00 sec) www.2345.com
  38. 38. 松散索引扫描vs. 紧凑索引扫描 —— 使用临时表 mysql>explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012 ignore index(loose_index_scan) where dayofweek > 5 group by Carrier, dayofweekG … table: ontime_2012 type: range possible_keys: DayOfWeek,covered key: covered key_len: 2 ref: NULL rows: 407712 Extra: Using where; Using index; Using temporary; Using filesort 10: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万条数据 排序 www.2345.com
  39. 39. 松散索引扫描vs. 紧凑索引扫描 —— 紧凑索引扫描 mysql>explain select max(DepDelayMinutes) as ddm, Carrier, dayofweek from ontime_2012 ignore index(loose_index_scan) where dayofweek = 5 group by Carrier, dayofweekG … table: ontime_2012 type: ref possible_keys: DayOfWeek,covered key: covered key_len: 2 ref: const rows: 170856 Extra: Using where 10: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万行数据 www.2345.com
  40. 40. 其他聚合函数不支持松散索引 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: range 1. No loose index scan possible_keys: DayOfWeek,covered 2. Filter by key key: covered 3. Group by filesort key_len: 2 ref: NULL rows: 407712 Extra: Using where; Using index; Using temporary; Using filesort mysql> select avg(DepDelayMinutes) as ddm,… +---------+---------+---------------+ | ddm | Carrier | dayofweek | +---------+---------+---------------+ | 7.7223 | AA | 6 | | 7.6131 | AA | 7 | … 30 rows in set (0.50 sec) www.2345.com
  41. 41. ORDER BY and filesort ORDER BY 及 filesort www.2345.com
  42. 42. mysql> explain select district, name, population from City where CountryCode = 'USA' order by population desc limit 10G table: City type: ALL 有文件排序 possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4079 Extra: Using where; Using filesort www.2345.com
  43. 43. 解决文件排序:添加索引 mysql> alter table City add key my_sort2 (CountryCode, population); mysql> explain select district, name, population from City where CountryCode = 'USA' order by population desc limit 10G table: City type: ref key: my_sort2 无文件排序 key_len: 3 ref: const rows: 207 Extra: Using where www.2345.com
  44. 44. 结束 Q&A 44 www.2345.com
  45. 45. 谢谢 45 www.2345.com

×