使用pt-query-digest分析慢查询

pt-query-digest是Percona工具包的一部分,用于对查询进行分析。可以通过以下任何方式收集查询:

  • 慢查询日志
  • 通用查询日志
  • 进程列表
  • 二进制日志
  • TCP转储

慢查询日志

首先要开启慢查询日志并收集查询,然后就可以通过传递慢查询日志来运行pt-query-digest。

通过修改配置文件,打开慢查询日志

  1. [root@www mysql]# vim /etc/my.cnf
  2. [mysqld]
  3. #slow_log
  4. slow_query_log=on #开启
  5. slow_query_log_file=/var/lib/mysql/www-slow.log #日志文件
  6. long_query_time = 0.001 #为了测试,定义超过0.001秒的就记录
  7. log_queries_not_using_indexes = on #设置对未使用索引的SQL进行记录

做几次查询,生成慢查询日志后,使用工具进行分析

  1. [root@www mysql]# pt-query-digest /var/lib/mysql/www-slow.log > /root/query_digest

摘要报告(digest report)中的查询按照查询执行的次数与查询时间的乘积排列。所有查询的详细信息,例如查询校验和(每种查询类型有一个唯一的值)、平均时间、百分比时间和执行次数等都会显示出来。可以通过搜索查询校验和来深入研究特定查询。

摘要报告的内容如下所示:

  1. [root@www ~]# cat query_digest
  2. # 40ms user time, 420ms system time, 26.11M rss, 224.43M vsz
  3. # Current date: Sun Oct 6 16:28:28 2019
  4. # Hostname: www.lnmp.com
  5. # Files: /var/lib/mysql/www-slow.log
  6. # Overall: 2 total, 1 unique, 0.03 QPS, 0.00x concurrency ________________
  7. # Time range: 2019-10-06T08:21:13 to 2019-10-06T08:22:31
  8. # Attribute total min max avg 95% stddev median
  9. # ============ ======= ======= ======= ======= ======= ======= =======
  10. # Exec time 247ms 73ms 174ms 123ms 174ms 72ms 123ms
  11. # Lock time 331us 124us 207us 165us 207us 58us 165us
  12. # Rows sent 38.74k 5.53k 33.21k 19.37k 33.21k 19.57k 19.37k
  13. # Rows examine 585.98k 292.99k 292.99k 292.99k 292.99k 0 292.99k
  14. # Query size 146 73 73 73 73 0 73
  15. #对此查询的分析如下所示:
  16. # Profile
  17. # Rank Query ID Response time Calls R/Call V/M Item
  18. # ==== ================== ============= ===== ====== ===== ===============
  19. # 1 0x8D07475FE113B1C0 0.2466 100.0% 2 0.1233 0.04 SELECT employees
  20. #对于#1查询(0x8D07475FE113B1C0),其所有的执行累计响应时间为0.2466秒,
  21. #占全部查询的累计响应时间的100%。执行次数为2次
  22. #平均查询时间为0.1233秒
  23. # Query 1: 0.03 QPS, 0.00x concurrency, ID 0x8D07475FE113B1C0 at byte 0 __
  24. # This item is included in the report because it matches --limit.
  25. # Scores: V/M = 0.04
  26. # Time range: 2019-10-06T08:21:13 to 2019-10-06T08:22:31
  27. # Attribute pct total min max avg 95% stddev median
  28. # ============ === ======= ======= ======= ======= ======= ======= =======
  29. # Count 100 2
  30. # Exec time 100 247ms 73ms 174ms 123ms 174ms 72ms 123ms
  31. # Lock time 100 331us 124us 207us 165us 207us 58us 165us
  32. # Rows sent 100 38.74k 5.53k 33.21k 19.37k 33.21k 19.57k 19.37k
  33. # Rows examine 100 585.98k 292.99k 292.99k 292.99k 292.99k 0 292.99k
  34. # Query size 100 146 73 73 73 73 0 73
  35. # String:
  36. # Databases employees
  37. # Hosts localhost
  38. # Users root
  39. # Query_time distribution
  40. # 1us
  41. # 10us
  42. # 100us
  43. # 1ms
  44. # 10ms ################################################################
  45. # 100ms ################################################################
  46. # 1s
  47. # 10s+
  48. # Tables
  49. # SHOW TABLE STATUS FROM `employees` LIKE 'employees'\G
  50. # SHOW CREATE TABLE `employees`.`employees`\G
  51. # EXPLAIN /*!50100 PARTITIONS*/
  52. select first_name,last_name from employees where hire_date > '1998-01-01'\G

通用查询日志

可以使用pt-query-digest通过传递参数–type genlog来分析通用查询日志。由于通用日志不报告查询的次数,因此只显示累计的数字:

  1. mysql> set global general_log = 'ON';
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> show variables like '%general_log%';
  4. +------------------+------------------------+
  5. | Variable_name | Value |
  6. +------------------+------------------------+
  7. | general_log | ON |
  8. | general_log_file | /var/lib/mysql/www.log |
  9. +------------------+------------------------+
  10. 2 rows in set (0.00 sec)

做几次查询后,生成日志并使用工具进行分析

  1. [root@www mysql]# pt-query-digest --type genlog /var/lib/mysql/www.log > /root/general_query_digest

