数据库
首页 > 数据库> > MySQL DBA 防坑指南

MySQL DBA 防坑指南

作者:互联网

1. MySQL连接数问题




图片图片

2. MySQL文件句柄设置

图片图片


3. 注意SQL隐式转换的坑

在开发规范中,我们往往会要求研发避免在where条件中出现隐式类型转换,什么是隐式转换:即在where语句中条件的值和条件对应的列的数据类型不一致。如 where id=‘123’,而id的类型为bigint,或者where code=100,而code的类型为varchar,隐式转换会产生以下两个问题:1. 隐式类型转换可能导致索引失效。2. 隐式类型转换可能产生非预期的结果。

4. SQL为什么一会可以走到索引,一会走不到索引


有些时候开发同学会找到DBA,反馈有一条SQL有索引,之前也能走到索引,查询性能非常的高,突然收到慢查询报警,查了十多秒,这种情况产生的原因一般和数据内容有关。
MySQL如果通过索引选择扫描行数过多(大约20%以上,这个不是确定的),优化器会认为使用全表扫描更佳,从而会走全表扫描,当然很多时候其实还是走索引性能会更好一点,MySQL选择优化器并不是那么智能。
举个例子,微博的用户有一张评论表,查询我们这些小众用户的评论会走索引,查询非常的快,如果正好查询的是一个大V账号,有可能涉及数百万条数据导致没有走到索引。

图片图片

5. 自增键重启后回溯问题

图片图片
InnoDB 引擎的自增值,其实是保存在了内存里,并且到了 MySQL 8.0 版本后,才有了“自增值持久化”的能力,也就是才实现了“如果发生重启,表的自增值可以恢复为 MySQL 重启前的值”。 在 MySQL 5.7 及之前的版本,自增值保存在内存里,并没有持久化。每次重启后,第一次打开表的时候,都会去找自增值的最大值 max(id),然后将 max(id)+1 作为这个表当前的自增值。 举例来说,如果一个表当前数据行里最大的 id 是 10,AUTO_INCREMENT=11。这时候,我们删除 id=10 的行,AUTO_INCREMENT 还是 11。但如果马上重启实例,重启后这个表的 AUTO_INCREMENT 就会变成 10。也就是说,MySQL 重启可能会修改一个表的 AUTO_INCREMENT 的值。

图片图片

6. 自增键用完怎么办

图片图片
如果你用过或了解过MySQL,那你一定知道自增主键了。每个自增id都是定义了初始值,然后按照指定步长增长(默认步长是1)。 虽然,自然数是没有上限的,但是我们在设计表结构的时候,通常都会指定字段长度,那么,这时候id就有上限了。
在插入数据时有可能唯一主键冲、sql事务回滚、批量插入的时候,批量申请自增值等原因导致自增id是不连续的。 我们一般会将自增键的类型设置为int,数据范围为负21亿到正21亿,对于一个频繁插入删除数据的表来说,21亿是可能会被用完的,可能引发业务无法正常写入。 因此在建表的时候你需要考察你的表是否有可能达到这个上限,如果有可能,就应该创建成 8 个字节的 bigint unsigned。
另外可以将表的自增键做好监控,比如到达使用率的80%,就可以报警出来。

7. 大表删除hang的问题


MySQL里面直接对大表执行drop table删除有可能导致MySQL Hang住,对业务造成影响。删除超大表的前提是该表是独立表空间,然后按照如下步骤删除才能避免引起业务故障。

 一、表创建一个硬链接

# du -sh pay_bills.ibd
175G pay_bills.ibd
# 创建硬链接
# ln pay_bills.ibd pay_bills.ibd_hdlk
 二、执行表删除在Linux中,每个存储文件都会有指向该文件的Inode Index,多个文件名可以通过相同Inode Index指向相同一个存储文件。 如果该文件名引用的Inode Index上还被其他文件名引用,则只会删除该文件名和Inode Index之间的引用如果该文件名引用的Inode Index上没有被其他文件名引用,则删除该文件名和Inode Index之间的引用并删除Inode Index指向的存储文件。 实际上只是删除了对 pay_bills.ibd 的一个文件引用,我们 pay_bills.ibd_hdlk 对物理文件的引用还是存在的,就不会执行OS级别的删除操作,IO波动不大,降低对MySQL的影响。
