简单介绍了一些常见MySQL数据库优化手段,比如减少数据访问、使用索引、使用关联查询等等。
查询性能低下的最基本原因就是访问了太多数据,一些查询要不可避免地筛选大量的数据,大部分性能欠佳的查询都可以用减少数据访问的方式进行优化,这是最简单也是很有效的优化方式。
SELECT *
语句,只返回必要的行,通常使用 LIMIT
语句来限制返回的数据条数。执行时间、检查的行数、返回的行数
来看,但这些不可作为绝对的标准。
一般MySQL能够使用如下三种方式应用WHERE条件,从好到坏依次为:
Extra
列中出现了Using index
)来返回记录,直接从索引中过滤不需要的记录并返回命中的结果。这是在MySQL服务器层完成的,但无须再回表查询记录。Using Where
)。这在MySQL服务器层完成,MySQL需要先从数据表读出记录然后过滤。有些时候我们需要重写查询以获取更好的性能,尽管得到的结果可能不同,也许最终程序的代码也会和查询一起被改。
关于子查询优化我们给出的最重要的优化建议就是尽可能使用关联查询代替,但这不是绝对的。
MySQL5.6
开始,引入物化子查询(针对where clause的subquery),子查询物化将子查询结果存入临时表,确保子查询只执行一次,该表不记录重复数据且采用哈希索引查找,where后面的in()子查询不会被改写为exists子查询,因此可不做改写。
子查询生成的临时表是没有索引的。
MySQL 经常用同样的方法来优化这两个查询,它们都会用索引来优化,这也是最有效的优化办法。
当无法使用索引的时候,MySQL 会用临时表或者文件排序(filessort,但并不一定使用此磁盘文件)来执行 GROUP BY。
如果需要对关联查询做分组,那么通常采用标识列(比如id)来进行分组效率会比较高(如果允许)。
进行分页操作时,通常都会通过Limit加上偏移量来查询某些数据,同时再加上适合的order by字句,如果有对应的索引,性能一般都不错。
一个非常常见又令人头疼的问题就是,在偏移量非常大的时候,例如可能是LIMIT1000,20这样的查询,这时MySQL需要查询10 020条记录然后只返回最后20条,前面10 000条记录都将被抛弃,这样的代价非常高。
如下案例:
select * from contacts ORDER BY phone LIMIT 40000,11;
此时,最简单的一个优化的办法是尽可能利用到索引覆盖扫描,而不是一次性查询所有的列,然后根据需要做一次关联查询在返回所需要的列,这种方式称为延迟关联。
select * from contacts INNER JOIN (select contact_id from contacts ORDER BY phone LIMIT 40000,11) as xx USING(contact_id);
MySQL总是通过创建并填充临时表的方式来执行UNION查询。因此很多优化策略在UNION查询中都没法很好地使用。经常需要手工地将MHERE、LIMIT、ORDER BY等子句“下推”到UNION的各个子查询中,以便优化器可以充分利用这些条件进行优化(例如,直接将这些子句冗余地写一份到各个子查询)。
除非确实需要服务器消除重复的行,否则就一定要使用UNION ALL
,这一点很重要。如果没有ALL关键字,MySQL会给临时表加上DISTINCT
选项,这会导致对整个临时我的数据做唯一性检查。这样做的代价非常高。即使有ALL关键字,MySQL仍然会使用临时表存储结果。事实上,MySQL总是将结果放入临时表,然后再读出,再返回给客户端。虽然很多时候这样做是没有必要的(例如,MySQL可以直接把这些结果返回给客户端)。
参考资料:
如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!