MySQL性能管理及架构设计

影响因素

超高QPS和TPS

QPS: 每秒钟处理查询量(同时处理SQL的数量)

风险:效率低下的sql

并发量 & CPU使用率

并发量:同一时间处理的请求的数量 和同时连接数不一样几千连接数大部分是sleep状态

风险:

大量的并发 数据库连接被占满(max_connections默认100)

超高的CPU使用率 CPU资源耗尽导致宕机

磁盘IO

注意:

最好不要在主库上数据库备份
大型活动前取消备份计划
风险:

磁盘IO性能突然下降(使用更快的磁盘准备)
其他大量消耗磁盘性能的计划任务(调整计划任务,做好磁盘维护)
网卡流量

风险:

网卡IO被占满(1000Mb/8≈100MB)
如何避免无法连接数据库情况:

减少从服务器数量
分级缓存
避免select * 查询
分离业务网络或者服务器网络
其他影响因素

大表

定义:

行数过大,单表超过千万行 日志表等没有更新删除操作,只有插入或者简单查询没啥问题,但是修改表结构不好
数据文件过大,表数据超过10G
对查询的影响:

慢查询 很难在一定时间过滤出需要的数据 大量磁盘IO -> 降低磁盘效率 暗栗
对DDL操作:

建立索引需要很长时间
修改表结构需要长时间锁表
风险:

MySQL < 5.5 建立索引会锁表
MySQL >= 5.5 建立索引会引起主从延迟,长时间主从延迟
影响正常的数据操作(数据库连接数被占满)
如何处理(在下文会有说明):

分库分表

难点:

分表主键的选择
分表后跨分区数据的查询和统计
大表历史数据归档

难点:

减少对前后端业务的影响
归档时间点选择(定单(年),日志(周))
如何进行归档操作
大事务

什么是事务:

原子性 -> 不可分割
一致性 -> 数据完整性
隔离性
SQL标准中定义的四种隔离机别(以下隔离性由低到高,并发性由高到低)

未提交读(脏读)(READ UNCOMMITED)
已提交读(默认)(READ COMMITED)
可重复读(REPEATABLE READ)
可串行化(SERIALIZABLE)

可以通过以下事务指令来验证已提交读和可重复读的区别

begin;

查看隔离级别

show variables like ‘%iso%’;

修改隔离级别

set session tx_isolation=‘read-commited’;
commit;
持久性 -> 一旦提交,永久保存
什么是大事务:

运行时间长,操作数据多的事务

风险:

锁定数据太多
大量阻塞和锁超时
回滚所需时间长
执行时间长,造成主从延迟
如何处理:

避免一次处理太多数据
移出不必要在事务中的SELECT操作
影响性能的几个方面

服务器硬件

CPU资源和可用内存大小

如何选择CPU:

更快的CPU 频率
更多的CPU 数量
CPU密集型应用,当前版本MySQL不支持对同一SQL并发处理,频率 > 数量

系统的并发量如何,例如Web应用,数量 > 频率

MySQL版本,5.6之前的对多CPU支持不好,对于5.6包括之后的多CPU处理比较好

32位和64位CPU选择,这个现在已经不需要选择了,要注意在64位使用32位服务器版本,因为最多寻址4G,对MySQL这个单线程数据库限制很大

内存

常用MySQL存储引擎

MyISAM

索引缓存在内存中,数据缓存在操作系统

InnoDB

在内存同时缓存数据和索引

注意:增加内存对增加数据库性能有限,无法无限增加性能

内存的选择:

内存的主频,选择服务器主板支持主频最高的内存,频率越高速度越快 尽量使用相同品牌,颗粒,频率,电压,校验技术和型号的内存条,单条容量尽可能大。略大于数据库所占磁盘大小最好

磁盘I/O

磁盘的配置和选择:

传统机械磁盘:

特点:

使用最多,价格低,最常见,读写慢,存储空间大

过程:

1.移动磁头到磁盘表面正确位置

2.等待磁盘旋转,使用所需数据在磁头下

3.等待磁盘旋转过去,所有所需数据都被磁头读出

1+2(访问速度) 3(传输速度)

选择:

1.存储容量

2.传输速度

3.访问时间

4.主轴转速

5.物理尺寸(越小时间越短,容量小)

使用RAID增强传统机器硬盘的性能:

定义:

磁盘阵列(Redundant Arrays of Independent Drives,RAID)是由很多块独立的磁盘,组合成一个容量巨大的磁盘组,并提供数据冗余保证数据完整性的技术。

常用RAID级别:

RAID 0是最早出现的RAID模式,即Data Stripping数据分条技术。RAID 0是组建磁盘阵列中最简单的一种形式,只需要2块以上的硬盘即可,成本低,可以提高整个磁盘的性能和吞吐量。RAID 0没有提供冗余或错误修复能力,但实现成本是最低的。
RAID 1称为磁盘镜像,原理是把一个磁盘的数据镜像到另一个磁盘上,也就是说数据在写入一块磁盘的同时,会在另一块闲置的磁盘上生成镜像文件,在不影响性能情况下最大限度的保证系统的可靠性和可修复性
RAID5(分布式奇偶校验的独立磁盘结构)。通过分布式奇偶校验块把数据分散到多个磁盘上,这样如果任何一个盘的数据失效,都可以从奇偶校验块中重建,但是如果两块磁盘失效,整个卷的数据都无法回复,gg。(最经济的磁盘配置)
RAID10(高可靠性与高效磁盘结构)。这种结构无非是一个带区结构加一个镜象结构,因为两种结构各有优缺点,因此可以相互补充,达到既高效又高速的目的。大家可以结合两种结构的优点和缺点来理解这种新结构。这种新结构的价格高,可扩充性不好。主要用于数据容量不大,但要求速度和差错控制的数据库中。(性能最好的配置)

选择:

使用固态存储SSD和PCIe卡:

特点:

相比机械磁盘有更好的随机读写的性能
相比机械磁盘能更好的支持并发
相比机械磁盘更容易损坏
SSD特点:

直接使用SATA接口SATA3.0(6Gbps)SATA2.0(3Gbps)
SATA接口的SSD同样支持RAID但与机械硬盘的RAID不同
PCI-E SSD特点:

无法使用SATA接口
需要独特的驱动和配置
价格比SSD贵
性能比SSD好
需要牺牲部分服务器内存和CPU资源
不要使用RAID,成本太高
选择:

适用于存在大量随机IO的场景
解决单线程负载的I/O瓶颈
使用网络存储NAS和SAN:

SAN特点:

SAN(Storage Area Network)通过光纤连接服务器,通过块接口访问,可以当作硬盘使用
大量顺序读写
随机读写慢
不如本地RAID磁盘
NAS特点:

NAS(Network-Attached Storage)使用网络连接通过基于文件的协议如NFS或SMB访问
延迟
选择:

不适合MySQL数据库存放数据文件 适合数据库备份

网络:

限制:

延迟
带宽
网络的质量对性能影响(丢包)
建议:

高性能高宽带的网络接口设备和交换机
对多个网卡进行绑定,增强可用性和带宽
尽可能进行网络隔离
服务器系统

