Mysql 性能改进——最快实践

没错,标题我没打错。这里不是最佳实践,而是最快实践。在服务器上线,巨大的压力导致相应缓慢的时候,最佳实践已经毫无意义。这个时候,目的只有一个:最快改善性能,给开发人员重新设计、调整应用留出一定的时间。

这里不是细腻的微调,而是最粗旷的拉升。用最简单(可快速实施),变更最少(尽量避免变更引入新的 bug 和问题)的方法迅速改善 mysql 的性能。所以我这里的最快实践,不一定是最好的,不一定是最有效的,但是一定是最快能看到性能改善的方法。

tmp_table_size

实施难度:容易

实施时间:短

实施效果:明显

tmp_table_size 默认 32M,根据手册上的说法,这个限制了内存临时表的大小。增大这个值可以立刻改善 mysql 的性能,虽然不是万灵丹,但却是个救命药。网上解释很多不多说了。

thread_cache_size

实施难度:容易

实施时间:短

实施效果:一般

在使用 SHOW STATUS; 查看 mysql 参数时,如果 thread_created 这个值很高的话,可以将 thread_cache_size 设置得大一些。内存允许的情况下,128 或者更大都是可以考虑的。mysql 通过内建的线程复用机制来实现了一个连接池。如果你的应用出现 max connection 的情况话(php 发生这种情况尤为严重),还是请开启 thread_cache_size 吧。

索引

实施难度:一般

实施时间:一般

实施效果:明显

不知什么时候,有一位高人说“对于 where 查询的条件字段,都加上索引会提高查询效率”。于是大家忙不停的将所有可能的字段都加上了索引。潘多拉的魔盒从此打开……

上图:

nouse_index

这样的表中,假设 t2 的总记录数不超过10 条。如果 t2_c1 这个字段有这样的查询 select * from t1 where t2_c1 = 1; 不少童鞋都会在 t2_c1 上加多一个索引,为了让这个搜索更快一些。这会是真的么?

显然不是!

在 t2_c1 字段的数据差异很小的情况下,使用索引不会比全表扫描快。更有可能的情况是,索引不但导致 t1 表数据修改变慢,同时导致查询变慢。为什么?大家先学习一下“随机存取”和“连续预读”的差异就明白了。不必要的索引还是去掉吧!我甚至见过索引比数据都大的表,如果读索引的速度比直接读数据都慢,这会有什么后果?太可怕了……

只查要用到的列

实施难度:大

实施时间:长

实施效果:明显

这绝对是老生常谈,但是总有人不在意。他们心中有疑问:“为什么?为什么?为什么 SELECT * FROM table 会慢?”他们心中有梦想:“这不可能吧,扫描的都是那么多数据,那几个表。索引使用也一样有效。”

的确,数据扫描的记录数不会因为列的限制而减少,索引的影响也不因为列的限制而改变。不过每个内存页面中存放记录的条数会因为列的不同发不同。为了说明这个问题,我专门构造了一个 140万条记录,每条记录大约 50字节的表。如果应用只是用结果集的主键,使用 select * from table 查询比使用 select id from table 慢了近一倍。其实道理也很简单,结果集行记录变小了,内存页面中每个页面可以放的记录数就多了。内存页面的交换就减少,I/O减少。同时采用连续预读I/O效率提高。进而查询速度提升。

在业务逻辑都确定的情况下,每个方法所用到的字段也都确定了。这个时候可以快速将那些没有用到的字段从查询语句中剔除。查询效率自然提升。

按照上面的顺序进行快速优化,可以在不改变业务逻辑和代码逻辑的情况下迅速提升 mysql 性能,同时可避免应用长时间下下线,也为进一步优化争取时间。何乐而不为?

如果还有更快、更好的方法,我再补充吧!

“性能是改进出来的,不是设计出来的!”

Join the Conversation

2 Comments

  1. 总结的不错,学习了。如果开发人员在设计中针对索引使用更加的了解,充分理解“*”带来的灾难,性能就好很多了。不过,在开发中没有那么大的数据量,所以开发人员往往忽略了这些重要的问题。还有在表2中如果c1的int类型跟表1的t2_c1类型长度不一样,也会对查询速度有影响。

Leave a comment

Your email address will not be published. Required fields are marked *