mysql性能测试、优化
性能测试
数据库服务衡量指标:
- Qps:query per second
- Tps:transaction per second
常见 MySQL 压力测试工具:
- mysqlslap
- Sysbench:功能强大,官网: https://github.com/akopytov/sysbench
- tpcc-mysql
- MySQL Benchmark Suite
- MySQL super-smack
- MyBench
mysqlslap工具:
mysqlslap:来自于mariadb包,测试的过程默认生成一个mysqlslap的schema,生成测试表t1,查询和插入测试数据,mysqlslap库自动生成,如果已经存在则先删除。用--only-print来打印实际的测试过程,整个测试完成后不会在数据库中留下痕迹
格式:
mysqlslap [options]
常用选项:
-a #自动生成测试表和数据,表示用mysqlslap工具自己生成的SQL脚本来测试并发压力
--auto-generate-sql-load-type=type #测试语句的类型。代表要测试的环境是读操作还是写操作还是两者混合的。取值包括:read,key,write,update和mixed(默认)
--auto-generate-sql-add-auto-increment #代表对生成的表自动添加auto_increment列,从5.1.18版本开始支持
-x N #自动生成的测试表中包含多少个字符类型的列,默认1
-y N #自动生成的测试表中包含多少个数字类型的列,默认1
--number-of-queries=N #总的测试查询次数(并发客户数×每客户查询次数)
-q #使用自定义脚本执行测试,例如可以调用自定义的存储过程或者sql语句来执行测试
--create-schema #代表自定义的测试库名称,测试的schema
--commint=N #多少条DML后提交一次
-C #如服务器和客户端都支持压缩,则压缩信息
-c N #表示并发量,即模拟多少个客户端同时执行select。可指定多个值,以逗号或者--delimiter参数指定值做为分隔符,如:--concurrency=100,200,500
-e 存储引擎 #代表要测试的引擎,可以有多个,用分隔符隔开。例如:--engines=myisam,innodb
-i N #测试执行的迭代次数,代表要在不同并发环境下,各自运行测试多少次
--only-print #只打印测试语句而不实际执行。
--detach=N #执行N条语句后断开重连
-T #打印内存和CPU的相关信息
例:
#单线程测试
mysqlslap -a -uroot -p123456
#多线程测试。使用--concurrency来模拟并发连接
mysqlslap -a -c 100 -uroot -p123456
#迭代测试。用于需要多次执行测试得到平均值
mysqlslap -a -i 10 -uroot -p123456
#生成测试库,使用自增,使用读操作测试,写入1000个数据,自动生成3个辅助索引
mysqlslap -a --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=read --auto-generate-sql-write-number=1000 --auto-generate-sql-secondary-indexes=3
#测试同时不同的存储引擎的性能进行对比
mysqlslap -a -c 50,100 --number-of-queries 1000 --i 5 -e myisam,innodb -T -uroot -p123456
#执行一次测试,分别50和100个并发,执行1000次总查询
mysqlslap -a -c 50,100 --number-of-queries 1000 -T -uroot -p123456
#50和100个并发分别得到一次测试结果(Benchmark),并发数越多,执行完所有查询的时间越长。为了准确起见,可以多迭代测试几次
mysqlslap -a -c 50,100 --number-of-queries 1000 -i 5 -T -uroot -p123456


用于sql的相关优化配置
分析sql执行效率
只支持在会话中开启,不能写进配置文件
可以看到sql执行时具体在哪些地方花费了时间,是cpu还是io等
| profiling | sql执行分析器是否开启 |
| profiling_history_size | 分析器记录的历史sql数量 |
使用方式
show profile [类型1,...] [for query 序号] [LIMIT row_count [OFFSET offset]];
状态类型:
- ALL : 所有类型
- BLOCK IO : 显示块IO相关开销
- CONTEXT SWITCHES : 上下文切换相关开销
- CPU : 显示用户CPU时间、系统CPU时间
- IPC : 显示发送和接收相关开销信息
- MEMORY :
- PAGE FAULTS : 显示页面错误相关开销信息
- SWAPS : 显示交换次数相关开销的信息
- SOURCE : 显示和Source_function,Source_file,Source_line相关的开销信息
例:
mysql
->set profiling=1;
show variables like 'prof%';
show profiles; #查看当前执行记录中的全部sql
show profile all query 1\G;

