zoukankan      html  css  js  c++  java
  • mysql慢查询

    mysql 开启慢查询日志 
    
    MySQL加速查询速度的独门武器:查询缓存
    
    对mysql查询缓存从五个角度进行详细的分析:Query Cache的工作原理、如何配置、如何维护、如何判断查询缓存的性能、适合的业务场景分析。
    
    
    n  工作原理
    
    查询缓存的工作原理,基本上可以用二句话概括:
    
    l  缓存SELECT操作或预处理查询(注释:5.1.17开始支持)的结果集和SQL语句;
    
    l  新的SELECT语句或预处理查询语句,先去查询缓存,判断是否存在可用的记录集,判断标准:与缓存的SQL语句,是否完全一样,区分大小写;
    
    查询缓存对什么样的查询语句,无法缓存其记录集,大致有以下几类:
    
    l  查询语句中加了SQL_NO_CACHE参数;
    
    l  查询语句中含有获得值的函数,包涵自定义函数,如:CURDATE()、GET_LOCK()、RAND()、CONVERT_TZ等;
    
    l  对系统数据库的查询:mysql、information_schema
    
    l  查询语句中使用SESSION级别变量或存储过程中的局部变量;
    
    l  查询语句中使用了LOCK  IN SHARE MODE、FOR UPDATE的语句
    
    l  查询语句中类似SELECT …INTO 导出数据的语句;
    
    l  事务隔离级别为:Serializable情况下,所有查询语句都不能缓存;
    
    l  对临时表的查询操作;
    
    l  存在警告信息的查询语句;
    
    l  不涉及任何表或视图的查询语句;
    
    l  某用户只有列级别权限的查询语句;
    
    查询缓存的优缺点:
    
    l  不需要对SQL语句做任何解析和执行,当然语法解析必须通过在先,直接从Query  Cache中获得查询结果;
    
    l  查询缓存的判断规则,不够智能,也即提高了查询缓存的使用门槛,降低其效率;
    
    l  Query Cache的起用,会增加检查和清理Query Cache中记录集的开销,而且存在SQL语句缓存的表,每一张表都只有一个对应的全局锁;
    
    n  配置
    
            是否启用mysql查询缓存,可以通过2个参数:query_cache_type和query_cache_size,其中任何一个参数设置为0都意味着关闭查询缓存功能,但是正确的设置推荐query_cache_type=0。
    
    l  query_cache_type
    
    值域为:0 -– 不启用查询缓存;
    
    值域为:1 -– 启用查询缓存,只要符合查询缓存的要求,客户端的查询语句和记录集斗可以缓存起来,共其他客户端使用;
    
    值域为:2 -– 启用查询缓存,只要查询语句中添加了参数:SQL_CACHE,且符合查询缓存的要求,客户端的查询语句和记录集,则可以缓存起来,共其他客户端使用;
    
    l  query_cache_size
    
    允许设置query_cache_size的值最小为40K,对于最大值则可以几乎认为无限制,实际生产环境的应用经验告诉我们,该值并不是越大,查询缓存的命中率就越高,也不是对服务器负载下降贡献大,反而可能抵消其带来的好处,甚至增加服务器的负载,至于该如何设置,下面的章节讲述,推荐设置为:64M;
    
    l  query_cache_limit
    
    限制查询缓存区最大能缓存的查询记录集,可以避免一个大的查询记录集占去大量的内存区域,而且往往小查询记录集是最有效的缓存记录集,默认设置为1M,建议修改为16k~1024k之间的值域,不过最重要的是根据自己应用的实际情况进行分析、预估来设置;
    
    l  query_cache_min_res_unit
    
    设置查询缓存分配内存的最小单位,要适当地设置此参数,可以做到为减少内存块的申请和分配次数,但是设置过大可能导致内存碎片数值上升。默认值为4K,建议设置为1k~16K
    
    l  query_cache_wlock_invalidate
    
    该参数主要涉及MyISAM引擎,若一个客户端对某表加了写锁,其他客户端发起的查询请求,且查询语句有对应的查询缓存记录,是否允许直接读取查询缓存的记录集信息,还是等待写锁的释放。默认设置为0,也即允许;
    
    n  维护
    
    l  查询缓存区的碎片整理
    
        查询缓存使用一段时间之后,一般都会出现内存碎片,为此需要监控相关状态值,并且定期进行内存碎片的整理,碎片整理的操作语句:FLUSH QUERY CACHE;
    
    l  清空查询缓存的数据
    
    那些操作操作可能触发查询缓存,把所有缓存的信息清空,以避免触发或需要的时候,知道如何做,二类可触发查询缓存数据全部清空的命令:
    
    (1).     RESET QUERY CACHE;
    
    (2).     FLUSH TABLES;
    
    n  性能监控
    
    l  碎片率
    
    查询缓存内存碎片率=Qcache_free_blocks / Qcache_total_blocks * 100%
    
    l  命中率
    
    查询缓存命中率=Qcache_hits/(Qcache_hits + Qcache_inserts)  * 100%
    
    l  内存使用率
    
    查询缓存内存使用率=(query_cache_size – Qcache_free_memory) / query_cache_size * 100%
    
    l  Qcache_lowmem_prunes
    
    该参数值对于检测查询缓存区的内存大小设置是否,有非常关键性的作用,其代表的意义为:查询缓存去因内存不足而不得不从查询缓存区删除的查询缓存信息,删除算法为LRU;
    
    l  query_cache_min_res_unit
    
        内存块分配的最小单元非常重要,设置过大可能增加内存碎片的概率发生,太小又可能增加内存分配的消耗,为此在系统平稳运行一个阶段性后,可参考公式的计算值:
    
    查询缓存最小内存块 = (query_cache_size – Qcache_free_memory) / Qcache_queries_in_cache
    
    l  query_cache_size
    
    我们如何判断query_cache_size是否设置过小,依然也只有先预设置一个值,推荐为:32M~128M之间的区域,待系统平稳运行一个时间段(至少1周),并且观察这周内的相关状态值:
    
    (1).     Qcache_lowmem_prunes;
    
    (2).     命中率;
    
    (3).     内存使用率;
    
        若整个平稳运行期监控获得的信息,为命中率高于80%,内存使用率超过80%,并且Qcache_lowmem_prunes的值不停地增加,而且增加的数值还较大,则说明我们为查询缓冲区分配的内存过小,可以适当地增加查询缓存区的内存大小;
    
        若是整个平稳运行期监控获得的信息,为命中率低于40%,Qcache_lowmem_prunes的值也保持一个平稳状态,则说明我们的查询缓冲区的内存设置过大,或者说业务场景重复执行一样查询语句的概率低,同时若还监测到一定量的freeing items,那么必须考虑把查询缓存的内存条小,甚至关闭查询缓存功能;
    
    n  业务场景
    
    通过上述的知识梳理和分析,我们至少知道查询缓存的以下几点:
    
    l  查询缓存能够加速已经存在缓存的查询语句的速度,可以不用重新解析和执行而获得正确得记录集;
    
    l  查询缓存中涉及的表,每一个表对象都有一个属于自己的全局性质的锁;
    
    l  表若是做DDL、FLUSH TABLES 等类似操作,触发相关表的查询缓存信息清空;
    
    l  表对象的DML操作,必须优先判断是否需要清理相关查询缓存的记录信息,将不可避免地出现锁等待事件;
    
    l  查询缓存的内存分配问题,不可避免地产生一些内存碎片;
    
    l  查询缓存对是否是一样的查询语句,要求非常苛刻,而且还不智能;
    
        我们再重新回到本节的重点上,查询缓存适合什么样的业务场景呢?只要是清楚了查询缓存的上述优缺点,就不难罗列出来,业务场景要求:
    
    l  整个系统以读为主的业务,比如门户型、新闻类、报表型、论坛等网站;
    
    l  查询语句操作的表对象,非频繁地进行DML操作,可以使用query_cache_type=2模式,然后SQL语句加SQL_CACHE参数指定;
    
    
    /*
        SHOW VARIABLES LIKE '%SLOW%';
        SET GLOBAL LOG_SLOW_QUERIES=ON
        SET SLOW_QUERY_LOG=ON
        SET long_query_TIME=1  --单位是秒
    */
    优化MySQL最重要的一部分工作是先确定”有问题”的查询语句。只有先找出这些查询较慢的sql查询(执行时间较长),我们才能进一步分析原因并且优化它。MySQL为我们提供了Slow Query Log记录功能,它能记录执行时间超过了特定时长的查询。分析Slow Query Log有助于帮我们找到”问题”查询。记录slow queries
     
    首先,我们需要查看mysql server版本号,以及是否配置启用了slow query log。
     
    #打开服务
     log_slow_queries = ON
     
    当log_slow_queries是ON时,才表示已经启用了记录slow query功能。默认是不记录slow query的。
     启用slow query日志
     #//将下列配置放到my.cnf中
     [mysqld]
     log-slow-queries = /var/lib/mysql/slow-queries.log
     
    //新增加的参数
     long_query_time = 3
     log-queries-not-using-indexes
     log-slow-admin-statements 
    
    上面的配置打开了slow query日志,将会捕获了执行时间超过了3秒的查询,包括执行速度较慢的管理命令(比如OPTIMEZE TABLE),并且记录了没有使用索引的查询。这些SQL,都会被记录到log-slow-queries指定的文件/var/lib/mysql/slow-queries.log文件中。
     log-slow-queries <slow_query_log_file>
     存放slow query日志的文件。你必须保证mysql server进程mysqld_safe进程用户对该文件有w权限。
     long_query_time
     如果query time超过了该值,则认为是较慢查询,并被记录下来。单位是秒,最小值是1,默认值是10秒。10秒对于大多数应用来讲,太长了。我们推荐从3秒开始, 依次减少,每次都找出最”昂贵”的10条SQL语句并且优化他们。日复一日,一步一步优化。一次性找出很多条SQL语句,对于优化来讲,意义并不大。
     log-queries-not-using-indexes
     MySQL会将没有使用索引的查询记录到slow query日志中。无论它执行有多快,查询语句没有使用索引,都会被记录。有的时候,有些没有使用引索的查询非常快(例如扫描很小的表),但也有可能导致服务器变慢,甚至还会使用大量的磁盘空间。
     log-slow-admin-statements
     一些管理指令,也会被记录。比如OPTIMEZE TABLE, ALTER TABLE等等。
     日志文件
     
    MySQL5.1中,提供了全局变量slow_query_log、slow_query_log_file可以灵活地控制enable/disable慢查询。同时可以通过long_query_time设置时间
     #//停用slow query记录
     #注意:设置了slow_query_log全局变量, log_slow_queries也会隐性地跟着改变
     mysql>set global slow_query_log=OFF
     
    我们可以通过tail -f查看日志文件。
     $tail -f /var/lib/mysql/slow-queries.log
     # Time: 110107 16:22:11
     # User@Host: root[root] @ localhost []
     # Query_time: 9.869362 Lock_time: 0.000035 Rows_sent: 1 Rows_examined: 6261774
     SET timestamp=1294388531;
     select count(*) from ep_friends;
     
    第一行,SQL查询执行的时间
     第二行,执行SQL查询的连接信息
     第三行记录了一些我们比较有用的信息
     Query_time SQL执行的时间,越长则越慢
     Lock_time 在MySQL服务器阶段(不是在存储引擎阶段)等待表锁时间
     Rows_sent 查询返回的行数
     Rows_examined 查询检查的行数
     Slow Query日志,虽然帮助你记录了那些执行过了的SQL语句。但它不是万能的,意义可能没有你想象的那么大。它只告诉了你哪些语句慢,但是为什么慢?具体 原因,还是需要你自己去分析,不断的调试。也许,你只需要换一条更有效的sql语句,也许你只需简单地增加一个索引,但也有可能你需要调整你应用程序的设 计方案。比如,上面那条语句是很明显,它检查了600多万行数据。不幸的是,并不是每条语句都这么明显。也许还有别的原因,比如:
     *锁表了,导致查询处于等态状态。lock_time显示了查询等待锁被翻译的时间
     *数据或索引没有被缓存。常见于第一次启动服务器或者服务器没有调优
     *备份数据库,I/O变慢
     *也许同时运行了其它的查询,减少了当前查询
    MySQL5.1可以在运行时改变日记行为,将日志记录到数据库表中。只要将mysql全局变量log_output设置为 TABLE即可。MySQL会将日志分别记录到表mysql.gengera_log和mysql.slow_log二张表中。但是,我们推荐将日志记录 在日记文件中。
     mysql> show variables like ‘log_output’G
     Variable_name: log_output
     Value: FILE
     mysql>set global log_output=table’;
     缺陷与审记
     
    虽然记录了slow query能够帮助你优化产品。但是MySQL目前版本,还有几大蹩足的地方。
     1.MySQL5.0版本, long_query_time时间粒度不够细,最小值为1秒。对于高并发性能的网页脚本而言,1秒出现的意义不大。即出现1秒的查询比较少。直到mysql5.1.21才提供更细粒度的long_query_time设定.
     2.不能将服务器执行的所有查询记录到慢速日志中。虽然MySQL普通日志记录了所有查询,但是它们是解析查询之前就记录下来了。这意味着普通日志没办法包含诸如执行时间,锁表时间,检查行数等信息。
     3.如果开启了log_queries_not_using_indexes选项,slow query日志会充满过多的垃圾日志记录,这些快且高效的全表扫描查询(表小)会冲掉真正有用的slow queries记录。比如select * from category这样的查询也会被记录下来。
     
    通过microslow-patch补丁可使用更细的时间粒度,和记录所有执行过的sql语句。不过,使用这个补订不得不自己编译MySQL,出于稳定性考滤,我们推荐在开发测试环境,可以打上这个补丁,享受这个补丁带来的便利。在运营环境尽量不要这么做…
     
    MySQL自带了mysqldumpslow工具用来分析slow query日志,除此之外,还有一些好用的开源工具。比如MyProfi、mysql-log-filter,当然还有mysqlsla
  • 相关阅读:
    如何加快github下载代码的速度
    还原 对于 服务器“ZHULIN-DB-DEV”失败。 (Microsoft.SqlServer.SmoExtended)
    sqlserver 常用语句
    sql 中 rank() over,dense_rank(),row_number() 的区别
    sqlserver 算两个日期间的月份数
    理解http的幂等性
    学习的第一推动力(很好)
    clean-room 洁净室软件工程
    如何组建测试团队
    vscode go 调试 launch.json
  • 原文地址:https://www.cnblogs.com/zhaowenzhong/p/5164322.html
Copyright © 2011-2022 走看看