结果如下:

  1. [root@www ~]# cat general_query_digest
  2. # 110ms user time, 10ms system time, 25.58M rss, 220.06M vsz
  3. # Current date: Sun Oct 6 16:58:45 2019
  4. # Hostname: www.lnmp.com
  5. # Files: /var/lib/mysql/www.log
  6. # Overall: 7 total, 4 unique, 0 QPS, 0x concurrency ______________________
  7. # Time range: 2019-10-06T08:55:42.298155Z to 2019-10-06T08:57:26.314967Z
  8. # Attribute total min max avg 95% stddev median
  9. # ============ ======= ======= ======= ======= ======= ======= =======
  10. # Exec time 0 0 0 0 0 0 0
  11. # Query size 489 29 209 69.86 202.40 57.22 34.95
  12. # Profile
  13. # Rank Query ID Response time Calls R/Call V/M Item
  14. # ==== ================== ============= ===== ====== ===== ===============
  15. # 1 0x7DD5F6760F2D2EBB 0.0000 0.0% 3 0.0000 0.00 SHOW VARIABLES
  16. # 2 0x8D07475FE113B1C0 0.0000 0.0% 2 0.0000 0.00 SELECT employees
  17. # 3 0x956C52D06C06E02E 0.0000 0.0% 1 0.0000 0.00 SET
  18. # 4 0xE71D7852C493A0A8 0.0000 0.0% 1 0.0000 0.00 SET
  19. # Query 1: 0 QPS, 0x concurrency, ID 0x7DD5F6760F2D2EBB at byte 955 ______
  20. # This item is included in the report because it matches --limit.
  21. # Scores: V/M = 0.00
  22. # Time range: 2019-10-06T08:55:42.298155Z to 2019-10-06T08:57:26.314967Z
  23. # Attribute pct total min max avg 95% stddev median
  24. # ============ === ======= ======= ======= ======= ======= ======= =======
  25. # Count 42 3
  26. # Exec time 0 0 0 0 0 0 0 0
  27. # Query size 21 105 35 35 35 35 0 35
  28. # Query_time distribution
  29. # 1us
  30. # 10us
  31. # 100us
  32. # 1ms
  33. # 10ms
  34. # 100ms
  35. # 1s
  36. # 10s+
  37. show variables like '%general_log%'\G
  38. # Query 2: 0 QPS, 0x concurrency, ID 0x8D07475FE113B1C0 at byte 483 ______
  39. # This item is included in the report because it matches --limit.
  40. # Scores: V/M = 0.00
  41. # Time range: 2019-10-06T08:55:52.258705Z to 2019-10-06T08:56:06.280872Z
  42. # Attribute pct total min max avg 95% stddev median
  43. # ============ === ======= ======= ======= ======= ======= ======= =======
  44. # Count 28 2
  45. # Exec time 0 0 0 0 0 0 0 0
  46. # Query size 29 146 73 73 73 73 0 73
  47. # Query_time distribution
  48. # 1us
  49. # 10us
  50. # 100us
  51. # 1ms
  52. # 10ms
  53. # 100ms
  54. # 1s
  55. # 10s+
  56. # Tables
  57. # SHOW TABLE STATUS LIKE 'employees'\G
  58. # SHOW CREATE TABLE `employees`\G
  59. # EXPLAIN /*!50100 PARTITIONS*/
  60. select first_name,last_name from employees where hire_date > '1985-01-01'\G
  61. # Query 3: 0 QPS, 0x concurrency, ID 0x956C52D06C06E02E at byte 700 ______
  62. # This item is included in the report because it matches --limit.
  63. # Scores: V/M = 0.00
  64. # Time range: all events occurred at 2019-10-06T08:57:15.264670Z
  65. # Attribute pct total min max avg 95% stddev median
  66. # ============ === ======= ======= ======= ======= ======= ======= =======
  67. # Count 14 1
  68. # Exec time 0 0 0 0 0 0 0 0
  69. # Query size 42 209 209 209 209 209 0 209
  70. # Query_time distribution
  71. # 1us
  72. # 10us
  73. # 100us
  74. # 1ms
  75. # 10ms
  76. # 100ms
  77. # 1s
  78. # 10s+
  79. set global general_log = 'off'
  80. /usr/sbin/mysqld, Version: 8.0.16 (MySQL Community Server - GPL). started with:
  81. Tcp port: 3306 Unix socket: /var/lib/mysql/mysql.sock
  82. Time Id Command Argument\G
  83. # Query 4: 0 QPS, 0x concurrency, ID 0xE71D7852C493A0A8 at byte 629 ______
  84. # This item is included in the report because it matches --limit.
  85. # Scores: V/M = 0.00
  86. # Time range: all events occurred at 2019-10-06T08:56:48.591288Z
  87. # Attribute pct total min max avg 95% stddev median
  88. # ============ === ======= ======= ======= ======= ======= ======= =======
  89. # Count 14 1
  90. # Exec time 0 0 0 0 0 0 0 0
  91. # Query size 5 29 29 29 29 29 0 29
  92. # Query_time distribution
  93. # 1us
  94. # 10us
  95. # 100us
  96. # 1ms
  97. # 10ms
  98. # 100ms
  99. # 1s
  100. # 10s+
  101. set global general_log = 'ON'\G

进程列表

可以使用pt-query-digest而非日志文件从进程列表(process list)中读取查询:

  1. shell> pt-query-digest --processlist h=localhost --iterations 10 --run-time 1m -u<user> -p<password>

run-time指定每次迭代应该运行多长时间。以上例子中该工具会每分钟生成一份报告,并持续10分钟。

二进制日志

要使用pt-query-digest分析二进制日志,应该先用mysqlbinlog工具将其转换为文本格式:

  1. [root@www binlogs]# mysqlbinlog /data/mysql/binlogs/server1.000040 > /root/binlog.000040
  2. [root@www binlogs]# pt-query-digest --type binlog /root/binlog.000040 > binlog_digest

TCP转储

可以使用tcpdump命令捕获TCP流量,并将其发送给pt-query-digest进行分析:

  1. shell> tcpdump -s 65535 -x -nn -q -tttt -i any -c 1000 port 3306 > mysql.tcp.txt
  2. shell> pt-query-digest --type tcpdump mysql.tcp.txt> tcpdump_digest

在pt-query-digest中有很多选项可供选择,例如用特定时间窗口筛选查询,筛选某个特定的查询以及生成报告。更多信息请参阅Percona文档。

优化数据类型

应该这样定义表,它既能保存所有可能值,同时在磁盘上占用的空间又最小。如果表占用的存储空间越小,则:

  • 向磁盘写入或读取的数据就越少,查询起来就越快;
  • 在处理查询时,磁盘上的内容会被加载到主内存中。所以,表越小,占用的主存空间就越小;
  • 被索引占用的空间就越小。

如何操作

  1. 如果要存储员工编号,而其可能的最大值为500000,则最佳数据类型为 MEDIUMINT UNSIGNED(3个字节)。如果将它存储为4个字节的INT类型,则每一行都浪费了一个字节;
  2. 如果要存储员工名字(first_name),由于其长度不等,可能的最大长度为20个字符,则最好将其声明为varchar(20)类型。如果将员工名字存储为char(20)类型,但是只有几个人的名字长为20个字符,其余的长度不到10个字符,就会浪费10个字符的空间。
  3. 在声明类型为varchar的列时,应该考虑其长度。尽管类型varchar在磁盘上进行了优化,但这个类型的数据被加载到内存时却会占用全部的长度空间。例如,如果将first_name存储在类型varchar(255)中,并且其实际长度为10,则在磁盘上它占用10+1(用于存储长度的一个附加字节)个字节;但在内存中,它会占用全部的255个字节。
  4. 如果类型为varchar列的长度超过255个字符,则需要用2个字节来存储长度。
  5. 如果不允许存储空值,则应将列声明为NOT NULL。这样做就避免了测试每个值是否为空的开销,并且还节省了一些存储空间–每列能节省1位。
  6. 如果字符串的长度是固定的,请存储为char而非varchar类型,因为类型varchar需要一个或两个字节来存储字符串的长度。
  7. 如果这些值是固定的,则使用ENUM而非varchar类型。例如,如果要存储可能处于等待状态,或者已批准、已拒绝、已部署、尚未部署,以及已失效或被删除的值,则可以使用ENUM类型。它需要1或2个字节即可,不像类型char(10)那样占用10个字节。
  8. 优先选择使用整数类型而非字符串类型。
  9. 尝试利用前缀索引。
  10. 尝试利用InnoDB压缩。

了解更多关于每一种数据类型的存储需求内容,可以参阅https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html

了解每一种整数类型的范围,可以参阅https://dev.mysql.com/doc/refman/8.0/en/integer-types.html

使用performance_schema

可以使用performance_schema在运行时检查服务器的内部执行情况。

performance_schema中有许多影响服务器计时的事件消费者,例如函数调用、对操作系统的等待、SQL语句执行中的某个阶段(例如解析或排序)、一条语句或一组语句。所有收集的信息都存储在performance_schema中,不会被复制。

默认情况下,performance_schema是启用的;如果要禁用它,可以在my.cnf文件中设置performance_schema = OFF。默认情况下,并非所有的消费者和计数器都处于启用状态;可以通过更新performance_schema.setup_instruments和performance_schema.setup_consumers表来关闭/打开它们。

