高性能MySQL(第三版) 是在MySQL5.5的基础上进行讲解的。
研读了第六章 查询性能优化的5-6小节,记录一些知识点。
- 假如有如下索引 (a,b),有下面的查询:
select ... from tb1 where b between 2 and 5
因为索引的前导字段是 a,但是查询的 where 条件中只指定了字段 b,MySQL 无法使用 (a,b) 这个索引,只能全表扫描,因为 MySQL不支持松散索引扫描。
- MySQL 不支持在同一张表同时进行查询和更新,当需要将查询和更新放在一条 SQL 中时,可以将查询语句当作临时表处理。
- 如果想知道结果集的行数,最好用 count(*),而不是 count(列名),count(列名) 只会把列中不为空的行统计出来,不为空不是不为NULL,是没有数据的意思。
- 在没有 where 条件的情况下,MyISAM 的 count() 很快,这是因为 MyISAM 存储了总行数
- 除非有其他特许需要,否则在关联查询中,只需要在关联顺序中的第二个表的相应列上创建索引就行
- 最好确保 group by 和 order by 中的表达式只涉及到一个表中的列,这样 MySQL 才有可能使用索引来优化这个过程
- 为了提升 limit 的性能,可以通过索引覆盖的技术进行延迟关联
什么是索引覆盖,就直接拿《高性能MySQL》中的例子来看看,如下"
select film_id,description from sakila.film order by title limit 50,5
SQL的功能是查找出第50-54条数据并返回,MySQL是这样处理的,把0-54条数据都查出来,然后将50之前的数据舍弃,这样做对性能的影响很大。
并且查询过程是这样的:
1.先通过非主键索引找到主键索引的值film_id,但是还需要查出字段description的值,所以还需要再通过主键索引的值查到所需要的数据description,也就是需要两次查询
2.上面这个SQL是先关联查询出所有的数据,然后再limit
通过如果用延迟关联,性能会有提升,修改后SQL如下:
select film.fim_id,film.description from sakila.film
INNER JOIN (
select film_id from sakila.fim order by title limit 50,5
) as lim USING(fim_id)
这样先将需要数据的主键id查出来,然后再进行关联查询,提升了性能
- limit 和 offset 问题,其实是 offset 的问题,他会导致 MySQL 扫描大量不需要的行然后再抛弃掉(可以用书签记录上次取数据的位置,然后别用 offset)
- SQL_CALC_FOUND_ROWS 可以获取去掉 limit 后满足条件的所有行,代价比较大,因为要扫所有满足条件的行
- 尽量用 UNION ALL,如果没有 ALL 关键字,MySQL 会给临时表加上 DISTINCT 选项,会导致整个临时表的数据需要做唯一性检查,代价很高