分析sql的索引使用
可参考索引博客explain部分:mysql索引
explain 查询sql语句;
字段说明
常关注select_type、type、key
id SELECT识别符。这是SELECT的查询序列号。
select_type SELECT类型。
SIMPLE 简单SELECT(不使用UNION或子查询)
PRIMARY 最外面的SELECT
UNION UNION中的第二个或后面的SELECT语句
DEPENDENT UNION UNION中的第二个或后面的SELECT语句,取决于外面的查询
UNION RESULT UNION的结果
SUBQUERY 子查询中的第一个SELECT
DEPENDENT SUBQUERY 子查询中的第一个SELECT,取决于外面的查询
DERIVED 导出表的SELECT(FROM子句的子查询)
table 表名
type 联接类型
system 表仅有一行(=系统表)。这是const联接类型的一个特例
const 表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const用于用常数值比较PRIMARY KEY或UNIQUE索引的所有部分时
eq_ref 对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY。eq_ref可以用于使用= 操作符比较的带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式
ref 对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用ref。如果使用的键仅仅匹配少量行,该联接类型是不错的。ref可以用于使用=或<=>操作符的带索引的列
ref_or_null 该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化
index_merge 该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素
unique_subquery 该类型替换了下面形式的IN子查询的ref:value IN (SELECT primary_key FROMsingle_table WHERE some_expr);unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高
index_subquery 该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:value IN (SELECT key_column FROM single_table WHERE some_expr)
range 只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range
index 该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小
all 对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出
possible_keys 指出MySQL能使用哪个索引在该表中找到行。注意,该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用
key 显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX
key_len 显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。注意通过key_len值我们可以确定MySQL将实际使用一个多部关键字的几个部分
ref 显示使用哪个列或常数与key一起从表中选择行
rows 显示MySQL认为它执行查询时必须检查的行数
Extra MySQL解决查询的详细信息
Distinct MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行
Not exists MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行
range checked for each record (index map: #) MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。对前面的表的每个行组合,MySQL检查是否可以使用range或index_merge访问方法来索取行
Using filesort MySQL需要额外的一次传递,以找出如何按排序顺序检索行。通过根据联接类型浏览所有行并为所有匹配WHERE子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序,并按排序顺序检索行
Using index 从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。当查询只使用作为单一索引一部分的列时,可以使用该策略
Using temporary 为了解决查询,MySQL需要创建一个临时表来容纳结果。典型情况如查询包含可以按不同情况列出列的GROUP BY和ORDER BY子句时
Using where WHERE子句用于限制哪一个行匹配下一个表或发送到客户。除非你专门从表中索取或检查所有行,如果Extra值不为Using where并且表联接类型为ALL或index,查询可能会有一些错误
Using sort_union(...), Using union(...), Using intersect(...) 这些函数说明如何为index_merge联接类型合并索引扫描
Using index for group-by 类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。并且,按最有效的方式使用索引,以便对于每个组,只读取少量索引条目
例:
explain select user from mysql.user\G;

分析慢查询sql
可写配置文件
| slow_query_log | 开启慢查询日志 |
| long_query_time | 慢查询时间设置,执行时间超过为慢 |
| log_output | table表示慢日志信息存放在mysql.slow_log数据表里;file表示慢日志信息存放在磁盘文件上;none,即使开启了慢日志功能,也不会记录任何慢SQL |
| log_queries_not_using_indexes | 是否记录未使用索引的sql |
| log_slow_admin_statements | 该参数决定是否记录管理类的命令,有 ALTER TABLE,ANALYZE TABLE, CHECK TABLE, CREATE INDEX, DROP INDEX, OPTIMIZE TABLE,REPAIR TABLE,默认是不记录这一类语句到慢日志 |
| log_throttle_queries_not_using_indexes | 该参数决定每分钟记录未使用索引的SQL的数量上限,因为未使用索引的SQL可能会非常多,导致慢日志空间增长飞快。 |
| log_slow_slave_statements | 该参数在从库上设置,决定是否记录在复制过程中超过long_query_time的SQL,如果binlog格式是row,则即使开启了该参数,也不会记录相关SQL |
例:
mysql
->set global slow_query_log=1;
set long_query_time=0.001;
show variables like '%long%'; #不使用索引,进行全表扫描,测试慢查询
#查看日志中的记录
tail -f /var/lib/mysql/node1-slow.log


说明:
- Id为执行sql的线程id号,SHOW FULL PROCESSLIST查看
- Rows_sent为查询返回的结果行数,1行
- Rows_examined为MySQL在找到这一行结果的过程中检查了多少行,599行

浙公网安备 33010602011771号