如何操作

如何使用performance_schema呢?

启用/禁用performance_schema

要禁用performance_schema,可以修改配置文件

  1. [root@www ~]# vim /etc/my.cnf
  2. [mysqld]
  3. performance_schema = 0

启用/禁用消费者和计数器

可以在setup_consumers表中看到可用的消费者列表,如下所示:

  1. mysql> select * from performance_schema.setup_consumers;
  2. +----------------------------------+---------+
  3. | NAME | ENABLED |
  4. +----------------------------------+---------+
  5. | events_stages_current | NO |
  6. | events_stages_history | NO |
  7. | events_stages_history_long | NO |
  8. | events_statements_current | YES |
  9. | events_statements_history | YES |
  10. | events_statements_history_long | NO |
  11. | events_transactions_current | YES |
  12. | events_transactions_history | YES |
  13. | events_transactions_history_long | NO |
  14. | events_waits_current | NO |
  15. | events_waits_history | NO |
  16. | events_waits_history_long | NO |
  17. | global_instrumentation | YES |
  18. | thread_instrumentation | YES |
  19. | statements_digest | YES |
  20. +----------------------------------+---------+
  21. 15 rows in set (0.00 sec)

如果要启用events_waits_current:

  1. mysql> UPDATE performance_schema.setup_consumers SET ENABLED='YES' \
  2. -> WHERE NAME='events_waits_current';
  3. Query OK, 1 row affected (0.00 sec)
  4. Rows matched: 1 Changed: 1 Warnings: 0

同样,可以从setup_instruments表启用/禁用计数器,大约有1182种计数器(视MySQL版本而定):

  1. mysql> SELECT NAME, ENABLED, TIMED FROM performance_schema.setup_instruments LIMIT 10;
  2. +---------------------------------------------------------+---------+-------+
  3. | NAME | ENABLED | TIMED |
  4. +---------------------------------------------------------+---------+-------+
  5. | wait/synch/mutex/pfs/LOCK_pfs_share_list | NO | NO |
  6. | wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc | NO | NO |
  7. | wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_commit | NO | NO |
  8. | wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_commit_queue | NO | NO |
  9. | wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_done | NO | NO |
  10. | wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_flush_queue | NO | NO |
  11. | wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_index | NO | NO |
  12. | wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_log | NO | NO |
  13. | wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_binlog_end_pos | NO | NO |
  14. | wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_sync | NO | NO |
  15. +---------------------------------------------------------+---------+-------+
  16. 10 rows in set (0.00 sec)

performance_schema表

performance_schema中有5种主要的表类型。它们是当前事件表、事件历史表、事件摘要表、对象实例表和设置(配置)表:

  1. mysql> show tables like '%current%';
  2. +------------------------------------------+
  3. | Tables_in_performance_schema (%current%) |
  4. +------------------------------------------+
  5. | events_stages_current |
  6. | events_statements_current |
  7. | events_transactions_current |
  8. | events_waits_current |
  9. +------------------------------------------+
  10. 4 rows in set (0.00 sec)
  11. mysql> show tables like '%history%';
  12. +------------------------------------------+
  13. | Tables_in_performance_schema (%history%) |
  14. +------------------------------------------+
  15. | events_stages_history |
  16. | events_stages_history_long |
  17. | events_statements_history |
  18. | events_statements_history_long |
  19. | events_transactions_history |
  20. | events_transactions_history_long |
  21. | events_waits_history |
  22. | events_waits_history_long |
  23. +------------------------------------------+
  24. 8 rows in set (0.00 sec)
  25. mysql> show tables like '%summary%';
  26. +------------------------------------------------------+
  27. | Tables_in_performance_schema (%summary%) |
  28. +------------------------------------------------------+
  29. | events_errors_summary_by_account_by_error |
  30. | events_errors_summary_by_host_by_error |
  31. | events_errors_summary_by_thread_by_error |
  32. | events_errors_summary_by_user_by_error |
  33. | events_errors_summary_global_by_error |
  34. | events_stages_summary_by_account_by_event_name |
  35. | events_stages_summary_by_host_by_event_name |
  36. | events_stages_summary_by_thread_by_event_name |
  37. | events_stages_summary_by_user_by_event_name |
  38. | events_stages_summary_global_by_event_name |
  39. | events_statements_summary_by_account_by_event_name |
  40. | events_statements_summary_by_digest |
  41. | events_statements_summary_by_host_by_event_name |
  42. | events_statements_summary_by_program |
  43. | events_statements_summary_by_thread_by_event_name |
  44. | events_statements_summary_by_user_by_event_name |
  45. | events_statements_summary_global_by_event_name |
  46. | events_transactions_summary_by_account_by_event_name |
  47. | events_transactions_summary_by_host_by_event_name |
  48. | events_transactions_summary_by_thread_by_event_name |
  49. | events_transactions_summary_by_user_by_event_name |
  50. | events_transactions_summary_global_by_event_name |
  51. | events_waits_summary_by_account_by_event_name |
  52. | events_waits_summary_by_host_by_event_name |
  53. | events_waits_summary_by_instance |
  54. | events_waits_summary_by_thread_by_event_name |
  55. | events_waits_summary_by_user_by_event_name |
  56. | events_waits_summary_global_by_event_name |
  57. | file_summary_by_event_name |
  58. | file_summary_by_instance |
  59. | memory_summary_by_account_by_event_name |
  60. | memory_summary_by_host_by_event_name |
  61. | memory_summary_by_thread_by_event_name |
  62. | memory_summary_by_user_by_event_name |
  63. | memory_summary_global_by_event_name |
  64. | objects_summary_global_by_type |
  65. | socket_summary_by_event_name |
  66. | socket_summary_by_instance |
  67. | table_io_waits_summary_by_index_usage |
  68. | table_io_waits_summary_by_table |
  69. | table_lock_waits_summary_by_table |
  70. +------------------------------------------------------+
  71. 41 rows in set (0.00 sec)
  72. mysql> show tables like '%setup%';
  73. +----------------------------------------+
  74. | Tables_in_performance_schema (%setup%) |
  75. +----------------------------------------+
  76. | setup_actors |
  77. | setup_consumers |
  78. | setup_instruments |
  79. | setup_objects |
  80. | setup_threads |
  81. +----------------------------------------+
  82. 5 rows in set (0.00 sec)

如果要找出被访问最多的文件:

  1. mysql> SELECT EVENT_NAME, COUNT_STAR from file_summary_by_event_name \
  2. -> ORDER BY count_star DESC LIMIT 10;
  3. +--------------------------------------+------------+
  4. | EVENT_NAME | COUNT_STAR |
  5. +--------------------------------------+------------+
  6. | wait/io/file/innodb/innodb_data_file | 3249 |
  7. | wait/io/file/sql/query_log | 183 |
  8. | wait/io/file/innodb/innodb_log_file | 92 |
  9. | wait/io/file/innodb/innodb_temp_file | 80 |
  10. | wait/io/file/sql/binlog_index | 21 |
  11. | wait/io/file/sql/binlog | 20 |
  12. | wait/io/file/sql/casetest | 15 |
  13. | wait/io/file/csv/metadata | 12 |
  14. | wait/io/file/sql/slow_log | 12 |
  15. | wait/io/file/csv/data | 6 |
  16. +--------------------------------------+------------+
  17. 10 rows in set (0.05 sec)

