LAMP 系统性能调优:第3 部分: mysql -学习笔记


首先,mysql调优有三个主要的方式,由低到高分别是:



1、硬件调优


2、修改mysql进程


3、优化mysql查询


一 硬件调优

  先看看硬件调优吧。这个有两方面你可以考虑,首先对现有硬件条件进行修复,能调整的调整,能替换的替换,例如你可以把中央处理器(CPU)或磁盘速度加倍,也可以让内存增大 4 到 8 倍。或者你可以替换掉有问题的硬件。其次,如果你的预算没有限制,那么你干脆可以无限制的增加你的服务器大笑。不过这种解决方案也就仅限于此了。

二、修改mysql进程

   也就是对mysqld进行调优,对这个进程进行调优意味着适当地分配内存,并让 mysqld 了解将会承受何种类型的负载。加快磁盘运行速度不如减少所需的磁盘访问次数。类似地,确保 MySQL 进程正确操作就意味着它花费在服务查询上的时间要多于花费在处理后台任务(如处理临时磁盘表或打开和关闭文件)上的时间。

三、查询优化


       这个是最好的方法啦,这意味着对表应用了适当的索引,查询是按照可以充分利用 MySQL 功能的方式来编写的。可以配置 mysqld 来报告可能需要进行调优的查询。


       如何调优呢,具体方法如下:


       a、记录慢速查询


             啥是慢速查询呢:执行时间超过给定时间范围的查询就称为慢速查询。您可以配置mysqld 将这些慢速查询记录到适当命名的慢速查询日志中。然后你日后可以通过观察这些日志,来决定哪些部分需要调整。你需要在 my.cnf 中所做如下配置。




            my.cnf中添加如下配置


[plain] view plaincopy

[mysqld]  

; enable the slow query log, default 10 seconds  

log-slow-queries  

; log queries taking longer than 5 seconds  

long_query_time = 5  

; log queries that don't use indexes even if they take less than long_query_time  

; MySQL 4.1 and newer only  

log-queries-not-using-indexes  


下面解释下上面的代码:

           这三个设置一起使用,可以记录执行时间超过 5 秒和没有使用索引的查询。请注意有关log-queries-not-using-indexes 的警告。慢速查询日志都保存在 MySQL 数据目录中,名为 hostname-slow.log。如果希望使用一个不同的名字或路径,可以在 my.cnf 中使用log-slow-queries = /new/path/to/file 实现此目的。


   mysqldumpslow ,你可以通过此命令来查看慢查询日志 


   [root@ mysql-5.0.37]# mysqldumpslow /data/mysql-db/slow_queries.log -t 10  

Reading mysql slow query log from /data/mysql-db/slow_queries.log  

Count: 1  Time=763486.00s (763486s)  Lock=0.00s (0s)  Rows=0.0 (0), *********  

SET insert_id=N;  

INSERT INTO `nike`.`nike_countlog_index` (`userId`, `action`, `model`, `info`, `cTime`, `ip`, `isRen`)   

VALUES ('S', 'S', 'S', 'S', 'S', 'S', 'S')  


   b、对查询进行缓存


             又是缓存哈,大多数LAMP应用都严重依赖于数据库查询,查询的大致过程如下:


             PHP 发出查询请求->数据库收到指令对查询语句进行分析->确定如何查询->从磁盘中加载信息->返回结果


            看到了吧,如果你反复查询,他就反复执行这些。MySQL 有一个特性称为查询缓存,他可以将查询的结果保存在内存中,在很多情况下,这会极大地提高性能。不过,问题是查询缓存在默认情况下是禁用的。


            将query_cache_size = 32M 添加到 /etc/my.conf 中可以启用 32MB 的查询缓存。


               b、对查询进行缓存


             又是缓存哈,大多数LAMP应用都严重依赖于数据库查询,查询的大致过程如下:


             PHP 发出查询请求->数据库收到指令对查询语句进行分析->确定如何查询->从磁盘中加载信息->返回结果


            看到了吧,如果你反复查询,他就反复执行这些。MySQL 有一个特性称为查询缓存,他可以将查询的结果保存在内存中,在很多情况下,这会极大地提高性能。不过,问题是查询缓存在默认情况下是禁用的。


            将query_cache_size = 32M 添加到 /etc/my.conf 中可以启用 32MB 的查询缓存。


            在启动了查询缓存以后,我们最重要的是要知道他确实起作用了,mysql提供如下查看方法

            mysql> SHOW STATUS LIKE 'qcache%';  