电脑配置参数(XP默认TCP并发数只有10个) 服务器系统优化参数

系统选择

Windows
FreeBSD
Solaris(稳定性好,良好的多线程)
Linux
CentOS系统参数优化

内核相关参数(/etc/sysctl.conf)

端口监听队列长度

net.core.somaxconn=65535
net.core.netdev_max_backlog=65535
net.ipv4.tcp_max_syn_backlog=65535

加快TCP连接的回收

net.ipv4.tcp_fin_timeout=10
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1

tcp接收和发送缓冲区大小的值

net.core.wmem_default=87380
net.core.wmem_max=16777216
net.core.rmem_default=87380
net.core.rmem_max=16777216

减少失效连接占用的tcp系统资源的数量

net.ipv4.tcp_keepalive_time=120
net.ipv4.tcp_keepalive_intvl=30
net.ipv4.tcp_keepalive_probes=3

定义单个共享内存段最大值(足够大)

容纳整个innodb缓冲池大小

注意,对于64位Linux,可取最大值为物理内存-1byte,建议大于物理内存一半,一般取值大于innodb缓冲池大小即可。

kernal.shmmax = 4294967295

系统内存交换分区(磁盘虚拟内存)

保留交换分区很重要,但是要控制何时使用交换分区

这个参数只有在虚拟内存完全满了才能使用交换分区

vm.swappiness=0
增加资源限制(/etc/security/limit.conf)

以下两句加到文件末尾

* 对所有用户有效

soft 当前系统生效设置

hard 系统中所能设定的最大值

nofile 所限制资源是打开文件的最大数目

限制的数量

  • soft nofile 65535
  • hard nofile 65535

65535 保证可以打开足够多的文件句柄

重启操作系统生效

磁盘调度策略(/sys/block/devname/queue/scheduler)

cat /sys/block/sda/queue/scheduler

默认的cfq策略

noop anticipatory deadline [cfq]

查看当前系统支持的IO调度算法

dmesg | grep -i scheduler

out

io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered (default)

查看当前系统的I/O调度方法:

cat /sys/block/sda/queue/scheduler

out

noop anticipatory deadline [cfq]

临地更改I/O调度方法:

例如:想更改到noop电梯调度算法:

echo noop > /sys/block/sda/queue/scheduler

想永久的更改I/O调度方法:

修改内核引导参数,加入elevator=调度程序名

vi /boot/grub/menu.lst

更改到如下内容:

kernel /boot/vmlinuz-2.6.18-8.el5 ro root=LABEL=/ elevator=deadline rhgb quiet

需要重启才能修改调度方法

noop(电梯式调度策略)

NOOP实现了一个简单的FIFO队列,它像电梯的工作主法一样对I/O请求进行组织,当有一个新的请求到来时,它将请求合并到最近的请求之后,以此来保证请求同一介质.NOOP倾向饿死读而利于写.NOOP对于闪存设备,RAM,嵌入式系统是最好的选择.
读操作需要等待下一次读操作完成

写请求通过合并堆积到I/O队列

deadline(截止时间调度策略)

Deadline确保了在一个截止时间内服务请求,这个截止时间是可调整的,而默认读期限短于写期限.这样就防止了写操作因为不能被读取而饿死的现象.Deadline对数据库类应用是最好的选择.
anticipatory(预料I/O调度策略)

本质上与Deadline一样,但在最后一次读操作后,要等待6ms,才能继续进行对其它I/O请求进行调度. 可以从应用程序中预订一个新的读请求,改进读操作的执行,但以一些写操作为代价. 它会在每个6ms中插入新的I/O操作,而会将一些小写入流合并成一个大写入流,用写入延时换取最大的写入吞吐量.AS适合于写入较多的环境,比如文件服务器 AS对数据库环境表现很差.
文件系统的选择

Windows : FAT NTFS(是win服务器的唯一选择) Linux : EXT3 EXT4 XFS(都有日志功能)

EXT3/4系统挂在参数(/etc/fstab)

writeback 只有原数据写入到日志,innodb有自己的日志系统,最好,最快

ordered 比writeback稍微慢,一旦崩溃更加安全

journal 不适合innodb

data=writeback | ordered | journal
noatime
nodiratime

/dev/sda1/ext4 noatime,nodiratime,data=writeback 1 1
数据库存储引擎的选择

MySQL体系结构图

插件式存储引擎

MyISAM:不支持事务,表级锁(MySQL5.5之前版本默认存储引擎)

MyISAM存储引擎表由MYD和MYI组成

create table ‘tablename’(…)ENGINE=MyISAM DEFAULT CHARSET=utf8
特性:

并发性与锁级别(读写互斥,只读操作可以接受,读写混合操作支持不好)
表损坏修复(不支持事务恢复)
check table [tablename]
repair table [tablename]
MyISAM表支持全文索引,前缀索引
MyISAM表支持数据压缩(只能读)
myisampack -b -f(强制) tablename.MYI
限制:

<5.0版本单表最大4G(大表需要修改MAX_Rows和AVG_ROW_LENGTH)
5.0版本支持256TB
场景:

非事务型应用
只读类应用
空间类应用(支持空间函数,GPS数据等)
InnoDB:事务级存储引擎,完美支持行级锁,事务ACID特性(MySQL5.5之后版本默认存储引擎)

使用表空间存储:

innodb_file_per_table ON:独立表空间:tablename.ibd OFF:系统表空间:ibdataX

show variables like ‘innodb_file_per_table’
比较:

系统表空间无法简单的收缩文件大小
独立表空间可以通过optimize table命令收缩系统文件
系统表空间会产生IO瓶颈(多个表IO操作)
独立表空间可以同时向多个文件刷新数据
系统表空间->独立表空间步骤:

使用mysqldump导出所有数据库表数据
停止MySQL服务,修改参数,并删除Innodb相关文件
重启MySQL服务,重建Innodb系统表空间
重新导入数据
注意下面的系统表空间数据:

Innodb数据字典信息 Undo回滚段

特性:

事务性存储引擎
完全支持事务的ACID特性
Redo Log和Undo Log(事务)

Redo Log 存储的是已提交的事务(顺序写入)

Undo Log 存储的是未提交的事务(随机读写)

show virables like ‘innodb_log_buffer_size’

log 文件数量

show virables like ‘innodb_log_files_in_group’

支持行级锁
行级锁可以最大程度的支持并发
行级锁是由存储引擎层实现(MySQL完全不了解锁的实现方式)
锁作用:

管理共享资源的并发访问
用于实现事务的隔离性
锁类型:

共享锁(也称读锁)
独占锁(也称写锁)

测试锁

开启事务

begin;

update 数据

进入另一个client进行select操作

因为事务没有commit,查到的数据不变

rollback;
锁粒度:

表级锁(基本锁策略,开销小)
行级锁

加表级锁

lock table write;

这时候在另一个client执行查询就会阻塞

unlock tables;

这时候在另一个client才能执行查询

阻塞和死锁
阻塞:不同锁之间兼容性关系,同一时刻,一个事务需要等待另一个事务的锁释放它所占用资源,产生阻塞。