或者想知道哪一个文件的写入时间最长:

  1. mysql> SELECT EVENT_NAME, SUM_TIMER_WRITE FROM file_summary_by_event_name \
  2. -> ORDER BY SUM_TIMER_WRITE DESC LIMIT 10;
  3. +--------------------------------------+-----------------+
  4. | EVENT_NAME | SUM_TIMER_WRITE |
  5. +--------------------------------------+-----------------+
  6. | wait/io/file/innodb/innodb_data_file | 8598755323 |
  7. | wait/io/file/innodb/innodb_log_file | 4102550995 |
  8. | wait/io/file/sql/query_log | 1764069288 |
  9. | wait/io/file/innodb/innodb_temp_file | 1454021094 |
  10. | wait/io/file/sql/slow_log | 140477337 |
  11. | wait/io/file/sql/binlog | 27573957 |
  12. | wait/io/file/sql/pid | 9900549 |
  13. | wait/io/file/sql/binlog_cache | 0 |
  14. | wait/io/file/sql/relaylog | 0 |
  15. | wait/io/file/sql/relaylog_cache | 0 |
  16. +--------------------------------------+-----------------+
  17. 10 rows in set (0.00 sec)

可以使用events_statements_summary_by_digest表来获取查询报告,就像对pt-query-digest所做的那样。按所花费的时间列出排名靠前的查询:

  1. mysql> SELECT SCHEMA_NAME,digest, digest_text, round(sum_timer_wait/1000000000000,6) \
  2. -> as avg_time, count_star FROM events_statements_summary_by_digest \
  3. -> ORDER BY sum_timer_wait DESC LIMIT 1\G
  4. *************************** 1. row ***************************
  5. SCHEMA_NAME: employees
  6. digest: e7099bc0313e71566cdcbf0f4fedd9dee2da121c3d2c30762979ce49fad7da64
  7. digest_text: SELECT `first_name` , `last_name` FROM `employees` WHERE `hire_date` > ?
  8. avg_time: 0.444007
  9. count_star: 4
  10. 1 row in set (0.00 sec)

按执行次数列出排名靠前的查询:

  1. mysql> SELECT SCHEMA_NAME,digest, digest_text, round(sum_timer_wait/1000000000000,6) \
  2. -> as avg_time, count_star FROM events_statements_summary_by_digest \
  3. -> ORDER BY count_star DESC LIMIT 1\G
  4. *************************** 1. row ***************************
  5. SCHEMA_NAME: employees
  6. digest: 230e50b71157a47e34c64f86d958d304e42cc8bad0d5a345f7f60672da38222c
  7. digest_text: SHOW VARIABLES LIKE ?
  8. avg_time: 0.013246
  9. count_star: 10
  10. 1 row in set (0.00 sec)

假设要查找特定查询的统计信息,可以使用performance_schema检查所有统计信息,而不是依赖于mysqlslap基准数据:

  1. mysql> SELECT * FROM events_statements_summary_by_digest \
  2. -> WHERE DIGEST_TEXT LIKE '%SELECT%employees%' LIMIT 1\G
  3. *************************** 1. row ***************************
  4. SCHEMA_NAME: employees
  5. DIGEST: e7099bc0313e71566cdcbf0f4fedd9dee2da121c3d2c30762979ce49fad7da64
  6. DIGEST_TEXT: SELECT `first_name` , `last_name` FROM `employees` WHERE `hire_date` > ?
  7. COUNT_STAR: 4
  8. SUM_TIMER_WAIT: 444006679000
  9. MIN_TIMER_WAIT: 65428428000
  10. AVG_TIMER_WAIT: 111001669000
  11. MAX_TIMER_WAIT: 173988118000
  12. SUM_LOCK_TIME: 787000000
  13. SUM_ERRORS: 0
  14. SUM_WARNINGS: 0
  15. SUM_ROWS_AFFECTED: 0
  16. SUM_ROWS_SENT: 373688
  17. SUM_ROWS_EXAMINED: 1200096
  18. SUM_CREATED_TMP_DISK_TABLES: 0
  19. SUM_CREATED_TMP_TABLES: 0
  20. SUM_SELECT_FULL_JOIN: 0
  21. SUM_SELECT_FULL_RANGE_JOIN: 0
  22. SUM_SELECT_RANGE: 0
  23. SUM_SELECT_RANGE_CHECK: 0
  24. SUM_SELECT_SCAN: 4
  25. SUM_SORT_MERGE_PASSES: 0
  26. SUM_SORT_RANGE: 0
  27. SUM_SORT_ROWS: 0
  28. SUM_SORT_SCAN: 0
  29. SUM_NO_INDEX_USED: 4
  30. SUM_NO_GOOD_INDEX_USED: 0
  31. FIRST_SEEN: 2019-10-06 16:21:13.627844
  32. LAST_SEEN: 2019-10-06 16:56:06.412642
  33. QUANTILE_95: 181970085861
  34. QUANTILE_99: 181970085861
  35. QUANTILE_999: 181970085861
  36. QUERY_SAMPLE_TEXT: select first_name,last_name from employees where hire_date > '1985-01-01'
  37. QUERY_SAMPLE_SEEN: 2019-10-06 16:56:06.412642
  38. QUERY_SAMPLE_TIMER_WAIT: 131864014000
  39. 1 row in set (0.00 sec)

使用sys schema

sys schema以一种更简单和更易理解的形式解释从performance_schema收集来的数据。为了使sys schema能工作,应该启用performance_schema。如想最大限度地使用sys schema,需要启用performances_schema上的所有消费者和计数器,但这样会影响服务器的性能。所以,仅启动你在寻找的消费者。

带有x$前缀的视图以皮秒为单位显示数据,供其他工具做进一步的处理;其他表是人类可阅读的。

如何操作

从sys schema中启用一个计数器:

  1. mysql> CALL sys.ps_setup_enable_instrument('statement');
  2. +------------------------+
  3. | summary |
  4. +------------------------+
  5. | Enabled 22 instruments |
  6. +------------------------+
  7. 1 row in set (0.01 sec)
  8. Query OK, 0 rows affected (0.01 sec)

如果要重置为默认值,执行以下操作:

  1. mysql> CALL sys.ps_setup_reset_to_default(TRUE)\G

sys schema中有许多表,下面只是展示了其中一些最常用的表。

按类型列出每个主机的语句(INSERT和SELECT)

  1. mysql> SELECT statement, total, total_latency, rows_sent, rows_examined, \
  2. -> rows_affected, full_scans FROM sys.host_summary_by_statement_type \
  3. -> WHERE host='localhost' ORDER BY total DESC LIMIT 5;
  4. +------------+-------+---------------+-----------+---------------+---------------+------------+
  5. | statement | total | total_latency | rows_sent | rows_examined | rows_affected | full_scans |
  6. +------------+-------+---------------+-----------+---------------+---------------+------------+
  7. | set | 4920 | 8.41 ms | 0 | 0 | 0 | 0 |
  8. | freturn | 2460 | 1.33 ms | 0 | 0 | 0 | 0 |
  9. | Field List | 246 | 152.92 ms | 0 | 0 | 0 | 0 |
  10. | stmt | 39 | 23.60 ms | 33 | 7515 | 559 | 0 |
  11. | select | 21 | 514.21 ms | 373761 | 1200320 | 0 | 14 |
  12. +------------+-------+---------------+-----------+---------------+---------------+------------+
  13. 5 rows in set (0.00 sec)