+-------------------------+------------+  

| Variable_name           | Value      |  

+-------------------------+------------+  

| Qcache_free_blocks      | 5216       |  

| Qcache_free_memory      | 14640664   |  

| Qcache_hits             | 2581646882 |  

| Qcache_inserts          | 360210964  |  

| Qcache_lowmem_prunes    | 281680433  |  

| Qcache_not_cached       | 79740667   |  

| Qcache_queries_in_cache | 16927      |  

| Qcache_total_blocks     | 47042      |  

+-------------------------+------------+  

8 rows in set (0.00 sec)  


通常间隔几秒显示这些变量你就会看出不同来,运行FLUSH STATUS 可以重置一些计数器,如果服务器已经运行了一段时间,这会非常有帮助。

         缓存当然也不是越大越多越好,当缓存占用内存过多,那么服务一样很慢。作为一条规则,如果FLUSH QUERY CACHE占用了很长时间,那就说明缓存太大了。



       c、强制限制


        您可以在mysqld 中强制一些限制来确保系统负载不会导致资源耗尽的情况出现。


       例如你可以在my.cn中加入以下限制:


       [plain] view plaincopy

set-variable=max_connections=500  

set-variable=wait_timeout=10  

max_connect_errors = 100  


      解释下哈:

      第一行:最大连接数,在服务器没有崩溃之前确保只建立服务允许数目的连接,要确定服务器上目前建立过的最大连接数,请执行:


     SHOW STATUS LIKE 'max_used_connections'


     


     第二行:mysqld将终止等待时间(空闲时间)超过10秒的连接。在 LAMP 应用程序中,连接数据库的时间通常就是 Web 服务器处理请求所花费的时间。有时候,如果负载过重,连接会挂起,并且会占用连接表空间。如果有多个交互用户或使用了到数据库的持久连接,那么将这个值设低一点并不可取!


     第三行:如果一个主机在连接到服务器时有问题,并重试很多次后放弃,那么这个主机就会被锁定,直到FLUSH HOSTS 之后才能运行。默认情况下,10 次失败就足以导致锁定了。将这个值修改为 100 会给服务器足够的时间来从问题中恢复。如果重试 100 次都无法建立连接,那么使用再高的值也不会有太多帮助,可能它根本就无法连接



     d、缓冲区和缓存

             mysql有超过100个可以调节的设置,要记住那么基本是不可能的,但是幸运的是你只需要记住很少一部分你就可以基本满足你的需求了,我们还可以通过“SHOW STATUS”命令来查看mysql是否按照我们的期望运行着得意。


            MySQL 可调节设置可以应用于整个mysqld 进程,也可以应用于单个客户机会话。


           服务器端的设置


           表缓存


            数据库中的每个表存储在一个文件中,要读取文件的内容,你必须先打开文件,然后再读取。为了加快从文件中读取数据的过程,mysqld 对这些打开文件进行了缓存,其最大数目由 /etc/mysqld.conf 中的 table_cache 指定


            例如:


      SHOW STATUS LIKE 'open%tables';

           


            上图说明:有1504个打开的文件,有0个表需要打开,如果你每次重新执行 SHOW TABLE LIKE "open%tables";open_tables 的变化很大,说明该缓存的命中率不高。


            线程缓存            

       SHOW STATUS LIKE 'threads%';       

            


            这里主要看Threads_created,如果重复执行SHOW STATUS LIKE  "threads%"时,这个值增长的非常快,那么你可以考虑在my.cnf中加大线程缓存,例如:thread_cache = 40 。


             关键字缓存            