死锁:两个或两个以上事务在执行过程中相互占用了对方占用的资源。

系统可以处理死锁:资源占用最少的事务进行回滚操作。

Innodb状态检查:

show engine innodb status [\G]
场景:

Innodb适用于大多数OLTP应用
5.7之后支持全文索引和空间函数
CSV存储引擎

存储格式:csv文件

特点:

以文本方式存储在文件中
.csv文件存储表内容
.csm文件存储表的元数据如表状态和数据量
.frm文件存储表结构信息
所有列不能为NULL
不支持索引,不适合大表,不适合在线处理
可以对数据文件直接编辑
场景:

数据交换中间表
电子表格->CSV文件->MySQL数据目录
数据->CSV文件->其他web程序
Archive存储引擎

特点:

以zlib对表数据进行压缩,磁盘I/O更少
数据存储引擎在ARZ为后缀的文件中
只支持insert和select操作
支持行级锁和缓冲区,但是本身不是事务型存储引擎
只允许在自增ID列建立索引
场景:

日志和数据采集类应用
Memory存储引擎

也称HEAP存储引擎,所以数据是保存在内存中的
重启之后数据消失,表重建
IO效率比MyISAM高得多
支持HASH索引和BTree索引
create index inx_1 on ()
create index inx_1 using btree on ()
HASH索引对等值查询比较快,对范围查找支持不好;BTree索引对范围查找支持比较好
所有字段都为固定长度varchar(10)=char(10)
不支持BLOG和TEXT大字段类型
使用表级锁(性能不见的比Innodb好)
最大大小由max_heap_table_size参数确定,最大默认16M(需要重建表)
和临时表区别:

临时表分为查询优化器使用的系统临时表和create temporary table创建的临时表,只对当前session可见。
Memory存储引擎表不是临时表
系统使用临时表如果内存未超限制可以使用Memory临时表,如果超限则需要使用MyISAM临时表
create temporary table创建的临时表可以使用任何存储引擎
场景:

用于查找或映射表,例如邮编地区对应表
用于保存数据分析中产生的中间表
用于缓存周期性聚合数据的结果表
Federated存储引擎

特点:

提供了访问远程MySQL服务器上表的方法
本地不存储数据,数据全部存放在远程服务器上
本地需要保存表结构和远程服务器的连接信息
可以实现SQL Server连接服务器的功能(性能不好)
默认禁止,启用需要在启动时增加federated参数
mysql://user_name[:password]@host_name[:port_num]/db_name/tbl_name

查看是否支持

show engine;

配置文件中 federated = 1 重启服务

在远程数据库建表并设置远程数据库权限

grant select,update,insert,delete on . to fred_link@‘127.0.0.1’ identified by ‘12345678’;

在本地数据库建相同的表

create table (…) engine=federated connection=‘mysql://fred_link:[email protected]:3306//’

操作远程数据库

场景:

偶尔的统计分析及手工查询
如何选择存储引擎

大多情况选择innodb

参考条件:

事务(innodb)
备份(innodb在线热备份)
崩溃恢复(innodb)
存储引擎特有特性
不需要事务,主要做select和insert操作可以考虑MYISAM
大都insert操作select很少可以考虑Archive存储引擎
注意:尽量不要混合使用多个存储引擎
数据库参数配置

参数很重要,有时候如下图所示

大多参数配置可以查看我之前写的 CentOS-7系统初始化以及MySQL配置优化

MySQL获取配置信息路径

命令行参数
mysqld_safe --datadir=/data/sql_data
配置文件

查询默认配置文件读取顺序

mysqld --help --verbose | grep -A 1 ‘Default options’

MySQL配置参数的作用域

全局参数
set global = ;
set @@global. := ;
会话参数
set [session] = ;
set @@session. := ;
内存相关的参数

确定可使用的内存上限
确定MySQL的每个连接使用的内存(分配全部内存)

排序缓冲区大小

sort_buffer_size

连接缓冲区大小

join_buffer_size

对一个表全表扫描时 4K的倍数

read_buffer_size

索引缓冲区大小

read_rnd_buffer_size

以上四个是为每个线程分配

确定为OS保留的内存(服务器只布mysql)
如何为缓冲池分配内存

innodb使用缓冲池大小,重要,缓存索引,缓存数据,锁,内部数据结构,使用缓冲池延缓写入

innodb性能严重依赖这个参数

总内存 -(每个线程所需要内存*连接数)- 系统保留内存

服务器总内存 75% 以上

Innodb_buffer_pool_size

myisam存储引擎缓冲池大小

key_buffer_size
select sum(index_length) from information_schema.tables where engine=‘myisam’

全部使用innodb也需要为这个分配内存,因为mysql内部表还是使用myisam存储引擎

I/O相关配置参数

Innodb I/O相关配置

控制单个事务日志文件大小

Innodb_log_file_size

控制文件个数 (用处不大)

Innodb_log_files_in_group

事务日志总大小 = 上面两个参数相乘

日志缓冲区大小 32M~128M

Innodb_log_buffer_size

0:每秒进行一次log写入cache, 并flush log到磁盘

1[默认]:每次提交每次写入cache,并flush log到磁盘

2[建议]:每次提交每次写入cache,每秒flush log到磁盘

Innodb_flush_log_at_trx_commit

避免操作系统和Innodb对数据双重缓存

通知操作系统不要进行缓存,所有读写都通过存储设备来完成

Innodb_flush_method=O_DIRECT

为每个表建立单独表空间

Innodb_file_per_table = 1

双写缓存增加数据安全性,防止页数据损坏写入之后造成数据损坏

Innodb_doublewrite = 1

MyISAM I/O相关配置

ON:只对在建表时指定了delay_key_write选项的表使用延迟刷新

OFF:每次写操作后刷新键盘缓冲中的脏块到磁盘

ALL:对所有MYISAM表都使用延迟键写入

delay_key_write
安全相关配置参数

指定自动清理binlog的天数

expire_logs_days

控制MySQL可以接收的包的大小

max_allowed_packet

禁用DNS查找

skip_name_resolve

确保sysdate()返回确定性日期

防止主从复制不一致

sysdata_is_now

禁止非super权限用户的写权限

保证主从安全性

read_only

禁用Slave自动恢复

skip_slave_start

设置MySQL所使用的SQL模式

sql_mode

sql_mode

strict_trans_tables(如果给定数据不能插入,会中断事务操作)
no_engine_subtitution(如果指定存储引擎不可用,不使用默认存储引擎)
no_zero_date(顾名思义)
no_zero_in_date
only_full_group_by(如果group by中的列不在select语句中,则执行不会成功)
其他常用配置参数

控制MySQL如何向磁盘刷新binlog日志

设置为1可以保证每次事务都写日志

sync_binlog

控制内存临时表大小(值保持一致)

tmp_table_size
max_heap_table_size

控制允许最大连接数(默认100建议千以上)

max_connections
数据库表结构设计和SQL语句

这一节虽然少,但是最重要,如果做的好可能会超过上文的所有优化

库表结构设计

数据库设计对性能的影响

过分的反范式化为表建立太多列
过分的范式化造成太多的表关联
在OLTP环境中错误的使用了不恰当的分区表
使用外键保证数据的完整性
尤其是大表尽量减少使用外键约束(个人观点)