按类型列出每个用户的语句

  1. mysql> SELECT statement, total, total_latency, rows_sent, rows_examined, \
  2. -> rows_affected, full_scans FROM sys.user_summary_by_statement_type \
  3. -> ORDER BY total DESC LIMIT 5;
  4. +-------------+-------+---------------+-----------+---------------+---------------+------------+
  5. | statement | total | total_latency | rows_sent | rows_examined | rows_affected | full_scans |
  6. +-------------+-------+---------------+-----------+---------------+---------------+------------+
  7. | set | 4920 | 8.41 ms | 0 | 0 | 0 | 0 |
  8. | freturn | 2465 | 1.34 ms | 0 | 0 | 0 | 0 |
  9. | Field List | 246 | 152.92 ms | 0 | 0 | 0 | 0 |
  10. | jump_if_not | 42 | 43.94 us | 0 | 0 | 0 | 0 |
  11. | stmt | 39 | 23.60 ms | 33 | 7515 | 559 | 0 |
  12. +-------------+-------+---------------+-----------+---------------+---------------+------------+
  13. 5 rows in set (0.00 sec)

冗余索引

  1. mysql> SELECT * FROM sys.schema_redundant_indexes \
  2. -> WHERE table_name='employees' \G
  3. *************************** 1. row ***************************
  4. table_schema: employees
  5. table_name: employees
  6. redundant_index_name: name_desc
  7. redundant_index_columns: first_name,last_name
  8. redundant_index_non_unique: 1
  9. dominant_index_name: name
  10. dominant_index_columns: first_name,last_name
  11. dominant_index_non_unique: 1
  12. subpart_exists: 0
  13. sql_drop_index: ALTER TABLE `employees`.`employees` DROP INDEX `name_desc`
  14. 1 row in set (0.00 sec)

未使用的索引

  1. mysql> SELECT * FROM sys.schema_unused_indexes \
  2. -> WHERE object_schema='employees';
  3. +---------------+--------------+----------------+
  4. | object_schema | object_name | index_name |
  5. +---------------+--------------+----------------+
  6. | employees | dept_emp | dept_no |
  7. | employees | dept_manager | dept_no |
  8. | employees | employees | hire_date |
  9. | employees | employees | last_name |
  10. | employees | employees | name |
  11. | employees | employees | name_desc |
  12. | employees | employees | hire_date_year |
  13. +---------------+--------------+----------------+
  14. 7 rows in set, 1 warning (0.00 sec)

每个主机执行的语句

  1. mysql> SELECT * FROM sys.host_summary ORDER BY statements DESC LIMIT 1\G
  2. *************************** 1. row ***************************
  3. host: localhost
  4. statements: 7829
  5. statement_latency: 794.13 ms
  6. statement_avg_latency: 101.43 us
  7. table_scans: 39
  8. file_ios: 1346
  9. file_io_latency: 136.09 ms
  10. current_connections: 1
  11. total_connections: 2
  12. unique_users: 1
  13. current_memory: 1.32 MiB
  14. total_memory_allocated: 42.29 MiB
  15. 1 row in set (0.01 sec)

对表的统计

  1. mysql> SELECT * FROM sys.schema_table_statistics LIMIT 1\G
  2. *************************** 1. row ***************************
  3. table_schema: employees
  4. table_name: employees
  5. total_latency: 443.36 ms
  6. rows_fetched: 1200096
  7. fetch_latency: 443.36 ms
  8. rows_inserted: 0
  9. insert_latency: 0 ps
  10. rows_updated: 0
  11. update_latency: 0 ps
  12. rows_deleted: 0
  13. delete_latency: 0 ps
  14. io_read_requests: 1300
  15. io_read: 20.31 MiB
  16. io_read_latency: 129.43 ms
  17. io_write_requests: 0
  18. io_write: 0 bytes
  19. io_write_latency: 0 ps
  20. io_misc_requests: 5
  21. io_misc_latency: 41.88 us
  22. 1 row in set (0.02 sec)

对带缓冲区(buffer)的表的统计:

  1. mysql> SELECT * FROM sys.schema_table_statistics_with_buffer LIMIT 1\G
  2. *************************** 1. row ***************************
  3. table_schema: employees
  4. table_name: employees
  5. rows_fetched: 1200096
  6. fetch_latency: 443.36 ms
  7. rows_inserted: 0
  8. insert_latency: 0 ps
  9. rows_updated: 0
  10. update_latency: 0 ps
  11. rows_deleted: 0
  12. delete_latency: 0 ps
  13. io_read_requests: 1300
  14. io_read: 20.31 MiB
  15. io_read_latency: 129.43 ms
  16. io_write_requests: 0
  17. io_write: 0 bytes
  18. io_write_latency: 0 ps
  19. io_misc_requests: 5
  20. io_misc_latency: 41.88 us
  21. innodb_buffer_allocated: 19.62 MiB
  22. innodb_buffer_data: 18.31 MiB
  23. innodb_buffer_free: 1.32 MiB
  24. innodb_buffer_pages: 1256
  25. innodb_buffer_pages_hashed: 0
  26. innodb_buffer_pages_old: 88
  27. innodb_buffer_rows_cached: 180523
  28. 1 row in set (0.21 sec)

语句分析

此输出类似于performance_schema.events_statements_summary_by_digest和pt-query-digest的输出。

根据查询的执行次数,排在前几位的查询如下:

  1. mysql> SELECT * FROM sys.statement_analysis ORDER BY exec_count DESC LIMIT 1\G
  2. *************************** 1. row ***************************
  3. query: SHOW VARIABLES LIKE ?
  4. db: employees
  5. full_scan: *
  6. exec_count: 10
  7. err_count: 0
  8. warn_count: 0
  9. total_latency: 13.25 ms
  10. max_latency: 2.32 ms
  11. avg_latency: 1.32 ms
  12. lock_latency: 1.74 ms
  13. rows_sent: 53
  14. rows_sent_avg: 5
  15. rows_examined: 5780
  16. rows_examined_avg: 578
  17. rows_affected: 0
  18. rows_affected_avg: 0
  19. tmp_tables: 10
  20. tmp_disk_tables: 0
  21. rows_sorted: 0
  22. sort_merge_passes: 0
  23. digest: 230e50b71157a47e34c64f86d958d304e42cc8bad0d5a345f7f60672da38222c
  24. first_seen: 2019-10-06 16:53:22.542062
  25. last_seen: 2019-10-06 17:22:18.985453
  26. 1 row in set (0.01 sec)

