• MySQL单条SQL语句性能评估


    MySQL单条SQL语句性能评估

    -基于《High Performance MySQL》第五章Profiling a Single Query

    很不幸,大部分MySQL指令对于评估一条SQL语句都不是很给力。虽然MySQL在这方面正在努力,不过目前为止,实际最好用的只有这两个命令:SHOW STATUS和SHOW PROFILE。

    SHOW PROFILE命令

    这个命令来自社区贡献,由Jeremy Cole提供,集成到了5.1以后的版本中。默认是没有开启这个命令支持的,需要用SET profiling = 1;来开启。开启以后,会输出任何命令的耗时和执行过程中的状态变化。每次执行命令的时候,评估数据会被记录到一个临时表中,这个表可以通过SHOW PROFILES;来看:

    clip_image002

    接着可以 SHOW PROFILE FOR QUERY 1;

    clip_image004
    评估表保存了SQL语句执行的每一步子过程耗时。这样直接从头到尾列出来不是很容易发现问题,可以用SQL计算做一个计算:

    >SET @query_id = 1;

    >SELECT STATE, SUM(DURATION) AS Total_R,

    ROUND(
    -> 100 * SUM(DURATION) /
    -> (SELECT SUM(DURATION)
    -> FROM INFORMATION_SCHEMA.PROFILING
    -> WHERE QUERY_ID = @query_id
    -> ), 2) AS Pct_R,
    -> COUNT(*) AS Calls,
    -> SUM(DURATION) / COUNT(*) AS "R/Call"
    -> FROM INFORMATION_SCHEMA.PROFILING
    -> WHERE QUERY_ID = @query_id
    -> GROUP BY STATE
    -> ORDER BY Total_R DESC;

    得到:

    clip_image006

    这样更容易发现最耗时的操作并针对性得调整SQL语句。有些过程比如"Sending Data",很难对应到具体如何优化,因为每一步操作基本都会涉及到发送数据,这种就只能先放放了。虽然我们得到了更细化的执行耗时,但其实这个命令不会告诉我们某个子工程为什么耗时。比如想要知道为什么"copying to tmp table"拷贝数据到临时表花了那么多时间,需要更进一步对这个子过程进行评估。

    SHOW STATUS命令

    SHOW STATUS返回各种计数,这些值有全局的(整个MySQL服务器),也有Session的(本次连接)。而如果用SHOW GLOBAL STATUS返回的计数都是全局的。SHOW STATUS返回的计数中哪些是全局的,哪些是本Session的,需要参考MySQL手册。

    SHOW STATUS不是真的评估工具,它仅仅返回MySQL的各种活动的计数。这些计数中只有一个Innodb_row_lock_time表示的时间,并且计数是全局的,所以也没啥用。

    所以我们要结合一个SQL语句执行的前后计数来猜测哪些动作比较耗费时间。最重要的计数是handler counters 和 temporary file and table counters。让我们先把计数清零,看看这个例子:

    > FLUSH STATUS;

    > SELECT * FROM sakila.nicer_but_slower_film_list;

    > SHOW STATUS WHERE Variable_name LIKE 'Handler%'

    OR Variable_name LIKE 'Created%';

    clip_image007

    clip_image008

    大概可以看出,这个SQL执行过程中,用了3次临时表——其中两个表在磁盘上,做了很多没有索引加速的都操作(Handler_read_rnd_next)。从这个结果猜测,可能这个select查询了一个view,此view需要执行一个未加索引的join。

    要注意SHOW STATUS操作本身自己就会出发一些计数增加,比如说写两次表格,所以前面一条SQL语句对应的临时表的操作计数应该在结果上减去2。

    这得注意的是,SHOW STATUS得到的信息可能和EXPLAIN差不多,但EXPLAIN只是预测,并不是真是执行的结果。EXPLAIN不会告诉你临时表是在内存还是在磁盘这种重要信息。

    耗时SQL语句日志

    MySQL可以在日志中记录耗时的SQL操作,Percona Server(MySQL fork出来的另外开源实现)记录的更细。以SHOW PROFILE章节中的SQL语句为例,Log是这样的:

    clip_image009从中可以看出,这条语句执行过程中创建了3个临时表,其中两个表在磁盘上。

    相比于SHOW STATUS和SHOW PROFILE,耗时SQL语句日志记录更详细的信息,特别是配合pt-query-digest日志分析工具,你可以从日志中方便找到对应的SQL语句的位置。Pt-query-digist可以为SQL语句输出统计头:

    # Query 1: 0 QPS, 0x concurrency, ID 0xEE758C5E0D7EADEE at byte 3214 _____

    然后用shell命令就能从日志文件中拉出对应的日志:

    tail -c +3214 /path/to/query.log | head -n100

    全局性能统计(Performance Schema)

    全局性能统计在MySQL5.5中开始引入,虽然5.5版本中不支持SQL语句级别的统计,但还是能提供一些有用的信息,比如:

    > SELECT event_name, count_star, sum_timer_wait

    -> FROM events_waits_summary_global_by_event_name

    -> ORDER BY sum_timer_wait DESC LIMIT 5;

    得到:

    clip_image011

    5.6以后的版本,应该会更有用。

  • 相关阅读:
    luogu 2962 [USACO09NOV]灯Lights
    bzoj 1923
    bzoj 1013
    bzoj 3513
    bzoj 4259
    bzoj 4503
    CF 632E
    bzoj 3527
    bzoj 3160
    bzoj 2179
  • 原文地址:https://www.cnblogs.com/jan4984/p/4551842.html
Copyright © 2020-2023  润新知