总结

性能优化顺序

数据库结构设计和SQL语句优化
数据库存储引擎选择和参数配置
系统选择和优化
硬件升级
基准测试

定义:基准测试是指通过设计科学的测试方法、测试工具和测试系统,实现对一类测试对象的某项性能指标进行定量的和可对比的测试。可能不关心业务逻辑。
MySQL基准测试目的

建立MySQL服务器的性能基准线
模拟比当前系统更高的负载,以找出系统的扩展瓶颈
测试不同的软硬件和操作系统配置
证明心的硬件设备配置是否正确
优点:

测试整个系统的性能,包括web服务器、缓存、数据库等
反映出系统各个组件接口性能问题体现真实性能情况
MySQL基准测试常见指标

单位时间处理事务数(TPS)
单位时间处理查询数(QPS)
响应时间(平均、最大、最小响应时间,各个时间所占百分比)
并发量(≠连接数):同时处理查询请求的数量
计划和设计基准测试

对整个系统还是某一组件
使用什么样的数据
准备基准测试以及数据处理脚本(CPU、IO、网络流量、状态和计数器信息等)
#!/bin/bash
INTERVAL=5
PREFIX=/home/imooc/benchmarks/$INTERVAL-sec-status
RUNFILE=/home/imooc/benchmarks/running
echo “1” > $RUNFILE
MYSQL=/usr/local/mysql/bin/mysql
$MYSQL -e “show global variables” >> mysql-variables
while test -e RUNFILE;dofile=RUNFILE; do file=(date +%F_%I)
sleep=$(date +%s.%N | awk ‘{print 5 - ($1 % 5)}’)
sleep sleepts=&quot;sleep ts=&quot;(date +“TS %s.%N %F %T”)"
loadavg=“(uptime)&quot;echo&quot;(uptime)&quot; echo &quot;ts $loadavg” >> PREFIXPREFIX-{file}-status
$MYSQL -e “show global status” >> PREFIXPREFIX-{file}-status &
echo “$ts $loadavg” >> PREFIXPREFIX-{file}-innodbstatus
$MYSQL -e “show engine innodb status” >> PREFIXPREFIX-{file}-innodbstatus &
echo “$ts $loadavg” >> PREFIXPREFIX-{file}-processlist
$MYSQL -e “show full processlist\G” >> PREFIXPREFIX-{file}-processlist &
echo $ts
done
echo Exiting because $RUNFILE does not exists
运行基准测试
保存以及分析基准测试结果
#!/bin/bash
awk ’
BEGIN {
printf “#ts date time load QPS”;
fmt=" %.2f";
}
/^TS/ {
ts = substr($2,1,index($2,".")-1);
load = NF -2;
diff = ts - prev_ts;
printf “\n%s %s %s %s”,ts,$3,4,substr(4,substr(load,1,length($load)-1);
prev_ts=ts;
}
/Queries/{
printf fmt,($2-Queries)/diff;
Queries=KaTeX parse error: Expected 'EOF', got '}' at position 6: 2 }̲ ' "@"
容易忽略的问题

使用生产环境数据时只使用了部分数据
在多用户场景中,只做单用户的测试
在单服务器测试分布式应用
反复执行统一查询
基准测试工具

mysqlslap

特点:

模拟服务器负载,并输出相关统计信息
可以指定也可以自动生成查询语句
常用参数说明

–auto-generate-sql(系统自动生成SQL脚本测试)
–auto-generate-sql-add-autoincrement(在生成的表中增加自增主键)
–auto-generate-sql-load-type(指定测试中使用的查询类型)
–auto-generate-sql-write-number(指定初始化数据时生成的数据量)
–concurrency(指定并发线程数量)
–engine(指定要测试表的存储引擎,可以用逗号分割多个存储引擎)
–no-drop(指定不清理测试数据)
–iterations(指定测试运行次数)
–number-of-queries(指定每个线程查询数量)
–debug-info(指定输出额外的内存及CPU统计信息)
–number-int-cols(指定测试表中包含的int类型列的数量)
–number-char-cols(指定测试表中包含的varchar类型列的数量
–create-schema(指定用于执行测试的数据库名字)
–query(自定义sql脚本)
–only-print(不运行脚本,而是把生成脚本打印出来)
mysqlslap --concurrency=1,50,100,200 --iterations=3 --number-int-cols=5 --number-char-cols=5 --auto-generate-sql --auto-generate-sql-add-autoincrement --engine=myisam,innodb --number-of-queries=10 --create-schema= [–only-print]
sysbench

安装:

wget https://github.com/akopytov/sysbench/archive/0.5.zip --no-check-certificate
unzip sysbench-0.5.zip
cd sysbench
sudo yum install automake
sudo yum install libtool
./autogen.sh
./configure --with-mysql-includes=/usr/include/mysql/ --with-mysql-libs=/usr/lib64/mysql/
make && make install
常用参数

–test(指定所要执行的测试类型,支持以下参数)
Fileio 文件系统I/O性能测试
cpu cpu性能测试
memory 内存性能测试
Oltp 测试要指定的lua脚本 Lua脚本位于sysbench-0.5/sysbench/tests/db
–mysql-db(指定数据库名)
–mysql-table-engine(指定存储引擎)
–olpt-tables-count(执行测试表的数量)
–olpt-table-size(表数据行数)
–num-threads(并发线程数)
–max-time(最大测试时间)
–report-interval(输出信息时间间隔)
–mysql-user
mysql-password
prepare(准备测试数据)
run(实际测试)
cleanup(清理测试数据)
sysbench --test=cpu --cpu-max-prime=10000 run
sysbench --test=fileio --file-total-size=1G prepare

查看参数

sysbench --test=fileio help
sysbench --test=fileio --num-threads=8 --init-rng=on --file-total-size=1G --file-test-mode=rndrw --report-interval=1 run

测试MySQL脚本

创建一个库

create database imooc;
grant all privileges on . to xuwenchao@‘localhost’ identified by ‘12345678’;

cd /home/xuwenchao/sysbench/sysbench-0.5/sysbench/tests/db
sysbench --test=./oltp.lua --mysql-table-engine=innodb --oltp-table-size=10000 --mysql-db=imooc --mysql-user=xuwenchao --mysql-password=12345678 --oltp-tables-count=10 --mysql-socket=/usr/local/mysql/data/mysql.sock prepare
数据库结构优化

目的:

减少数据冗余
尽量避免数据维护中出现更新,插入和删除异常(范式化设计)
节约存储空间
步骤:

需求分析:全面了解产品设计的存储需求
逻辑设计:设计数据逻辑存储结构
物理设计:根据所使用数据库特点进行表结构设计
维护优化:根据实际情况对索引存储结构等进行优化
三范式:重要,但是不总结了,已经学烂了…

关于基本用法这里就不多说了,关于sql索引和查询优化在下面总结。

高可用架构设计

MySQL复制功能

作用:

分担读负担
为高可用、灾难恢复、备份提供更多选择
实现在不同服务器的数据分布
利用二进制日志增量进行
不需要太多带宽
使用基于行的复制进行大批量更改时候会带来一定带宽压力
特别是跨IDC环境复制
实现数据读取的负载均衡
需要其他组件配合完成
利用DNS轮询的方式把程序的读连接到不同的备份数据库
利用LVS,haproxy这样的代理方式
非共享架构,同样的数据分布在多台服务器
增加了数据的安全性
利用备份的备库来减少主库的负载
复制并不能代替备份
方便进行数据库高可用架构部署
避免MySQL单点失败
实现数据库高可用和故障切换
实现数据库升级
二进制日志

MySQL日志

二进制日志作用

记录了所有对MySQL数据库的修改事件 包括增删改查事件和对表结构修改事件,通过binlog命令行工具进行查看

二进制日志格式

基于段的格式 binlog_format=STATEMENT

优点:

因为记录的是事件执行的SQL语句,日志记录量相对小,节约磁盘和网络I/O
注意:只对一条记录修改或插入,row格式所产生的日志量小于段产生的
缺点:

必须记录上下文信息以保证从服务器执行结果和主服务器相同
特定函数如UUID(),user(),非确定性函数无法复制,造成主从服务器数据不一致,中断复制链路

查看日志格式

show variables like ‘binlog_format’;

刷新日志

fulsh logs;

查看日志

show binary logs;

进入系统查看日志

mysqlbinlog mysql-bin.000002
mysqlbinlog -vv mysql-bin.000002
基于行的格式 binlog_format=ROW

同一SQL语句修改了1000条数据的情况下,基于段的日志格式只会记录这个SQL语句,基于行的日志会有1000条记录记录每一行的修改
优点:

避免复制过程中出现的主从不一致的情况,zhu从复制更加安全(只需要应用对行的更改,不需要重新执行SQL语句)
对每一行的修改比基于段的复制高效
缺点:

记录日志量大(binlog_row_image=[FULL|MINIMAL|NOBLOB])
混合日志格式binlog_format=MIXED

特点:

根据sql语句由系统决定基于段和基于行的日志格式中进行选择
数量的大小由所执行的SQL语句执行
建议

Binlog_format=mixed
or
Binlog_format=row
Binlog_row_image=minimal
二进制日志格式对复制的影响

基于SQL语句的复制(SBR)

优点:

日志量少,节约网络传输I/O
并不强制要求主从数据库表定义完全一样
相对基于行复制更加灵活
缺点:

对于非确定事件,无法保证主从复制数据的一致性
对于存储过程,触发器,自定义函数进行的修改也可能造成数据不一致
相对基于行复制执行时需要更多的行锁
基于SQL语句的复制(SBR)

优点:

可以应用任何SQL的复制包括非确定函数,存储过程等
可以减少数据库锁的使用(性能高)
缺点:

主从数据库表结构必须一致
无法在从服务器单独执行触发器
复制的工作方式

主服务器将变更写入二进制日志
从服务器读取主服务器的二进制日志变更写入到relay_log中
在从服务器上重放relay_log中的日志基于SQL段(statement)的日志是在从服务器上重新执行记录的SQL
基于行的日志(row)则是在从库上直接应用对数据库行的修改
基于日志点复制的步骤

在主DB服务器上建立复制账号
CREATE USER ‘repl’@‘ip’ IDENTIFIED by ‘password’;
GRANT replication SLAVE ON . TO ‘repl’@‘ip’;
配置主数据库服务器
log_bin = mysql_bin
max_binlog_size = 1000M
binlog_formart = row
expire_logs_day = 7
sync_binlog = 1
server_id = 100 #动态参数,集群中唯一
配置从数据库服务器
log_bin = mysql_bin
relay_log = mysqld-relay-bin
server_id = 101
relay_id = mysql-relay-bin
log_slave_update = on #可选 如果变成主服务器必须配置
read_only = on #可选
初始化从服务器数据

innodb推荐

mysqldump --master-data=2 -single-transaction

推荐的热备份工具

xtrabackup --slave-info
启动复制链路
CHANGE MASTER TO MASTER_HOST = ‘master_host_ip’,
MASTER_USER = ‘repl’,
MASTER_PASSWORD = ‘password’,
MASTER_LOG_FILE = ‘mysql_log_file_name’,
MASTER_LOG_POS = 4;
start slave

备份指令

mysqldump --single-transaction --master-data --triggers --routines --all-databases -uroot -p >> all.sql

在从服务器使用all.sql脚本

mysql -uroot -p < all.sql

MASTER_LOG_FILE和MASTER_LOG_POS在all.sql中获得

show slave status \G
start slave;

查看复制进程

show processlist;
优点:

是Mysql最早支持的复制技术,bug相对较少
对SQL查询没有任何限制
故障处理比较容易
缺点:

故障转移时重新获取新主的日志点信息比较困难
如果偏移量错误可能造成遗漏或重复
基于GTID复制

定义:全局事务ID,保证每一个在主上提交的事务在复制集群中可以生成唯一的ID GTID=source_id:transaction_id
在主DB服务器上建立复制账号
CREATE USER ‘repl’@‘ip’ IDENTIFIED by ‘password’;
GRANT replication SLAVE ON . TO ‘repl’@‘ip’;
配置主数据库服务器
bin_log=/usr/local/mysql/log/mysql-bin
server_id=100
gtid_mode=on
enforce-gtid-consiste

启用上面参数,下面语句不可用

create table … select

log-slave-updates=on
配置从数据库服务器
server_id=101
relay_log=/usr/local/mysql/log/relay_log
gtid_mode=on
enforce-gtid-consiste

建议

log_slave_update = on #可选 如果变成主服务器必须配置
read_only = on #可选
master_info_repository=TABLE
relay_log_info_repository=TABLE
初始化从服务器数据

innodb推荐

mysqldump --master-data=2 -single-transaction

推荐的热备份工具

xtrabackup --slave-info

最后记录备份时最后事务的GTID值

启动复制链路
CHANGE MASTER TO MASTER_HOST = ‘master_host_ip’,
MASTER_USER = ‘repl’,
MASTER_PASSWORD = ‘password’,
MASTER_AUTO_POSITION = 1;
start slave
优点:

可以很方便的进行故障转移
从库不会丢失主库上的任何修改
缺点:

故障处理比较复杂
对执行的SQL有一定限制
选择复制模式

所使用MySQL版本(<=5.6 不能用GTID)
复制架构以及主从切换方式
所使用高可用管理组件(下文详细介绍)
对应用的支持程度
MySQL复制拓扑结构

MySQL5.7之前一个从库只能有一个主库

MySQL5.7之后一个从库可以有多个主库

一主多从复制拓扑

优点:

配置简单
多个从库分担读负载
用途:

为不同业务使用不同的从库
将一台从库放到远程IDC,用作灾备恢复
分担主库读负载(但是主库上的写仍然会被复制到从库)
主-主复制拓扑

(ServerId不同) 主主模式

两个都充当主库

注意:

产生数据冲突造成复制链路中断,耗费大量时间造成数据丢失
两个主中操作的表最好分开
使用下面两个参数控制自增id生成 auto_increment_increment = 2 auto_increment_increment = 1 | 2
主备模式

只有一台服务器对外提供服务,另一台处于只读状态并只作为热备使用

注意:

确保初始数据相同
确保两台服务器已经启动binlog并具有不同的server_id
在两台服务器启用log_slave_updates参数
在初始备库启用read_only
拥有备库的主主复制拓扑

级联复制

上面的方式可以解决多个从库对主库网络IO和额外负载的影响

MySQL复制性能优化

再看一下这张图

影响主从延迟的因素:

主库写入二进制日志的时间
优化方案:

控制主库事务的大小,分割事务大小
二进制日志传输并写入从库的时间
优化方案:

使用MIXED日志格式记录日志,设置set binlog_row_image=minimal;
默认情况从库只有一个SQL线程,主上并发的修改在从库变成了串行(只有像大促这种活动体现出来慢)
优化方案:

使用多线程复制(5.6之后添加的功能),有时候可能不如单线程

停止链路复制

stop slave;
set global slave_parallel_type=‘logical_clock’;
set global slave_parallel_workers=4;

开启

start slave;
MySQL复制常见问题

由于数据损坏或丢失引起的主从复制错误

主库或从库意外宕机引起的错误
解决方案:

使用跳过二进制日志事件
注入空事务的方式先恢复中断的复制链路
使用其它方法对比主从服务器数据(下文介绍)
主库二进制文件损坏
解决方案:

通过change master重新指定(会丢失一些数据)
备库中继日志损坏
在从库进行数据修改造成主从复制错误
解决方案:

设置read_only参数
不唯一的server_id或server_uuid
max_allow_packet设置引起的主从复制错误
MySQL复制无法解决的问题

分担主数据库写负载
解决方案:

分库分表(下文)
自动进行故障转移以及主从切换
提供读写分离功能
关于高可用架构

高可用性:通过尽量缩短日常维护和突发系统崩溃所导致的停机时间提高系统和应用的可用性99999 9999 999 999

影响因素:

服务器磁盘空间耗尽
性能糟糕的SQL
表结构和索引没有优化
主从数据不一致
认为操作失败
如何实现:

避免导致系统不可用因素,减少系统不可用时间
建立完善的监控及报警系统
对备份数据恢复测试
正确配置数据库环境(注意readonly)
对不需要的数据归档和清理(innodb使用独立表空间)
增加系统冗余,保证系统不可用时可以尽快恢复
避免存在单点故障

共享存储本身就会成为一个单点,如果出问题,恢复起来比较麻烦;DRDB故障转移时时间长,转移时不能提供读服务

利用多写集群或NDB集群(对内存要求高,限制多)来解决单点故障

利用主从复制解决单点问题

主从切换之后如何通知应用新的主服务器IP
如何检查主服务器可用
如何处理从服务器和主服务器的复制关系
主从切换及数据转移
MMM架构

MMM架构是主备模式的数据库架构

需要的资源列表

部署步骤

配置主主复制以及主从同步集群
安装主从节点所需支持包
安装及配置MMM工具集
运行MMM监控服务
测试

1.创建数据库用户

2.备份数据库并同步到其他数据库

3.配置主从主主复制

前三条前面都有,不多写了

各个服务器分别安装mmm

yum search mmm
yum install mysql-mmm-agent.noarch -y

监控节点安装

yum install mysql-mmm* -y

创建用户

搭建mmm,具体搭建细节不再赘述,有需要的可以联系管理员

优点

使用Perl脚本语言开发及完全开源
提供了读写VIP(虚拟IP),使服务器角色变更对前端应用透明
在从服务器出现大量主从延迟,主从链路中断时可以把这台从服务器读的虚拟IP漂移到集群中其他正常服务器。
MMM提供从服务器的延迟监控
MMM提供了主数据库故障转移后从服务器对主服务器重新同步功能
很容易对发生故障的主数据库重新上线
缺点

发布时间早,不支持MySQL新的复制功能 (只支持基于日志点的复制)
没有读负载均衡的功能
在进行主从切换时,容易造成数据缺失
存在单点故障
MMH架构(Master High Availability)

在MySQL故障切换过程中,MHA能做到0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能最大程度上保证数据库的一致性,以达到真正意义上的高可用。

MHA由两部分组成:

MHA Manager(管理节点)和MHA
Node(数据节点)
MHA Manager可以独立部署在一台独立的机器上管理多个Master-Slave集群,也可以部署在一台Slave上。当Master出现故障时,它可以自动将最新数据的Slave提升为新的Master,然后将所有其他的Slave重新指向新的Master。整个故障转移过程对应用程序是完全透明的。
Manager工具包情况如下:

masterha_check_ssh:检查MHA的SSH配置情况。
masterha_check_repl:检查MySQL复制状况。
masterha_manager:启动MHA。
masterha_check_status:检测当前MHA运行状态。
masterha_master_monitor:检测Master是否宕机。
masterha_master_switch:控制故障转移(自动或手动)。
masterha_conf_host:添加或删除配置的server信息。

Node工具包(通常由MHA Manager的脚本触发,无需人工操作)情况如下:

save_binary_logs:保存和复制Master的binlog日志。
apply_diff_relay_logs:识别差异的中级日志时间并将其应用到其他Slave。
filter_mysqlbinlog:去除不必要的ROOLBACK事件(已经废弃)
purge_relay_logs:清除中继日志(不阻塞SQL线程)
MHA工作原理

从宕机崩溃的Master保存二进制日志事件(binlog event);
识别含有最新更新的Slave;
应用差异的中继日志(relay log)到其他Slave;
应用从Master保存的二进制日志事件;
提升一个Slave为新的Master;
使其他的Slave连接新的Master进行复制;
MHA配置步骤

配置集群所有主机的SSH免认证登录
安装MHA-node软件包和MHA-manager软件包
yum -y install perl-Config-Tiny.noarch per-Time-HiRes.x86_64perl-Parallel-ForkManager perl-Log-Dispatch-Perl.noarchperl-DBD-MySQL ncftp
建立主从复制集群
配置MHA管理节点
使用masterha_check_ssh和masterha_check_repld对配置进行检验
启动并测试MHA服务
部署步骤

略,有需要联系管理员

优点

Perl语言开发的开源工具
支持GTID的复制模式
MHA在进行故障转移时更不易产生数据丢失
同一个监控节点可以监控多个集群
加强了数据的安全性
优点

需要编写脚本或利用第三方工具来实现Vip的配置
MHA启动后只会对主数据库进行监控
需要基于SSH的免认证登录,存在一定安全隐患
没有提供从服务器的读负载均衡
读写分离与负载均衡

主从复制目的:分担主库读负载

读写分离原因:读既可以在主库运行又可以在从库运行,写操作只能在主库运行

两种读写分离方式:

程序实现
优点:

由开发人员控制那些查询在从库执行,比较灵活
程序直连数据库,性能耗损较少
缺点:

增加开发量,代码更复杂
人为控制容易出现错误
中间件实现
mysql-proxy

性能和稳定性不好,不建议使用

maxScale 优点:

由中间件根据查询语法分析,自动完成读写分离
对程序透明,对已有程序不用做任何调整
缺点:

增加了中间层,对查询效率有损耗
对于延迟敏感业务无法自动在主库执行
如何实现读负载均衡

软件:

LVS
Haproxy
MaxScale
硬件:

F5

最终的高可用架构

数据库优化

数据库索引优化

B-Tree索引

B-Tree索引是以B+树的结构存储数据

特点:

加快数据的查询速度
更适合进行范围查找
使用场景:

全值匹配的查询
匹配最左前缀的查询(联合索引)
匹配列前缀索引
匹配范围值的查询
精确匹配左前列并范围匹配另外一列
只访问索引的查询
使用限制:

如果不是按照索引最左列开始查询,则无法使用索引
使用索引时不能跳过索引钟的列
Not in和<>操作无法使用索引
如果查询中某个列的范围查询,则其右边所有列都无法使用索引

Hash索引

特点:

基于Hash表实现,只有查询条件精确匹配到Hash索引中的所有列时才能使用hash索引
对于Hash索引中的所有列,存储引擎都会为每一行计算一个Hash码,Hash索引中存储的就是Hash码
两次查找,先找到Hash码,再找对应的行(因为内存,影响不明显)
Hash索引无法用于排序
Hash索引不支持部分索引查找也不支持范围查找
Hash索引中Hash码的计算可能存在Hash冲突
为什么使用索引

索引打打减少了存储引擎需要扫描的数据量
索引可以帮助我们进行排序以避免使用临时表
索引可以把随机IO变为顺序IO(增加磁盘性能)
索引的影响

增加写操作成本(插入缓存,多次缓存一次写入)
太多索引增加查询优化器的选择时间
索引优化策略

1.索引列上不能使用表达式或函数

糟糕的索引使用

select …
from product
where to_days(out_date) - to_days(current_date) <= 30

修改后的索引使用

select …
from product
where out_date <= date_add(current_date, interval 30 day)

注:out_date是索引列

2.前缀索引和索引列的选择性

n设置索引大小

注:不同存储引擎对索引大小有限制

create index index_name on table(col_name(n));
索引的选择性是不重复索引值和表的记录数的比值(前缀索引长度选择尽可能让选择的值不同)

3.联合索引

如何选择索引列的顺序

经常被使用到的列优先
选择性高的列优先(过滤出更多数据)
宽度小的列优先
4.覆盖索引

select的数据列只用从索引中就能够取得

优点:

优化缓存,减少磁盘IO操作(缓存保存更多数据)
减少随机IO,变随机IO转变为顺序IO
可以避免对Innodb主键索引的二次查询
可以避免MyISAM表进行系统调用
不适合建立覆盖索引的情况:

存储引擎不支持覆盖索引
查询中使用了太多的列
使用了双%的like查询
explain select… \G

根据结果中Extra的值using index/using where

判断是否是从索引查找

select * 无法使用覆盖索引覆盖

B-Tree索引使用索引扫描来优化排序

条件:

索引的列顺序和Order by子句顺序完全一致
索引中所有列的方向(升序降序)和Order by 子句完全一致
Order by 中的字段全部在关联表的第一张表
B-Tree索引模拟Hash索引优化查询(Hash索引不能人为建立)

alter table film add title_md5 varchar(32);
update film set title=md5(title);
create index idx_md5 on film(title_md5);

explain select * from film where title_md5=md5(‘EGG IGBY’) and title=‘EGG IGBY’\G

同时过滤,避免哈希冲突

只能处理全值匹配查找
所使用Hash函数决定索引键的大小
利用索引优化锁

减少锁定的行数
加快处理速度,加快锁的释放

多个事务再没有name索引的情况执行以下排他锁语句

select * from where name=‘张三’ for update;
select * from where name=‘李四’ for update;

会产生等待

如果加上索引就不会有等待的问题。

索引的优化和维护

删除重复和冗余索引
primary key(id)
unique key(id)
index(id)
建立联合索引要删除相关的单个索引
pt-duplicate-key-checker h=127.0.0.1

查找未被使用的索引

索引的名字以及使用次数

select object_schema, object_name, index_name, b.TABLE_ROWS
from performance_schema.table_io_waits_summary_by_index_usage a
join information_schema.tables b
on a.OBJECT_SCHEMA=b.TABLE_SCHEMA and a.OBJECT_NAME=b.TABLE_NAME
where index_name is not null
and count_star = 0
order by object_schema, object_name;

更新索引统计信息以及减少索引碎片

更新索引统计信息

小心会锁表

innodb 效率更高

analyze table <table_name>

维护表和索引碎片

使用不当会锁表

optimize table <table_name>

SQL查询优化

如何获取有性能问题的SQL

用户反馈
通过慢查日志
实时获取
慢查询

慢查询日志,性能低,主要开销来自磁盘IO和日志存储所需磁盘空间,短时间占用内存多,默认功能未开启

启动慢查询日志功能

slow_query_log=on

通过脚本定时开关参数

指定慢查询日志存储路径文件

slow_query_log_file

指定记录慢查询日志(SQL执行时间)的阈值

通常0.001s比较合适

long_query_time

是否记录未使用索引的SQL

log_queries_not_using_indexes

set global slow_query_log=on;
慢查询日志内容

User@Host: sbtest[sbtest] @ localhost [] Id: 17

Query_time: 0.000233

Lock_time: 0.000120

Rows_sent: 1

Rows_examined: 1

SET timestamp=1564738274;

SELECT…

慢查询日志分析工具

mysqldumpslow
汇总除查询条件外其他完全相同的sql,并将分析结果按照参数中所指定的顺序输出。

-s order(c,t,l,r,at,al,ar)

c : 总次数

t : 总时间

l : 锁时间

r : 总数据行数

a* : 平均数 at = 总时间 / 总次数

t top 取前top条

mysqldumpslow -s r -t 10 slow-mysql.log
pt-query-digest
pt-query-digest --explain h=127.0.0.1,u=root,p=123456 slow-mysql.log
实时获取

通过information_schema数据库下的processlist表 time字段是执行秒数

查询速度慢的原因

MySQL服务器处理查询流程

客户端发送SQL请求到服务器
服务器检查是否可以在查询缓存中命中该SQL
服务端进行SQL解析,预处理,再由优化器生成对应执行计划
根据执行计划,调用存储引擎API来查询数据
将结果返回给客户端
查询缓存对sql性能影响

优先检查这个查询是否命中查询缓存中的数据,通过一个对大小写敏感的哈希查找(全职匹配)实现,必须同一个sql,字段必须相同才能在缓存查找。

注意:对缓存加锁,降低查询效率,对读写频繁 的系统不建议使用查询缓存

设置查询缓存是否可用

query_cache_type=ON|OFF|DEMAND

DEMAND表示只有在查询语句中使用SQL_CACHE和SQL_NO_CACHE来控制是否需要缓存

设置查询缓存内存大小

query_cache_size

设置查询缓存可用存储最大值

query_cache_limit

在查询上加上SQL_NO_CACHE提高效率

设置数据表被锁是否返回缓存数据

query_cache_wlock_invalidate

设置查询缓存分配内存块最小单位

query_cache_min_res_unit
MySQL依照执行计划和存储引擎交互阶段

服务端进行SQL解析,预处理,再由优化器生成对应执行计划

语法解析阶段通过关键字对MySQL语句进行解析,并生成一颗对应的解析树,MySQL解析器将使用MySQL语法规则验证和解析查询
检查语法是否使用了正确的关键字
关键字顺序是否正确
预处理阶段是根据MySQL规则进一步检查解析树是否合法
检查查询中表和数据列是否存在以及名字或别名是否存在歧义
语法检查全通过,查询优化器生成查询计划
造成MySQL生成错误执行计划的原因

统计信息不正确
执行计划中成本估算≠实际执行成本
MySQL服务器不知道那些页面在内存,那些在磁盘
那些顺序读取,那些随机读取
MySQL优化器所认为的最优可能与你认为的最优不一样
MySQL不考虑其他并发查询,可能影响查询速度
有时候基于一些固定规则来生成执行计划
不考虑不受其控制的成本
优化器可优化的SQL类型

重新定义表关联顺序
外连接转换为内链接
使用等价变换规则
优化count()、min()和max()(根据B-Tree索引优化)
select tables optimized away 优化器已经从执行计划移除了该表,并以一个常数取而代之
将一个表达式转化为常数表达式
子查询优化
提前终止查询(limit子句、不成立的结果)

例子

explain select …where id=-1;

id是无符号整形,这个查询不会读取数据,直接中止查询。

对in()条件进行优化
如何查询处理各个阶段所消耗的时间

使用profile

启动profile, session级别的配置

set profile=1;

查看每个查询总的时间信息

show profile;

查询每个阶段所消耗时间

show profile for query N;

Sending data一般可以通过索引优化

除了时间信息还有cpu信息

show profile cpu for query 1;

profile官方建议不再使用了,建议使用以下工具

使用performance_schema

启动所需要的监控

update setup_instruments set enabled=‘YES’ TIMED=‘YES’ where name like ‘stage%’;
update setup_consumers set enabled=‘YES’ where name like ‘events%’;

查询语句

select a.thread_id ,sql_text,c.event_name,(c.timer_end -c.timer_start) / 1000000000 as ‘duration (ms)’
from events_statements_history_long a join threads b on a.thread_id =b.thread_id
join events_stages_history_long c on c.thread_id=b.thread_id
and c.event_id between a.event_id and a.end_event_id

where b.processlist_id=connection_id() and a.event_name=‘statement/sql/select’

order by a.thread_id,c.event_id;
执行结果:

特定SQL的查询优化

大表优化

大表数据的修改最好分批处理

DELIMITER USEimmoc USE `immoc`
DROP PROCEDURE IF EXISTS p_delete_rowsKaTeX parse error: Expected 'EOF', got '#' at position 150: … DO #̲ 修改这一行就行 …
DELIMITER;
如何修改大表表结构

对表中的列的字段类型修改
改变字段宽度会锁表
无法解决主从延迟问题
解决方法:

从服务器修改后替换主服务器
建立新表

实现上述过程的工具:

pt-online-schema-change

pt-online-schema-change \

修改表结构

–alter=“MODIFY c varchar(150) not null default ‘’”
–user=root --password=123456
D=,t=
–charset=utf8 –-execute
如何优化not in和<>查询

原SQL

select id
from table01
where id not in (select id from table02);

优化SQL

select a.id
from table01 a
left join table02 b on a.id=b.id
where b.id is null

使用汇总表优化,提前汇总并记录到表

select count(*)
from product_comment
where pro_id = 123;

优化

create table product_comment_cnt(pro_id int, cnt int);

查询当前汇总评论数

select count(cnt) from(
select cnt
from product_comment_cnt
where pro_id = 123
UNION ALL
select count(*)
from product_comment
where pro_id = 123
and timestr>DATE(NOW())
) a;
分库分表

几种方式

一个实例中的多个数据库拆分到不同实例

把一个库中的表分离到不同的数据库

数据库分片

对一个库中相关表进行水平拆分到不同实例的数据库中

如何选择分区键

分区键尽量避免跨分片查询的发生
分区键尽量使各个分片中数据平均
如何存储无需分片的表

每个分片存储一份相同数据
保持数据一致 定期检查
额外节点统一存储
级联查询需要程序进行处理
如何在节点部署分片

每个分片使用单一数据库,并且数据库名相同
多个分片表存储在同一数据库,表名后加分片号后缀
一个节点部署多个数据库,每个数据库包含一个分片
如何分配分片中数据

按分区键Hash值取模分配
按分区键范围
利用分区键和分片映射表
如何生成全局唯一ID

使用自增id和自增id偏移量
使用全局节点生成id
在用Redis等缓存服务器中创建全局ID
数据库分片软件:oneProxyp(使用方式见脚本)

可以进行数据库分片,读写分离和负载均衡等功能。

数据库监控

具体的关于监控请参考前面的文章
对数据库可用性监控
对服务器性能监控
对主从复制的监控
对服务器资源监控(磁盘空间)
可用性监控

确认数据库是否可以通过网络连接

mysqladmin -umonitor_user -p -h ping
telnet ip port
确认可读写

检查read_only参数是否为off
建立监控表对表中数据更行
执行简单查询select @@version
监控数据库连接数

show variables like ‘max_connections’;

查看连接数

show global status like ‘Threads_connected’

监控工具报警

Threads_connected /max_connections > 0.8

数据库性能监控

记录性能监控过程中所采集到的数据库状态
如何计算QPS和TPS
QPS=(Queries2 - Queries1)/(Uptime_since_flush_status2-Uptime_since_flush_status1)

TPS=((Com_insert2 + Com_update2 + Com_delete2) - (Com_insert1 + Com_update1 + Com_delete1))/(Uptime_since_flush_status2-Uptime_since_flush_status1)
监控数据库并发请求数量

show global status like ‘Threads_running’

并发请求数量远小于同一时间连接到数据库的线程数量

如何监控Innodb阻塞

select b.trx_mysql_thread_id as ‘被阻塞线程’
,b.trx_query as ‘被阻塞SQL’
,c.trx_mysql_thread_id as ‘阻塞线程’
,c.trx_query as ‘阻塞SQL’
,(UNIX_TIMESTAMP()-UNIX_TIMESTAMP(c.trx_started)) as ‘阻塞时间’
from information_schema.innodb_lock_waits a
join information_schema.innodb_trx b
on b.trx_id=a.requesting_trx_id
join information_schema.innodb_trx c
on c.trx_id=a.blocking_trx_id
where (UNIX_TIMESTAMP()-UNIX_TIMESTAMP(c.trx_started)) > 60;

查询连接号

select connection_id();
主从复制监控

很多延迟不能发现

show slave status;

主上二进制日志文件名和偏移量

show master status \G

在从上执行

show slave status;
使用多线程的程序对比主上二进制文件偏移量和从上已经传输完成的主上二进制文件偏移量是否存在大量延迟

检查主从复制数据一致

pt-table-checksum

主库下运行

pt-table-checksum u=dba,p=‘123456’
–databases mysql
–replicate test.checksums

-----《高性能MySQL指南》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章