From b27a53fe40a61dc0fb5851e61e917c8f6b98d062 Mon Sep 17 00:00:00 2001 From: jackfrued Date: Mon, 28 Oct 2019 01:18:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E7=AC=AC93=E5=A4=A9?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Day91-100/93.MySQL性能优化.md | 103 +++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 10 deletions(-) diff --git a/Day91-100/93.MySQL性能优化.md b/Day91-100/93.MySQL性能优化.md index f037a56..27a7e6e 100644 --- a/Day91-100/93.MySQL性能优化.md +++ b/Day91-100/93.MySQL性能优化.md @@ -70,7 +70,7 @@ MySQL支持做数据分区,通过分区可以存储更多的数据、优化查 | slow_query_log | OFF | | slow_query_log_file | /mysql/data/localhost-slow.log | +---------------------------+----------------------------------+ - + mysql> show variables like 'long_query_time'; +-----------------+-----------+ | Variable_name | Value | @@ -124,24 +124,99 @@ MySQL支持做数据分区,通过分区可以存储更多的数据、优化查 3. 通过`show profiles`和`show profile for query`分析SQL。 + MySQL从5.0.37开始支持剖面系统来帮助用户了解SQL执行性能的细节,可以通过下面的方式来查看MySQL是否支持和开启了剖面系统。 + + ```SQL + select @@have_profiling; + select @@profiling; + ``` + + 如果没有开启剖面系统,可以通过下面的SQL来打开它。 + + ```SQL + set profiling=1; + ``` + + 接下来就可以通过剖面系统来了解SQL的执行性能,例如: + + ```SQL + mysql> select count(*) from tb_emp; + +----------+ + | count(*) | + +----------+ + | 14 | + +----------+ + 1 row in set (0.00 sec) + + mysql> show profiles; + +----------+------------+-----------------------------+ + | Query_ID | Duration | Query | + +----------+------------+-----------------------------+ + | 1 | 0.00029600 | select count(*) from tb_emp | + +----------+------------+-----------------------------+ + 1 row in set, 1 warning (0.00 sec) + + mysql> show profile for query 1; + +----------------------+----------+ + | Status | Duration | + +----------------------+----------+ + | starting | 0.000076 | + | checking permissions | 0.000007 | + | Opening tables | 0.000016 | + | init | 0.000013 | + | System lock | 0.000007 | + | optimizing | 0.000005 | + | statistics | 0.000012 | + | preparing | 0.000010 | + | executing | 0.000003 | + | Sending data | 0.000070 | + | end | 0.000012 | + | query end | 0.000008 | + | closing tables | 0.000012 | + | freeing items | 0.000032 | + | cleaning up | 0.000013 | + +----------------------+----------+ + 15 rows in set, 1 warning (0.00 sec) + ``` + 4. 优化CRUD操作。 - 优化`insert`语句 - 在`insert`语句后面跟上多组值进行插入在性能上优于分开`insert`。 - 如果有多个连接向同一个表插入数据,使用`insert delayed`可以获得更好的性能。 - 如果要从一个文本文件装载数据到表时,使用`load data infile`比`insert`性能好得多。 + - 优化`order by`语句 + - 如果`where`子句的条件和`order by`子句的条件相同,而且排序的顺序与索引的顺序相同,如果还同时满足排序字段都是升序或者降序,那么只靠索引就能完成排序。 + - 优化`group by`语句 + - 在使用`group by`子句分组时,如果希望避免排序带来的开销,可以用`order by null`禁用排序。 + - 优化嵌套查询 + + - MySQL从4.1开始支持嵌套查询(子查询),这使得可以将一个查询的结果当做另一个查询的一部分来使用。在某些情况下,子查询可以被更有效率的连接查询取代,因为在连接查询时MySQL不需要在内存中创建临时表来完成这个逻辑上需要多个步骤才能完成的查询。 + - 优化or条件 + - 如果条件之间是`or`关系,则只有在所有条件都用到索引的情况下索引才会生效。 + - 优化分页查询 + + - 分页查询时,一个比较头疼的事情是如同`limit 1000, 20`,此时MySQL已经排序出前1020条记录但是仅仅返回第1001到1020条记录,前1000条实际都用不上,查询和排序的代价非常高。一种常见的优化思路是在索引上完成排序和分页的操作,然后根据返回的结果做表连接操作来得到最终的结果,这样可以避免出现全表查询,也避免了外部排序。 + + ```SQL + select * from tb_emp order by ename limit 1000, 20; + select * from tb_emp t1 inner join (select eno from tb_emp order by ename limit 1000, 20) t2 on t1.eno=t2.eno; + ``` + + 上面的代码中,第2行SQL是优于第1行SQL的,当然我们的前提是已经在`ename`字段上创建了索引。 + - 使用SQL提示 - - USE INDEX - - IGNORE INDEX - - FORCE INDEX + - USE INDEX:建议MySQL使用指定的索引。 + - IGNORE INDEX:建议MySQL忽略掉指定的索引。 + - FORCE INDEX:强制MySQL使用指定的索引。 ### 配置优化 @@ -164,24 +239,32 @@ show status like 'connections'; show status like 'slow_queries'; ``` -1. 调整max_connections -2. 调整back_log -3. 调整table_open_cache -4. 调整thread_cache_size -5. 调整innodb_lock_wait_timeout -6. 调整`innodb_buffer_pool_size`:InnoDB数据和索引的内存缓冲区大小,以字节为单位,这个值设置得越高,访问表数据需要进行的磁盘I/O操作就越少,如果可能甚至可以将该值设置为物理内存大小的80%。 +1. 调整`max_connections`:MySQL最大连接数量,默认151。在Linux系统上,如果内存足够且不考虑用户等待响应时间这些问题,MySQL理论上可以支持到万级连接,但是通常情况下,这个值建议控制在1000以内。 +2. 调整`back_log`:TCP连接的积压请求队列大小,通常是max_connections的五分之一,最大不能超过900。 +3. 调整`table_open_cache`:这个值应该设置为max_connections的N倍,其中N代表每个连接在查询时打开的表的最大个数。 +4. 调整`innodb_lock_wait_timeout`:该参数可以控制InnoDB事务等待行锁的时间,默认值是50ms,对于反馈响应要求较高的应用,可以将这个值调小避免事务长时间挂起;对于后台任务,可以将这个值调大来避免发生大的回滚操作。 +5. 调整`innodb_buffer_pool_size`:InnoDB数据和索引的内存缓冲区大小,以字节为单位,这个值设置得越高,访问表数据需要进行的磁盘I/O操作就越少,如果可能甚至可以将该值设置为物理内存大小的80%。 ### 架构优化 1. 通过拆分提高表的访问效率。 - 垂直拆分 - 水平拆分 + 2. 逆范式理论。数据表设计的规范程度称之为范式(Normal Form),要提升表的规范程度通常需要将大表拆分为更小的表,范式级别越高数据冗余越小,而且在插入、删除、更新数据时出问题的可能性会大幅度降低,但是节省了空间就意味着查询数据时可能花费更多的时间,原来的单表查询可能会变成连表查询。为此,项目实践中我们通常会进行逆范式操作,故意降低范式级别增加冗余来减少查询的时间开销。 - 1NF:列不能再拆分 - 2NF:所有的属性都依赖于主键 - 3NF:所有的属性都直接依赖于主键(消除传递依赖) - BCNF:消除非平凡多值依赖 + 3. 使用中间表提高统计查询速度。 + + 使用`insert into 中间表 select ... where ...`这样的语句先将需要的数据筛选出来放到中间表中,然后再对中间表进行统计,避免不必要的运算和处理。 + 4. 主从复制和读写分离,具体内容请参考[《项目部署上线和性能调优》](./98.项目部署上线和性能调优.md)。 + 5. 配置MySQL集群。 + + +> **说明**:本章内容参考了网易出品的《深入浅出MySQL》一书,该书和《高性能MySQL》一样,都对MySQL进行了深入细致的讲解,虽然总体感觉后者更加高屋建瓴,但是前者也算得上是提升MySQL技能的佳作(作者的文字功底稍显粗糙,深度也不及后者),建议有兴趣的读者可以阅读这两本书。 \ No newline at end of file