show status like '%key_read%';

            

            关键字,理想情况下对于他的请求应该来自于内存而不是磁盘,从这个表中我们可以看出有多少是Key_reads 代表命中磁盘的请求个数,Key_read_requests 是总数, 命中磁盘的读请求数除以读请求总数就是不中比率 ―― 在本例中每 1,000 个请求,大约有 0.6 个没有命中内存。如果每 1,000 个请求中命中磁盘的数目超过 1 个,就应该考虑增大关键字缓冲区了。例如,key_buffer = 384M 会将缓冲区设置为 384MB。


           确定临时表的使用          


SHOW STATUS LIKE 'created_tmp%';

           

          每次使用临时表都会增大 Created_tmp_tables;基于磁盘的表也会增大 Created_tmp_disk_tables。对于这个比率,并没有什么严格的规则,因为这依赖于所涉及的查询。长时间观察Created_tmp_disk_tables 会显示所创建的磁盘表的比率,您可以确定设置的效率。tmp_table_size 和max_heap_table_size 都可以控制临时表的最大大小,因此请确保在 my.cnf 中对这两个值都进行了设置。



           每个会话的设置


            下面我要说的设置是针对每个会话的,所以你要小心啦,因为对于同一个服务器,有可能有百万级个会话同时进行着。


           排序


            首先说下排序,mysql是这么处理排序的,首先从磁盘上读取数据,然后分配一块缓存区来缓存这些数据。如果要排序的数据太大,那么数据就必须保存到磁盘上的临时文件中,并再次进行排序。


SHOW STATUS LIKE "sort%";

             


             如果sort_merge_passes 很大,就表示需要注意sort_buffer_size。例如, sort_buffer_size = 4M 将排序缓冲区设置为 4MB。


           查询


           MySQL 也会分配一些内存来读取表。理想情况下,索引提供了足够多的信息,可以只读入所需要的行,但是有时候查询(设计不佳或数据本性使然)需要读取表中大量数据。要理解这种行为,需要知道运行了多少个SELECT 语句,以及需要读取表中的下一行数据的次数(而不是通过索引直接访问)。可以通过: 


SHOW STATUS LIKE "com_select";  

SHOW STATUS LIKE "handler_read_rnd_next"; 

           

          


Handler_read_rnd_next /Com_select 得出了表扫描比率 ―― 在本例中是 521:1。如果该值超过 4000,就应该查看read_buffer_size,例如read_buffer_size = 4M。如果这个数字超过了 8M,就应该与开发人员讨论一下对这些查询进行调优了!




         其他有用的工具


      mytop :是mysql对linux的top命令的模拟。算得上是服务器的健康快照啦。


    mysqlard : 负责每 5 分钟搜集一次数据,并将它们存储到后台的一个 Round Robin Database 中。有一个 Web 页面会显示这些数据,例如表缓存的使用情况、关键字效率、连接上的客户机以及临时表的使用情况。


     mysqlreport:其报告要远比mysqlard 更加复杂,因为需要对服务器的每个方面都进行分析。这是对服务器进行调优的一个非常好的工具,因为它对状态变量进行适当计算来帮助确定需要修正哪些问题。


      以上这三个工具有空试试吧,我也木用过大笑   




(一)连接

连接通常来自Web服务器,下面列出了一些与连接有关的参数,以及该如何设置它们。

1、max_connections

这是Web服务器允许的最大连接数,记住每个连接都要使用会话内存(关于会话内存,文章后面有涉及)。

2、max_packet_allowed

最大数据包大小,通常等于你需要在一个大块中返回的最大数据集的大小,如果你在使用远程mysqldump,那它的值需要更大。

3、aborted_connects

检查系统状态的计数器,确定其没有增长,如果数量增长说明客户端连接时遇到了错误。

4、thread_cache_size

入站连接会在MySQL中创建一个新的线程,因为MySQL中打开和关闭连接都很廉价,速度也快,它就没有象其它数据库,如Oracle那么多持续连接了,但线程预先创建并不会节约时间,这就是为什么要MySQL线程缓存的原因了。

如果在增长请密切注意创建的线程,让你的线程缓存更大,对于2550或100的thread_cache_size,内存占用也不多。

(二)查询缓存

