本文为Percona的Practical MySQL Performance Optimization第3节的笔记,基础知识为主。
索引
InnoDB和MyISAM都支持B-tree索引,可以支持快速的相等查询(例如id = 1)和范围查询(例如>、<和in)。InnoDB的主键索引还是聚簇的,数据和主键放一起,获取数据会更快。
索引使用
explain
可以查看MySQL对一个语句的执行计划,其中的key
是查询使用的索引。
MySQL查询的时候只会对每个表用一个索引,而且只用这个索引的最左前缀。
例如对一个三个字段组成的组合索引Comb(CountryCode, District, Population)
MySQL可以用下面这3个部分:
- 只用
CountryCode
部分 - 只用
CountryCode + District
部分 - 用
CountryCode + District + Population
全部
组合索引中各部分的顺序也会影响查询,最好是先比较相等的字段,再到范围字段。
查询计划中可以根据key_len
或JSON格式的查询计划中used_key_parts
来判断用了索引的那个部分。
覆盖索引就是覆盖了一个查询中Select、Where、Group by、Order by出现的全部字段的索引。
查询
Group by优化
没有索引的情况下要扫描整个表,还会用临时表存放结果。
筛选条件是相等比较时,用包含筛选条件和Group by字段的组合索引(或覆盖索引),可以避免临时表。(效果类似上面的图,先通过筛选条件的索引找到Group的索引,根据Group的索引知道Group的个数和数据的位置,然后对每个Group扫描就可以了)。
如果筛选条件是范围查询,可以已通过union改成多个查询合并,来减少临时表的大小(每个查询不用临时表,但最后合并要)。
在对一个表进行Group by,Group by条件只包含索引的最左前缀,而且只用max/min对这个索引的前缀进行聚合运算,MySQL可以进行松散的索引扫描,只用扫描少部分的索引,很快。(应该是索引里直接保存了max/min的结果来减少对一课子树的扫描)。
Order by优化
Order by查询数据多的时候要进行文件排序,而索引是已经排序的,可以避免文件排序,Limit条数较少也可以避免文件排序。
计算表达式
如果查询条件里有函数,MySQL是不能用函数参数上的索引快速筛选的,这时通常要用单独的一列保存函数调用的结果,但是要在应用层或触发器保证正确更新。MySQL 5.7有了虚拟/生成字段,可以直接在一个虚拟字段里保存函数调用的结果,虚拟字段不会被保存,但是可以建索引!