优化有问题的查询时,有时转换下写法,返回的结果不变,但性能却有所提升。
目录
一、切分查询
二、分解关联查询
三、优化count()查询
四、优化关联查询
五、优化group by 查询
六、优化limit 分页
场景:定期清除大量数据时,如果用一个大的语句一次性完成的话,则可能一次锁住很多数据,占满事务日志,阻塞查询。
优化:将一个大的delete语句切分为多个较小的查询,可以尽可能小地影响mysql性能,同时还可以减少mysql复制的延迟。
案例:
mysql > delete from messages from created_date < now()
********用类似下面的办法也可以完成
row_affected = 0
do {
row_affected = do_query {
" delete from messages from created_date < now() limit 10000"
}
} while row_affected > 0
这样重构之后,一次只删除1万行,循环判断是否还有可删除的记录。
很多高性能的应用会对关联查询进行分解,简单地说,可以对每个表进行单表查询,然后将结果在应用程序中进行关联。例如:
mysql > select t1* from tag t1 inner join tag_post t2
on t1.tag_id = t2.tag_id
*******分解成以下查询可代替
mysql > select * from tag_post where tag = 'mysql'
select * from tag where tag_id in ( 1234 , 1245 )
分解关联查询的好处如下:
1、让缓存的效率更高。
2、单个查询可能减少锁表的竞争。
3、使用IN()代替关联查询,可让mysql按id顺序查询,比随机关联更高效。
4、减少冗余记录的查询。
5、在应用中实现了哈希关联。而不是使用mysql嵌套循环关联。
当使用count(*) ,不会像我们猜想的扩展所有的列,而是忽略所有的列,直接统计所有的行数。所有统计行数,不要在括号内指定列,而是直接用count(*)
利用count(*) 全表统计快的特性,还可以作如下的处理。
mysql> select count(*) from repayment where id > 5
********改写如下:
mysql> select ( select count(*) from repayment - count(*) )
from repayment where id < 5
这样优化器按id顺序查询,只需要查前5条记录。
如果表A和表B用列C作关联,关联顺序是A join B,此时只需要在B表的C列建索引,没用到的索引只会带来额外的负担。
如果对关联查询做分组group by ,按表中的某个列分组。通常采用表的标识列分组的效率会更高一些。
mysql> select t1.first_name, t1.last_name, count(*)
->from film_actor t1 inner join actor t2 on t1.actor_id = t2.actor_id
->group by t1.first_name,t1.last_name
*****这样查效率不高,改写如下效率会更高:
mysql> select t1.first_name, t1.last_name, count(*)
->from film_actor t1 inner join actor t2 on t1.actor_id = t2.actor_id
->group by t2.actor_id
这个查询 利用了actor的名字和id直接相关的特点,改写后查询的结果不影响。
limit 10000,10,这样的查询,mysql需要查10000条记录后返回10条查询结果,前面的10000条记录将被丢弃,这样的代价很高。优化的方法是尽可能地使用索引覆盖查询。
mysql> select film_id , description from film order by title limit 10000,10
*******改写如下:
mysql> select film_id , description from film t1
-> inner join ( select film_id from film order by title limit 10000,10) t2
-> on t1.film_id = t2.film_id