1 首先给出性能瓶颈定位Show命令
我们可以通过show命令查看MySQL状态及变量,找到系统的瓶颈:
Mysql> show status ——显示状态信息(扩展show status like ‘XXX’)
Mysql> show variables ——显示系统变量(扩展show variables like ‘XXX’)
Mysql> show innodb status ——显示InnoDB存储引擎的状态
Mysql> show processlist ——查看当前SQL执行,包括执行状态、是否锁表等
Shell> mysqladmin variables -u username -p password——显示系统变量
Shell> mysqladmin extended-status -u username -p password——显示状态信息
查看状态变量及帮助:
Shell> mysqld –verbose –help
2 开启 慢查询日志 定位慢 sql 有那些
3 其实最好的办法就是感觉响应慢老板接受不了,必须优化。
MySQL 是存在瓶颈的。 当 MySQL 单表数据量达到千万级别以上时,无论如何对 MySQL 进行优化,查询如何简单,MySQL 的性能都会显著降低。 采取措施:
1)增加 MySQL 配置中的 buffer 和 Cache 的数值,增加服务器 CPU 数量和内存的大小,这样能很大程度上应对 MySQL 的性能瓶颈。
性能优化中,效果最显著、成本最低的当属硬件和服务器优化,所以这是应该首先考虑的。
2)使用第三方引擎或衍生版本。
如 Percona 在功能和性能上较 MySQL 有着显著的提升;由 MySQL 创始人开发的免费 MariaDB 在 InnoDB 引擎上的性能也比 MySQL优秀;
据官网借号,另一款改进的产品 TokuDB,性能是 MySQL 的 10 倍以上。以上这些衍生版或改进版的 MySQL 主要都是针对 MySQL 的 InnoDB
引擎。 InnoDB 每次提交事物时,为了保证数据已经持久化到磁盘(Durable),需要调用一次 fsync 告知文件系统,将可能在缓存中的数据
刷新到次哦按。而 fsync 操作本身是非常『昂贵』的(消耗较多的 I/O 资源,响应较慢),如果每次事物提交都单独做 fsync 操作,那么这里
将是系统 TPS 的一个瓶颈,所以就有了 Group Commit 的概念。 MySQL 5.0 后,处于分布式架构的考虑,为了保证 InnoDB 内部 Commit
和 MySQL 日志的顺序一致,InnoDB 被迫放弃支持 Group Commit。之后,就一直没有好的解决方案了。直到出现 MariaDB,才比较完美的解决
了这个问题。
3)迁移到其它数据库。
如开源的 Post供热SQL 和商业的 Oracle。 与 Oracle 和 PostgreSQL 相比, MySQL 属于线程模式,并且采用了插件引擎的架构。这种实现
的确有自己的优势:轻巧快速、系统资源消耗小、支持更多并发连接,但进程模式能更充分的应用 CPU 资源,在应付复杂业务查询上更有优势。比如,
在常规优化的前提下,Oracle 的但别性能瓶颈经验值在 2 亿数据量的级别,远远优于 MySQL。 不仅如此,在关联查询和内置函数等功能上,
Oracle 都是完胜 MySQL 数据库的。 再比如,PostgreSQL 数据库相比 MySQL,拥有更强大的查询优化器,不会频繁重建索引,支持物化视图等
优势。当然,迁移到其他数据库还要看应用的类型,比如是偏向 OLTP( On-Line Transaction Processing,联机事物处理)的应用还是偏向
OLAP(On-Line Analytical Processing,联机分析处理)应用。
4)对数据库进行分区、分表,减少单表体积。
5)使用NoSQL 等辅助解决方案,如 Memcached、Redis。
6)使用中间件做数据拆分和分布式部署,这方面的典型案例有阿里巴巴对外开源的数据库中间件 Cobar。
7)使用数据库连接池技术。
在第 3 点,我们讲过,MySQL 是线程模式,可以支持更多的并发连接数。MySQL 能支持远比 Oracle 和 PostgreSQL 更多的连接。所以 Oracle
和 PostgreSQL 应用中通常用数据库连接池技术来复用连接。那么 MySQL 为什么还需要用这些数据库应用中常见的数据库连接池技术呢? 原因在于
MySQL 的所机制还不够完善,同时程序中的一些问题都有可能导致 MySQL 数据库连接阻塞,在并发大的情况下,就会浪费很多连接资源和反复连接
的消耗。使用数据库连接池,让连接进行排队和复用,一定程度上可以缓解高并发下的连接压力。
MySQL 瓶颈是真实存在的,但是不少大型互联网公司仍然在使用 MySQL,并且能使用的很好,这一方面是因为这些公司的技术实力足以对 MySQL 进行二次开发和改进,另一方面则得益于其成熟的架构。所以,一个工具能不能用好,人的因素占很大的比重。
先普及以下 GB和Gb区别
0.1342 GB (gigabytes)
1.074 Gb (gigabits)
内存一般不会说Gb,只有GB。
这里,其实就是著名的大B和小b的区别。
一般,通讯上说的,是小b,即bit,意思是位。
8个位是一个字节,叫Byte,就是大B。
我们一般说的宽带,4M,就是4Mb,要除8,才是电脑上一般用的B,下载速度也就是400KB左右。
内存的容量不说Gb,带宽才会涉及到Gb。
基本上,b就是个传输速率才会涉及到的概念。
总结 容量大小度量GB,通讯传输速率大小Gb;
解读:事务隔离级别,Oracle, SQL Server等商业知名数据库默认级别为READ-COMMITTED,而MySQL默认为REPEATABLE-READ,它利用自身独有的Gap Lock解决了"幻读"。但也因为Gap Lock的缘故,相比于READ-COMMITTED级别的Record Lock,REPEATABLE-READ的事务并发插入性能受到很大的限制。
设置:隔离级别的选择取决于实际的业务需求(安全与性能的权衡),如果不是金融、电信等事务级别要求很高的业务,完全可以设置成transaction_isolation=READ-COMMITTED。
解读:InnoDB缓冲池大小,它决定了MySQL可以在内存中缓存多少数据和索引,而不是每次都从磁盘上读取。我们都知道Redis的读写很快,其最重要的原因是它的所有数据都缓存在内存中。试想一下如果innodb_buffer_pool_size足够大,MySQL所有表数据和索引都能被缓存,那将是一种什么体验?
设置:如果是专用的MySQL服务器,一般设置为操作系统内存的75%左右,但至少保留2G内存用于操作系统维护和MySQL异常事件处理。
解读:InnoDB缓冲池实例个数,InnoDB缓冲池是通过一整个链表的方式来管理页面(段、簇、页)的,由于互斥锁的存在(保护链表中的页面),高并发事务下,页面的读取和写入就需要锁的竞争和等待。通过设置innodb_buffer_pool_instances,将一整个链表划分为多个,每个缓冲池实例管理自己的页面和互斥,从而提高效率。
设置:如果缓冲池比较大(8G以上),可以按照innodb_buffer_pool_size / innodb_buffer_pool_instances = 1G进行设置,但如果缓冲池特别大(32G以上),可以按照每个实例2~3G进行划分,实例数不是越多越好,多实例代表多线程,线程的开销(CPU、MEM)也得考虑。
解读:InnoDB日志文件大小(Redo Log),它将事务对InnoDB表的修改记录保存在ib_logfile0、ib_logfile1中。innodb_log_file_size越大,缓冲池中的脏数据需要检查点(checkpoint)进行刷盘的频率就越少,从而减少磁盘IO来降低高并发负载造成的峰值。但日志文件也不是越大约好,由于内存中脏数据刷盘的频率减少,一旦数据库发生异常崩溃,数据库重启时从innodb_log_file中读取数据进行恢复的时间越长。
设置:一般选取业务高峰期一个小时的日志量作为标准,计算过程如下:
# 命令
mysql -uroot -h172.26.96.146 -p -e 'show engine innodb status\G'|grep 'Log sequence number' \
&& sleep 60 \
&& mysql -uroot -h172.26.96.146 -p -e 'show engine innodb status\G'|grep 'Log sequence number'
# 输出
Log sequence number 149949388055
Log sequence number 149959622102
# 计算
( 149959622102 - 149949388055 ) / 1024 / 1024 = 10M
10 / 60 * 3600 = 600M
600 / 2 = 300M
# 解释
Log sequence number代表InnoDB运行至今写入日志的总字节数,两次打印之间线程休眠60秒
得到一分钟之内事务日志记录的总量10M,再转换成一个小时的总量600M
因为`ib_logfile0、ib_logfile1`两个文件循环写入,一个文件为300M
最终,innodb_log_file_size=300M
解读:InnoDB事务日志刷盘时机
当0时,事务提交到日志缓冲区,后台Write线程每隔一秒将缓冲区的日志写入系统缓冲区,实际写入物理日志文件的时机取决于操作系统。
当1时,事务提交到日志缓冲区,Master线程同步将缓冲区的日志直接写入物理日志文件,这完全符合InnoDB ACID事务标准,数据不会丢失。
当2时,事务提交到系统缓冲区,Master线程每隔一秒将系统缓冲区的日志写入物理日志文件。
设置:安全1 > 2 > 0,速度0 > 2 > 1,根据实际业务需求(安全与速度权衡)选择合理的刷盘时机。
解读:InnoDB独立表空间,innodb_file_per_table = ON表示每张表在独立的物理文件中(.ibd)存储数据和索引,innodb_file_per_table = OFF表示所有表都共享表空间即一个物理文件(ibdata1)。如果通过drop/truncate table操作,独立表空间的物理存储会立即被回收(删除/初始化),而共享表空间不会被回收且只会一直增大。
设置:innodb_file_per_table = ON,但需要注意的是,独立表空间只存储数据和索引,如回滚日志缓冲(Undo Log)、插入索引缓冲(Insert Buffer)、二次写缓冲(Doublewrite Buffer)等还是放在共享表空间。
query_cache_size
解读:查询缓存大小,它是为了在追踪表的数据未发生变化时,本次查询命中之前的查询语句,从而跳过解析、优化、执行阶段,直接返回缓冲池中的数据。但实际在OLTP系统中,极少能命中查询缓存(前提是数据库中的数据变化频率很小),因为一旦数据有变则缓存失效。且因为查询缓存会跟踪所有表的变化,它也会成为整个数据库的瓶颈(资源竞争点)。
设置:query_cache_size = 0,同时配合设置query_cache_type = 0,MySQL5.7.20以上、MySQL8.0会直接弃用所有查询缓存配置项。
max_connections
解读:最大连接数,当max_connections设置太小时(默认151),MySQL可能会报错Too many connections。当max_connections设置太大时(1000以上),操作系统可能忙于线程间的切换而失去响应。
设置:每个连接都会消耗一定内存,计算过程如下:
调整Innodb_Buffer_Pool_size大小必须重启mysql进程才可以生效,如今在MySQL5.7里,可以直接动态设置,方便了很多。
这个功能应用的场景:
需要注意的地方,在调整Buffer_Pool期间,用户的请求将会阻塞,直到调整完毕,所以请勿在白天调整,在凌晨3-4点低峰期调整。
调整时,内部把数据页移动到一个新的位置,单位是块。如果想增加移动的速度,需要调整innodb_buffer_pool_chunk_size参数的大小,默认是128M。
例(把BP 128M增大为384M):
mysql> SELECT @@innodb_buffer_pool_size;
+---------------------------+
| @@innodb_buffer_pool_size |
+---------------------------+
| 134217728 |
+---------------------------+
1 row in set (0.00 sec)
mysql> SELECT @@innodb_buffer_pool_chunk_size;
+---------------------------------+
| @@innodb_buffer_pool_chunk_size |
+---------------------------------+
| 134217728 |
+---------------------------------+
1 row in set (0.00 sec)
mysql> SET GLOBAL innodb_buffer_pool_size=402653184;
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT @@innodb_buffer_pool_size;
+---------------------------+
| @@innodb_buffer_pool_size |
+---------------------------+
| 402653184 |
+---------------------------+
1 row in set (0.00 sec)
innodb_buffer_pool_chunk_size的大小,计算公式是innodb_buffer_pool_size / innodb_buffer_pool_instances
比如现在初始化innodb_buffer_pool_size为2G,innodb_buffer_pool_instances实例为4,innodb_buffer_pool_chunk_size设置为1G,那么会自动把innodb_buffer_pool_chunk_size 1G调整为512M,例:
./mysqld --innodb_buffer_pool_size=2147483648 --innodb_buffer_pool_instances=4
--innodb_buffer_pool_chunk_size=1073741824;
mysql> SELECT @@innodb_buffer_pool_size;
+---------------------------+
| @@innodb_buffer_pool_size |
+---------------------------+
| 2147483648 |
+---------------------------+
1 row in set (0.00 sec)
mysql> SELECT @@innodb_buffer_pool_instances;
+--------------------------------+
| @@innodb_buffer_pool_instances |
+--------------------------------+
| 4 |
+--------------------------------+
1 row in set (0.00 sec)
# Chunk size was set to 1GB (1073741824 bytes) on startup but was
# truncated to innodb_buffer_pool_size / innodb_buffer_pool_instances
mysql> SELECT @@innodb_buffer_pool_chunk_size;
+---------------------------------+
| @@innodb_buffer_pool_chunk_size |
+---------------------------------+
| 536870912 |
+---------------------------------+
1 row in set (0.00 sec)
监控Buffer Pool调整进程
mysql> SHOW STATUS WHERE Variable_name='InnoDB_buffer_pool_resize_status';
+----------------------------------+----------------------------------+
| Variable_name | Value |
+----------------------------------+----------------------------------+
| Innodb_buffer_pool_resize_status | Resizing also other hash tables. |
+----------------------------------+----------------------------------+
1 row in set (0.00 sec)
如下命令查看 告警xing'i
mysql> show warnings;
+---------+------+------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------------------------------------+
| Warning | 1292 | Truncated incorrect innodb_buffer_pool_size value: '1073741824' |
+---------+------+------------------------------------------------------------------+
1 row in set (0.00 sec)
出现警告了,再看实际大小
mysql> show variables like '%innodb_buffer_pool_size%';
+-------------------------+-------------+
| Variable_name | Value |
+-------------------------+-------------+
| innodb_buffer_pool_size | 1073741824|
+-------------------------+-------------+
1 row in set (0.00 sec)
如果有警告信息,这是因为,调整后的buffer pool大小必须满足如下条件:
innodb_buffer_pool_chunk_size* innodb_buffer_pool_instances的倍数,即128M的倍数。
1 实战总结innodb_buffer_pool_size =2G,innodb_buffer_pool_instances=1 效果很好。
2 性能优化面广,涉及的方面多,需要根据实际情况而定。
3 仅仅建立索引对性能优化效果有限。
参考文献:
https://www.cnblogs.com/liugx/p/9935749.html
https://blog.csdn.net/nanyanglu/article/details/79109838
https://www.cnblogs.com/sandea/p/11695521.html
Ubuntu 14.04下安装MySQL http://www.linuxidc.com/Linux/2014-05/102366.htm
《MySQL权威指南(原书第2版)》清晰中文扫描版 PDF http://www.linuxidc.com/Linux/2014-03/98821.htm
Ubuntu 14.04 LTS 安装 LNMP Nginx\PHP5 (PHP-FPM)\MySQL http://www.linuxidc.com/Linux/2014-05/102351.htm
Ubuntu 14.04下搭建MySQL主从服务器 http://www.linuxidc.com/Linux/2014-05/101599.htm
Ubuntu 12.04 LTS 构建高可用分布式 MySQL 集群 http://www.linuxidc.com/Linux/2013-11/93019.htm
Ubuntu 12.04下源代码安装MySQL5.6以及Python-MySQLdb http://www.linuxidc.com/Linux/2013-08/89270.htm
MySQL-5.5.38通用二进制安装 http://www.linuxidc.com/Linux/2014-07/104509.htm