MySQL中的缓存查询包括两个解析查询计划,以及返回的数据集,如果基础表数据或结构有变化,将会使查询缓存中的项目无效。

1、query_cache_min_res_unit

MySQL参数中query_cache_min_res_unit查询缓存中的块是以这个大小进行分配的,使用下面的公式计算查询缓存的平均大小,根据计算结果设置这个变量,MySQL就会更有效地使用查询缓存,缓存更多的查询,减少内存的浪费。 

2、query_cache_size

这个参数设置查询缓存的总大小。

3、query_cache_limit

这个参数告诉MySQL丢掉大于这个大小的查询,一般大型查询还是比较少见的,如运行一个批处理执行一个大型报表的统计,因此那些大型结果集不应该填满查询缓存。

qcache hit ratio = qcache_hits / (qcache_hits + com_select)

使用

SQL> show status like 'qcache%';

SQL> show status like 'com_%';

找到这些变量。

average query size = (query_cache_size - qcache_free_memory)/qcache_queries_in_cache

使用

SQL> show variables like 'query%';

qcache_* status variables you can get with:

SQL> show status like 'qcache%';

获取query_cache_size的值。

(三)临时表

内存速度是相当快的,因此我们希望所有的排序操作都在内存中进行,我们可以通过调整查询让结果集更小以实现内存排序,或将变量设置得更大。

tmp_table_size

max_heap_table_size

无论何时在MySQL中创建临时表,它都会使用这两个变量的最小值作为临界值,除了在磁盘上构建临时表外,还会创建许多会话,这些会话会抢占有限制的资源,因此最好是调整查询而不是将这些参数设置得更高,同时,需要注意的是有BLOB或TEXT字段类型的表将直接写入磁盘。  深入浅出MySQL双向复制技术

(四)会话内存

MySQL中每个会话都有其自己的内存,这个内存就是分配给SQL查询的内存,因此你想让它变得尽可能大以满足需要。但你不得不平衡同一时间数据库内一致性会话的数量。这里显得有点黑色艺术的是MySQL是按需分配缓存的,因此,你不能只添加它们并乘以会话的数量,这样估算下来比MySQL典型的使用要大得多。最佳做法是启动MySQL,连接所有会话,然后继续关注顶级会话的VIRT列,mysqld行的数目通常保持相对稳定,这就是实际的内存总用量,减去所有的静态MySQL内存区域,就得到了实际的所有会话内存,然后除以会话的数量就得到平均值。

1、read_buffer_size

缓存连续扫描的块,这个缓存是跨存储引擎的,不只是MyISAM表。

2、sort_buffer_size

执行排序缓存区的大小,最好将其设置为1M-2M,然后在会话中设置,为一个特定的查询设置更高的值。

3、join_buffer_size

执行联合查询分配的缓存区大小,将其设置为1M-2M大小,然后在每个会话中再单独按需设置。

4、read_rnd_buffer_size

用于排序和order by操作,最好将其设置为1M,然后在会话中可以将其作为一个会话变量设置为更大的值。

(五)慢速查询日志

慢速查询日志是MySQL很有用的一个特性。

1、log_slow_queries

MySQL参数中log_slow_queries参数在my.cnf文件中设置它,将其设置为on,默认情况下,MySQL会将文件放到数据目录,文件以“主机名-slow.log”的形式命名,但你在设置这个选项的时候也可以为其指定一个名字。

2、long_query_time

默认值是10秒,你可以动态设置它,值从1到将其设置为on,如果数据库启动了,默认情况下,日志将关闭。截至5.1.21和安装了Google补丁的版本,这个选项可以以微秒设置,这是一个了不起的功能,因为一旦你消除了所有查询时间超过1秒的查询,说明调整非常成功,这样可以帮助你在问题变大之前消除问题SQL。

3、log_queries_not_using_indexes

开启这个选项是个不错的主意,它真实地记录了返回所有行的查询。

小结

参考博客:http://wyfirst.blog.51cto.com/835701/197774

http://blog.csdn.net/yananwang/article/details/7030029

你可能感兴趣的:(mysql)