消耗了最大的tmp_disk_tables的语句为:

  1. mysql> SELECT * FROM sys.statement_analysis ORDER BY tmp_disk_tables DESC LIMIT 1\G
  2. *************************** 1. row ***************************
  3. query: SELECT IF ( ( `locate` ( ? , ` ... ` . `COMPRESSED_SIZE` ) ) DESC
  4. db: sys
  5. full_scan: *
  6. exec_count: 2
  7. err_count: 0
  8. warn_count: 0
  9. total_latency: 391.11 ms
  10. max_latency: 215.87 ms
  11. avg_latency: 195.55 ms
  12. lock_latency: 1.23 ms
  13. rows_sent: 3
  14. rows_sent_avg: 2
  15. rows_examined: 267623
  16. rows_examined_avg: 133812
  17. rows_affected: 0
  18. rows_affected_avg: 0
  19. tmp_tables: 16
  20. tmp_disk_tables: 2
  21. rows_sorted: 4328
  22. sort_merge_passes: 6
  23. digest: bf060aa9a5df456317f07a0159bcd8e91c9fd9a588a89d87d42e89f3767147b8
  24. first_seen: 2019-10-06 20:54:43.243844
  25. last_seen: 2019-10-06 20:55:26.335113
  26. 1 row in set (0.00 sec)

更多sys schema对象信息,参阅https://dev.mysql.com/doc/refman/8.0/en/sys-schema-object-index.html

MySQL配置优化

Mysql 参数优化对于不同的网站,及其在线量,访问量,帖子数量,网络情况,以及机器硬件配置都有关系,优化不可能一次性完成,需要不断的观察以及调试,才有可能得到最佳效果。

下面列出了对性能优化影响较大的主要变量,主要分为连接请求的变量和缓冲区变量。

连接请求的变量

1、max_connections

MySQL 的最大连接数,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多, MySQL会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。数值过小会经常出现 ERROR 1040: Too many connections 错误,可以过mysql> show status like
‘connections’;查看当前状态的连接数量(试图连接到MySQL(不管是否连接成功)的连接数),以定夺该值的大小。

  1. #最大连接数
  2. mysql> show variables like '%max_connections%';
  3. +------------------------+-------+
  4. | Variable_name | Value |
  5. +------------------------+-------+
  6. | max_connections | 1024 |
  7. | mysqlx_max_connections | 100 |
  8. +------------------------+-------+
  9. 2 rows in set (0.00 sec)
  10. #响应的连接数
  11. mysql> show status like '%max_used_connections%';
  12. +---------------------------+---------------------+
  13. | Variable_name | Value |
  14. +---------------------------+---------------------+
  15. | Max_used_connections | 1 |
  16. | Max_used_connections_time | 2019-10-06 16:14:21 |
  17. +---------------------------+---------------------+
  18. 2 rows in set (0.00 sec)

如果 max_used_connections跟max_connections相同那么就是max_connections 设置过低或者超过服务器负载上限了,低于10%则设置过大。

如何设置 max_connections?

  1. [root@www ~]# vim /etc/my.cnf
  2. [mysqld]
  3. max_connections = 1024

2、back_log

MySQL 能暂存的连接数量。当主要MySQL线程在一个很短时间内得到非常多的连接请求,它就会起作用。如果MySQL的连接数据达到max_connections 时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,该堆栈的数量即 back_log,如果等待连接的数量超过back_log,将不被授予连接资源。

back_log 值指出在MySQL暂时停止回答新请求之前的短时间内有多少个请求可以被存在堆栈中。只有如果期望在一个短时间内有很多连接,你需要增加它。

当观察你主机进程列表(mysql> show full processlist),发现大量
xxxxx | unauthenticated user | xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 的待连接进程时,就要加大back_log的值了或加大 max_connections 的值。

  1. mysql> show variables like '%back_log%';
  2. +---------------+-------+
  3. | Variable_name | Value |
  4. +---------------+-------+
  5. | back_log | 1024 |
  6. +---------------+-------+
  7. 1 row in set (0.00 sec)

设置方法:

  1. [root@www ~]# vim /etc/my.cnf
  2. [mysqld]
  3. back_log = 1024

3、wait_timeout和interactive_timeout

wait_timeout – 指的是MySQL在关闭一个非交互的连接之前所要等待的秒数

interactive_time —指的是mysql在关闭一个交互的连接之前所要等待的秒数,比如我们在终端上进入mysql管理,使用的即使交互的连接,这时候,如果没有操作的时间超过了interactive_time设置的时间就会自动断开。默认数值是 28800,可调优为 7200。

对性能的影响

  • wait_timeout
    • 如果设置大小,那么连接关闭的很快,从而使一些持久的连接不起作用
    • 如果设置太大,容易造成连接打开时间过长,在 show processlist 时,能看到太多的 sleep状态的连接,从而造成 too many connections 错误
    • 一般希望 wait_timeout 尽可能地低
  • interactive_timeout 的设置将要对你的 web application 没有多大的影响
  1. mysql> show variables like '%wait_timeout%';
  2. +--------------------------+----------+
  3. | Variable_name | Value |
  4. +--------------------------+----------+
  5. | innodb_lock_wait_timeout | 50 |
  6. | lock_wait_timeout | 31536000 |
  7. | mysqlx_wait_timeout | 28800 |
  8. | wait_timeout | 28800 |
  9. +--------------------------+----------+
  10. 4 rows in set (0.00 sec)
  11. mysql> show variables like '%interactive_timeout%';
  12. +----------------------------+-------+
  13. | Variable_name | Value |
  14. +----------------------------+-------+
  15. | interactive_timeout | 28800 |
  16. | mysqlx_interactive_timeout | 28800 |
  17. +----------------------------+-------+
  18. 2 rows in set (0.00 sec)

如何设置

  1. [root@www ~]# vim /etc/my.cnf
  2. [mysqld]
  3. wait_timeout = 7200
  4. interactive_timeout = 7200

缓冲区变量

4、key_buffer_size

key_buffer_size指定索引缓冲区的大小,它决定索引处理的速度,尤其是索引读的速度。通过检查状态值 Key_read_requests 和 Key_reads,可以知道 key_buffer_size 设置是否合理。比例 key_reads / key_read_requests应该尽可能的低,至少是1:100,1:1000 更好(上述状态值可以使用 SHOW STATUS LIKE ‘key_read%’获得)。

  1. mysql> show variables like '%key_buffer_size%';
  2. +-----------------+---------+
  3. | Variable_name | Value |
  4. +-----------------+---------+
  5. | key_buffer_size | 8388608 |
  6. +-----------------+---------+
  7. 1 row in set (0.02 sec)
  8. mysql> show status like '%key_read%';
  9. +-------------------+-------+
  10. | Variable_name | Value |
  11. +-------------------+-------+
  12. | Key_read_requests | 0 |
  13. | Key_reads | 0 |
  14. +-------------------+-------+
  15. 2 rows in set (0.00 sec)

key_buffer_size 只对 MyISAM 表起作用。即使你不使用 MyISAM 表,但是内部的临时磁盘表是MyISAM表,也要使用该值。可以使用检查状态值 created_tmp_disk_tables 得知详情。

  1. mysql> show status like '%created_tmp%';
  2. +-------------------------+-------+
  3. | Variable_name | Value |
  4. +-------------------------+-------+
  5. | Created_tmp_disk_tables | 0 |
  6. | Created_tmp_files | 6 |
  7. | Created_tmp_tables | 1 |
  8. +-------------------------+-------+
  9. 3 rows in set (0.00 sec)

默认配置数值是 8388608(8M),主机有 4GB 内存,可以调优值为 268435456(256MB)。

修改/etc/my.cnf 文件,在[mysqld]下面添加如下内容

  1. key_buffer_size=268435456 key_buffer_size=256M

重启 MySQL Server 进入后,查看设置已经生效。

5、max_connect_errors

是一个 MySQL 中与安全有关的计数器值,它负责阻止过多尝试失败
的客户端以防止暴力破解密码的情况,当超过指定次数,MYSQL服务器将禁止host的连接请求,直到mysql服务器重启或通过flush hosts 命令清空此host的相关信息。max_connect_errors 的值与性能并无太大关系。

修改/etc/my.cnf 文件,在[mysqld]下面添加如下内容:

  1. max_connect_errors=20

6、sort_buffer_size

每个需要进行排序的线程分配该大小的一个缓冲区。增加这值加速 ORDER BY 或 GROUP BY操作。

Sort_Buffer_Size 是一个 connection 级参数,在每个 connection(session)第一次需要使用这个buffer的时候,一次性分配设置的内存。

Sort_Buffer_Size并不是越大越好,由于是connection级的参数,过大的设置+高并发可能会耗尽系统内存资源。例如:500 个连接将会消耗 500*sort_buffer_size(2M)=1G 内存

  1. mysql> show variables like '%sort_buffer_size%';
  2. +-------------------------+---------+
  3. | Variable_name | Value |
  4. +-------------------------+---------+
  5. | innodb_sort_buffer_size | 1048576 |
  6. | myisam_sort_buffer_size | 8388608 |
  7. | sort_buffer_size | 262144 |
  8. +-------------------------+---------+
  9. 3 rows in set (0.01 sec)

设置sort_buffer_size,修改/etc/my.cnf文件,在[mysqld]下面添加如下内容:

  1. sort_buffer_size = 2M

7、max_allowed_packet

MySQL根据配置文件会限制Server接受的数据包大小。有时候大的插入和更新会受max_allowed_packet参数限制,导致写入或者更新失败。最大值是1GB,必须设置 1024 的倍数。

  1. mysql> show variables like '%max_allowed_packet%';
  2. +---------------------------+------------+
  3. | Variable_name | Value |
  4. +---------------------------+------------+
  5. | max_allowed_packet | 67108864 |
  6. | mysqlx_max_allowed_packet | 67108864 |
  7. | slave_max_allowed_packet | 1073741824 |
  8. +---------------------------+------------+
  9. 3 rows in set (0.00 sec)

8、join_buffer_size

用于表间关联缓存的大小,和sort_buffer_size一样,该参数对应的分配内存也是每个连接独享。

  1. mysql> show variables like '%join_buffer_size%';
  2. +------------------+--------+
  3. | Variable_name | Value |
  4. +------------------+--------+
  5. | join_buffer_size | 262144 |
  6. +------------------+--------+
  7. 1 row in set (0.00 sec)

9、thread_cache_size

服务器线程缓存,这个值表示可以重新利用保存在缓存中线程的数量,当断开连接时,那么客户端的线程将被放到缓存中以响应下一个客户而不是销毁(前提是缓存数未达上限),如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,增加这个值可以改善系统性能。

  1. mysql> show variables like '%thread_cache_size%';
  2. +-------------------+-------+
  3. | Variable_name | Value |
  4. +-------------------+-------+
  5. | thread_cache_size | 18 |
  6. +-------------------+-------+
  7. 1 row in set (0.00 sec)

通过比较 Connections和Threads_created状态的变量,可以看到这个变量的作用。设置规则如下:
1GB 内存配置为 8,2GB 配置为 16,3GB 配置为 32,4GB 或更高内存,可配置更大。

  1. mysql> show status like 'connections';
  2. +---------------+-------+
  3. | Variable_name | Value |
  4. +---------------+-------+
  5. | Connections | 8 |
  6. +---------------+-------+
  7. 1 row in set (0.00 sec)
  8. mysql> show status like 'threads_%';
  9. +-------------------+-------+
  10. | Variable_name | Value |
  11. +-------------------+-------+
  12. | Threads_cached | 0 |
  13. | Threads_connected | 1 |
  14. | Threads_created | 1 |
  15. | Threads_running | 2 |
  16. +-------------------+-------+
  17. 4 rows in set (0.00 sec)
  • Threads_cached :代表当前此时此刻线程缓存中有多少空闲线程。
  • Threads_connected :代表当前已建立连接的数量,因为一个连接就需要一个线程,所以也可以看成当前被使用的线程数。
  • Threads_created :代表从最近一次服务启动,已创建线程的数量,如果发现 Threads_created值过大的话,表明MySQL服务器一直在创建线程,这也是比较耗资源,可以适当增加配置文件中 thread_cache_size 值。
  • Threads_running :代表当前激活的(非睡眠状态)线程数。并不是代表正在使用的线程数,有时候连接已建立,但是连接处于sleep状态。

配置InnoDB的几个变量

10、innodb_buffer_pool_size

对于 InnoDB 表来说,innodb_buffer_pool_size 的作用就相当于 key_buffer_size对于MyISAM表的作用一样。InnoDB使用该参数指定大小的内存来缓冲数据和索引。对于单独的MySQL数据库服务器,最大可以把该值设置成物理内存的 80%。根据 MySQL 手册,对于 2G 内存的机器,推荐值是1G(50%)。如果你的数据量不大,并且不会暴增,那么无需把 innodb_buffer_pool_size 设置的太大了。

  1. mysql> show variables like '%innodb_buffer_pool_size%';
  2. +-------------------------+------------+
  3. | Variable_name | Value |
  4. +-------------------------+------------+
  5. | innodb_buffer_pool_size | 2147483648 |
  6. +-------------------------+------------+
  7. 1 row in set (0.00 sec)

设置 innodb_buffer_pool_size,修改/etc/my.cnf文件,在[mysqld]下面添加如下内容:

  1. innodb_buffer_pool_size = 2048M

11、innodb_flush_log_at_trx_commit

主要控制了InnoDB将 log buffer 中的数据写入日志文件并 flush 磁盘的时间点,取值分别为0、1、2三个。

  • 0,表示当事务提交时,不做日志写入操作,而是每秒钟将 log buffer 中的数据写入日志文件并flush磁盘一次;
  • 1,则在每秒钟或是每次事务的提交都会引起日志文件写入、
    flush 磁盘的操作,确保了事务的 ACID;
  • 2,每次事务提交引起写入日志文件的动作,但每秒钟完成一次 flush 磁盘操作。

实际测试发现,该值对插入数据的速度影响非常大,设置为 2 时插入10000条记录只需要2秒,设置为0时只需要1秒,而设置为1时则需要 229 秒。因此,MySQL 手册也建议尽量
将插入操作合并成一个事务,这样可以大幅提高速度。
根据 MySQL 手册,在允许丢失最近部分事务的危险的前提下,可以把该值设为 0 或 2。

  1. mysql> show variables like '%innodb_flush_log_at_trx_commit%';
  2. +--------------------------------+-------+
  3. | Variable_name | Value |
  4. +--------------------------------+-------+
  5. | innodb_flush_log_at_trx_commit | 1 |
  6. +--------------------------------+-------+
  7. 1 row in set (0.00 sec)

12、innodb_thread_concurrency

此参数用来设置 innodb 线程的并发数量,默认值为 0 表示不限制,若要设置则与服务器的CPU 核数相同或是cpu的核数的 2 倍,建议用默认设置,一般为 8。

  1. mysql> show variables like '%innodb_thread_con%';
  2. +---------------------------+-------+
  3. | Variable_name | Value |
  4. +---------------------------+-------+
  5. | innodb_thread_concurrency | 0 |
  6. +---------------------------+-------+
  7. 1 row in set (0.00 sec)

13、innodb_log_buffer_size

此参数确定写日志文件所用的内存大小。缓冲区更大能提高性能,对于较大的事务,可以增大缓存大小。

  1. mysql> show variables like '%innodb_log_buffer_size%';
  2. +------------------------+----------+
  3. | Variable_name | Value |
  4. +------------------------+----------+
  5. | innodb_log_buffer_size | 16777216 |
  6. +------------------------+----------+
  7. 1 row in set (0.00 sec)

14、innodb_log_file_size

此参数确定数据日志文件的大小,更大的设置可以提高性能。

  1. mysql> show variables like '%innodb_log_file_size%';
  2. +----------------------+----------+
  3. | Variable_name | Value |
  4. +----------------------+----------+
  5. | innodb_log_file_size | 50331648 |
  6. +----------------------+----------+
  7. 1 row in set (0.00 sec)

15、innodb_log_files_in_group

为提高性能,MySQL可以以循环方式将日志文件写到多个文件。推荐设置为 3。

  1. mysql> show variables like '%innodb_log_files_in_group%';
  2. +---------------------------+-------+
  3. | Variable_name | Value |
  4. +---------------------------+-------+
  5. | innodb_log_files_in_group | 2 |
  6. +---------------------------+-------+
  7. 1 row in set (0.00 sec)

16、read_buffer_size

MySql 读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySql 会为它分配一段内存缓冲区。如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。和 sort_buffer_size 一样,该参数对应的分配内存也是每个连接独享。

  1. mysql> show variables like '%read_buffer_size%';
  2. +------------------+--------+
  3. | Variable_name | Value |
  4. +------------------+--------+
  5. | read_buffer_size | 131072 |
  6. +------------------+--------+
  7. 1 row in set (0.00 sec)

17、read_rnd_buffer_size

MySql 的随机读(查询操作)缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySql 会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySql会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。

注:顺序读是指根据索引的叶节点数据就能顺序地读取所需要的行数据。随机读是指一般需要根据辅助索引叶节点中的主键寻找实际行数据,而辅助索引和主键所在的数据段不同,因此访问方式是随机的。

  1. mysql> show variables like '%read_rnd_buffer_size%';
  2. +----------------------+--------+
  3. | Variable_name | Value |
  4. +----------------------+--------+
  5. | read_rnd_buffer_size | 262144 |
  6. +----------------------+--------+
  7. 1 row in set (0.00 sec)

18、bulk_insert_buffer_size

批量插入数据缓存大小,可以有效提高插入效率,默认为 8M。

  1. mysql> show variables like '%bulk_insert_buffer_size%';
  2. +-------------------------+---------+
  3. | Variable_name | Value |
  4. +-------------------------+---------+
  5. | bulk_insert_buffer_size | 8388608 |
  6. +-------------------------+---------+
  7. 1 row in set (0.01 sec)

19、binlog相关参数

  1. mysql> show variables like 'log_bin%';
  2. +---------------------------------+-----------------------------------+
  3. | Variable_name | Value |
  4. +---------------------------------+-----------------------------------+
  5. | log_bin | ON |
  6. | log_bin_basename | /data/mysql/binlogs/server1 |
  7. | log_bin_index | /data/mysql/binlogs/server1.index |
  8. | log_bin_trust_function_creators | OFF |
  9. | log_bin_use_v1_row_events | OFF |
  10. +---------------------------------+-----------------------------------+
  11. 5 rows in set (0.00 sec)
  • binlog_cache_size: 为每个session分配的内存,在事务过程中用来存储二进制日志
    的缓存,提高记录bin-log的效率。没有什么大事务,DML也不是很频繁的情况下可以设置小一点,如果事务大而且多,DML操作也频繁,则可以适当的调大一点。前者建议是1M,后者建议是:2-4M;
  • max_binlog_cache_size: 表示的是 binlog 能够使用的最大 cache 内存大小;
  • max_binlog_size: 指定binlog日志文件的大小,如果当前的日志大小达到max_binlog_size,还会自动创建新的二进制日志。你不能将该变量设置为大于 1GB 或小于4096 字节。默认值是1GB。在导入大容量的sql文件时,建议关闭 sql_log_bin,否则硬盘扛不住,而且建议定期做删除。
  • expire_logs_days: 定义了mysql清除过期日志的时间。二进制日志自动删除的天数。默认值为 0,表示“没有自动删除”。mysqladmin flush-logs 也可以重新开始新的binary log。

相关优化参数总结:

  1. [mysqld]
  2. slow_query_log = 1
  3. slow_query_log_file = /usr/local/mysql/data/slow-query.log
  4. long_query_time = 1
  5. log-queries-not-using-indexes
  6. max_connections = 1024
  7. back_log = 128
  8. wait_timeout = 60
  9. interactive_timeout = 7200
  10. key_buffer_size=256M
  11. max_connect_errors=20
  12. sort_buffer_size = 2M
  13. max_allowed_packet=32M
  14. join_buffer_size=2M
  15. thread_cache_size=200
  16. innodb_buffer_pool_size = 2048M
  17. innodb_flush_log_at_trx_commit = 1
  18. innodb_log_buffer_size=32M
  19. innodb_log_file_size=128M
  20. innodb_log_files_in_group=3
  21. log-bin=mysql-bin
  22. binlog_cache_size=2M
  23. max_binlog_cache_size=8M
  24. max_binlog_size=512M
  25. expire_logs_days=7
  26. read_buffer_size=1M
  27. read_rnd_buffer_size=16M
  28. bulk_insert_buffer_size=64M
  29. log-error = /usr/local/mysql/data/mysqld.err

优化总结

基本思路如下:

性能瓶颈定位

  • show 命令
  1. 可以通过 show 命令查看 MySQL 状态及变量,找到系统的瓶颈:
  2. 查看 MySQL服务器配置信息mysql> show variables;
  3. 查看 MySQL服务器运行的各种状态值 mysql> show global status;
  4. mysqladmin variables -u username -ppassword——显示系统变量
  5. mysqladmin extended-status -u username -ppassword——显示状态信息
  • 慢查询日志
  • explain 分析查询
  • profiling 分析查询

索引及查询优化

配置优化

MySQL 数据库是常见的两个瓶颈是CPU和I/O的瓶颈,CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候。磁盘I/O瓶颈发生在装入数据远大于内存容量的时候,如果应用分布在网络上,那么查询量相当大的时候那么平瓶颈就会出现在网络上,我们可以用mpstat, iostat, sar 和 vmstat 来查看系统的性能状态。

除了服务器硬件的性能瓶颈,对于MySQL系统本身,我们可以使用工具来优化数据库的性能,通常有三种:使用索引,使用EXPLAIN分析查询以及调整 MySQL的内部配置。