mysql> drop table pay_bills
;
Query OK, 0 rows affected (3.24 sec)


三、执行文件删除

 安装 truncate 工具

# yum install coreutils -y
 执行删除脚本
#!/bin/bash
TRUNCATE=/usr/bin/truncate
for i in `seq 175 -2 1`; do
$TRUNCATE -s ${i}G pay_bills.ibd_hdlk
sleep 1
done
最后删除硬连接 
rm -f pay_bills.ibd_hdlk


图片图片

8. Adaptive Hash Index引发的问题

图片图片
哈希(hash)是一种非常快的查找方法,在一般情况下这种查找的时间复杂度为O(1),即一般仅需要一次查找就能定位数据。而B+树的查找次数,取决于B+树的高度,在生产环境中,B+树的高度一般为3~4层,故需要3~4次的查询。
InnodB存储引擎会监控对表上各索引页的查询。如果观察到建立哈希索引可以带来速度提升,则建立哈希索引,称之为自适应哈希索引(Adaptive Hash Index,AHI) AHI是通过缓冲池的B+树页构造而来,因此建立的速度很快,而且不需要对整张表构建哈希索引。InnoDB存储引擎会自动根据访问的频率和模式来自动地为某些热点页建立哈希索引。
但是在DROP TABLE过程中,发现存在大量的线程处于OPENING TABLES的状态,DROP 时间非常的长。原因是当DROP TABLE时,InnoDB引擎还会删除表对应0的AHI(自适应哈希索引)。而这个过程需要持有一把数据字典的互斥锁、读写锁。
对于这个问题,可以在DROP TABLE的时候关闭AHI功能,甚至可以永久关闭AHI功能。

9. MHA切换VIP的问题


MHA是业界经典而且很多公司在用的HA切换工具,但是默认开源的MHA基于VIP漂移来进行切换,通过VIP漂移可能存在因为网卡问题漂移失败的问题,从而导致切换失败。

目前很多运维能力比较强的公司通过自建DNS,然后将MHA的VIP漂移的代码二次开发改造为切换DNS,业务连接DNS 域名来解决这个问题。

图片图片

10. pt-archiver迁移为什么少了一条数据

图片图片
pt-archiver属于大名鼎鼎的percona工具集的一员,是归档和清理MySQL大表数据的最佳轻量级工具之一。但是使用过程中发现迁移的数据少了一条(最后一条数据),原因是和工具的safe-auto-increment参数有关。
--[no]safe-auto-increment默认值:yes,指定不使用自增列(AUTO_INCREMENT)最大值对应的行进行归档。该选项在进行归档清除时会额外添加一条WHERE子句以防止工具删除单列升序字段具有的具有AUTO_INCREMENT属性最大值的数据行,为了在数据库重启之后还能使用到AUTO_INCREMENT对应的值,但这会引起无法归档或清除字段对应最大值的行。
图片图片

11. pt-osc和ghost变更丢数据的问题

图片图片

我们在使用pt-osc和gh-ost的过程中,发现了变更完丢数据的情况,知道了这个坑,就减少了删库跑路的风险。pt-osc和gh-ost执行方式关于数据处理的区别,我们做了一个测试

测试表如下:

CREATE TABLE`ddltest` (
`id` int(11)NOT NULL AUTO_INCREMENT,
`name`varchar(10) DEFAULT NULL,
PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8


mysql>select * from ddltest;
+—-+——+
| id | name|
+—-+——+
|  1| a    |
|  2| b    |
+—-+——+
pt-osc和gh-ost执行方式关于数据处理的区别,大概总结一下:
 最终最终总结: 针对此问题可以改进的地方:
  1. 完善SQL军规,新增字段时如果设置not null属性则必须带上default值。如果新增字段设置not null,禁止加唯一索引。
  2. 完善SQL审核流程,如果系统发现开发同学提交了新增唯一索引的SQL,则不允许开发自动执行,流转到DBA处理。
  3. 提高自我审核从严意识,同时在自动执行平台DBA审核界面,针对添加唯一索引,做强提醒功能。
  4. 针对加唯一索引的SQL,最好单独提交处理,走online ddl模式执行,尽量不用pt-osc和gh-ost。
如果使用新版OSC:Percona toolkil 3.0.13 ,参数–check-unique-key-change –check-alter 可以事先检查是否增加uniquekey,并报错。

图片图片

12. 数据库拆分引发的删库事件

图片图片
讲一个真实案例,曾经,有一名前同事在做一次数据库拆分,拆分是通过搭建同步备库和切换进行的(备库只同步了需要拆分的数据库),操作完成后,原来服务器实例已经拆走的数据库需要删除,删除后发现新的数据库也没有了,一次删除事件由此产生。
产生的原因是由于新库拆分完成后,忘记断开和老库和同步,以致于在老库删除后新库也跟着没有了。
这个完全是操作和流程问题,也是希望大家能够引起重要,运维操作建议写好操作步骤,并且关键步骤(类似删库和删表)最好有double check,可以避免类似故障发生。


图片图片

13.HA没有切换/监控没有正常报警

图片图片
大家有没有遇到过这种情况,数据库故障了,却没有按预期的进行故障切换,监控报警也经常失效,我想说的是我们使用了大量的工具来让我们的运维更加稳定,但是本身工具是不是也是单点?是不是也要做好监控呢?
比如HA平台、备份平台、监控平台,这些平台的自身服务或者Agent进行我们也要做好对应的监控,预防上述问题发生。


14. df看空间越来越少,du却没有发现大文件


有时候在Linux主机用df -hT 查看磁盘占用已经满了,但是用du -sh * 又找不到是哪些文件目录占满了磁盘。
原因是当我们使用rm在linux上删除了大文件,但是如果有进程打开了这个大文件,却没有关闭这个文件的句柄,那么linux内核还是不会释放这个文件的磁盘空间

解决方法:lsof -n | grep deleted  查看到占用的进程
然后用kill -9 进程号杀死进程就可以释放对应占用的空间了
批量处理命令:
lsof |awk '/deleted/{print $2}'|xargs kill -9

另外也看下有没有vim进程,如果使用vim打开了一个大文件,也会引起该问题。
图片图片

15. 死锁要紧么,需要注意什么

图片图片
如果是偶尔低频的死锁,没什么太大影响,如果是出现频率比较高,对业务影响比较大。分析死锁的原因最好能够复现死锁。
分析死锁可以使用show engine innodb status 命令得到锁的信息结合业务场景和业务代码进行分析。

图片图片

16. text等大对象类型有什么风险

图片图片
  1. text/blob大字段会引发页的分裂,影响性能,具体可以参考 浅析InnoDB Record Header及page overflow 
  2. text字段会引起表占用更多的物理磁盘空间,不合理的text浪费大量磁盘空间

图片图片

17. CPU %user 为什么特别的高

图片图片
一般MySQL服务器的CPU %user如果比较高,一般95%以上都是索引使用不当引起的,我们需要重点关注慢SQL,其中重点关注执行状态为send data/ creating sort index/ copying to tmp table / creating tmp table 的SQL,并跟踪优化。

18. 查询被hang住了,什么原因

如果查询hang住了,一般可以从以下几个方面进行排查:
可能的原因有:

19. mysql crash了,怎么办

mysql crash,可以从以下几个方面去排查分析:

那么如果mysql crash了该怎么办呢?

标签:文件,防坑,pt,DBA,索引,MySQL,删除,osc
来源: https://www.cnblogs.com/chengyunblogs/p/16225745.html