MySQL快速的复制一张表
快速的复制一张表mysqldump你可以使用下面的命令:
mysqldump -h$host -P$port -u$user --add-locks --no-create-info --single-transaction --set-gtid-purged=OFF db1 t --where="a>900" --result-file=/client_tmp/t.sql
这条命令中,主要参数含义如下:
–single-transaction的作用是,在导出数据的时候不需要对表db1.t加表锁,而是使用START TRANSACTION WITH CONSISTENT SNAPSHOT的方法;
–add-locks设置为0,表示在输出的文件结果里,不增加” LOCK TABLES t WRITE;” ;
–no-create-info的意思是,不需要导出表结构;
–set-gtid-purged=off表示的是,不输出跟GTID相关的信息;
–result-file指定了输出文件的路径,其中client表示生成的文件是在客户端机器上的。
再使用这个命令 ...
MySQL自增主键
自增主键自增值存在哪?不同的引擎对于自增值的保存策略不同:
MyISAM引擎的自增值保存在数据文件中。
InnoDB引擎的自增值,其实是保存在了内存里(重启重新去找自增值的最大值max(id)),到了MySQL 8.0版本后,才有了“自增值持久化”的能力(将自增值的变更记录在了redo log中,重启的时候依靠redo log恢复重启之前的值)。
自增值修改机制在MySQL里面,如果字段id被定义为AUTO_INCREMENT,在插入一行数据的时候,自增值的行为如下:
如果插入数据时id字段指定为0、null 或未指定值,那么就把这个表当前的 AUTO_INCREMENT值填到自增字段;
如果插入数据时id字段指定了具体的值,就直接使用语句里指定的值。
根据要插入的值和当前自增值的大小关系,自增值的变更结果也会有所不同。假设,某次要插入的值是X,当前的自增值是Y。
如果X<Y,那么这个表的自增值不变。
如果X≥Y,就需要把当前自增值修改为新的自增值。
其中,auto_increment_offset 和 auto_increment_increment是两个系统参数 ...
MySQL内部临时表的运用
内部临时表的运用Union例如:(select 1000 as f) union (select id from t1 order by id desc limit 2);
这个语句的执行流程是这样的:
创建一个内存临时表,这个临时表只有一个整型字段f,并且f是主键字段。
执行第一个子查询,得到1000这个值,并存入临时表中。
执行第二个子查询:
拿到第一行id=1000,试图插入临时表中。但由于1000这个值已经存在于临时表了,违反了唯一性约束,所以插入失败,然后继续执行;
取到第二行id=999,插入临时表成功。
从临时表中按行取出数据,返回结果,并删除临时表,结果中包含两行数据分别是1000和999。
如果把上面这个语句中的union改成union all的话,就没有了“去重”的语义。这样执行的时候,就依次执行子查询,得到的结果直接作为结果集的一部分,发给客户端。因此也就不需要临时表了。
group by例如:select id%10 as m, count(*) as c from t1 group by m;
这个语句的执行流程是这样的:
创建内存临时表,表里有 ...
MySQL优化JOIN语句
Join优化被驱动表使用了索引的情况例如这个简单的join语句select * from t1 straight_join t2 on (t1.a=t2.a);
在这条语句里,被驱动表t2的字段a上有索引,join过程用上了这个索引,因此这个语句的执行流程是这样的:
从表t1中读入一行数据 R;
从数据行R中,取出a字段到表t2里去查找;
取出表t2中满足条件的行,跟R组成一行,作为结果集的一部分;
重复执行步骤1到3,直到表t1的末尾循环结束。
在这个join语句执行过程中,驱动表是走全表扫描,而被驱动表是走树搜索。
假设被驱动表的行数是M,驱动表的行数是N。每次在被驱动表查一行数据,要先搜索索引a,再搜索主键索引。每次搜索一棵树近似复杂度是以2为底的M的对数,记为log2M,所以整个流程近似复杂度是 N + N2log2M。
这个算法称为**Index Nested-Loop Join(NLJ)**。
显然,N对扫描行数的影响更大,因此应该让小表来做驱动表。
Multi-Range Read优化(需要设置set optimizer_switch="mrr_cost ...
MySQL误删数据怎么办
误删数据怎么办误删行如果是使用delete语句误删了数据行,可以用Flashback工具通过闪回把数据恢复回来。
Flashback恢复数据的原理,是修改binlog的内容,拿回原库重放。而能够使用这个方案的前提是,需要确保binlog_format=row 和 binlog_row_image=FULL。
需要说明的是,我不建议你直接在主库上执行这些操作。
恢复数据比较安全的做法,是恢复出一个备份,或者找一个从库作为临时库,在这个临时库上执行这些操作,然后再将确认过的临时库的数据,恢复回主库。这是因为,一个在执行线上逻辑的主库,数据状态的变更往往是有关联的。可能由于发现数据问题的时间晚了一点儿,就导致已经在之前误操作的基础上,业务代码逻辑又继续修改了其他数据。所以,如果这时候单独恢复这几行数据,而又未经确认的话,就可能会出现对数据的二次破坏。
事前预防
把sql_safe_updates参数设置为on。这样一来,如果我们忘记在delete或者update语句中写where条件,或者where条件里面没有包含索引字段的话,这条语句的执行就会报错。
代码上线前,必须经过SQL审计。
...
MySQL备库并行复制策略
备库并行复制策略按表分发按表分发事务的基本思路是,如果两个事务更新不同的表,它们就可以并行。因为数据是存储在表里的,所以按表分发,可以保证两个worker不会更新同一行。
每个事务在分发的时候,跟所有worker的冲突关系包括以下三种情况:
如果跟所有worker都不冲突,coordinator线程就会把这个事务分配给最空闲的woker;
如果跟多于一个worker冲突,coordinator线程就进入等待状态,直到和这个事务存在冲突关系的worker只剩下1个;
如果只跟一个worker冲突,coordinator线程就会把这个事务分配给这个存在冲突关系的worker。
按行分发要解决热点表的并行复制问题,就需要一个按行并行复制的方案。按行复制的核心思路是:如果两个事务没有更新相同的行,它们在备库上可以并行执行。显然,这个模式要求binlog格式必须是row。
按行复制和按表复制的数据结构差不多,也是为每个worker,分配一个hash表。只是要实现按行分发,这时候的key,就必须是“库名+表名+唯一键的值”。(如果存在唯一索引也需要加上唯一索引)
按行分发的策略有两个问题:
...
MySQL保证高可用
Mysql的高可用主备延迟所谓主备延迟,就是同一个事务,在备库执行完成的时间和主库执行完成的时间之间的差值。
你可以在备库上执行show slave status命令,它的返回结果里面会显示seconds_behind_master,用于表示当前备库延迟了多少秒。
主备延迟的来源:
有些部署条件下,备库所在机器的性能要比主库所在的机器性能差。
第二种常见的可能了,即备库的压力大:由于主库直接影响业务,大家使用起来会比较克制,反而忽视了备库的压力控制。结果就是,备库上的查询耗费了大量的CPU资源,影响了同步速度,造成主备延迟。
解决方式:
一主多从。除了备库外,可以多接几个从库,让这些从库来分担读的压力。
通过binlog输出到外部系统,比如Hadoop这类系统,让外部系统提供统计类查询的能力。
第三种,大事务。如果一个主库上的语句执行10分钟,那这个事务很可能就会导致从库延迟10分钟。
例如:
一次性地用delete语句删除太多数据
大表DDL
主备切换可靠性优先策略:
在图中的双M结构下,从状态1到状态2切换的详细过程是这样的:
判断备库B现在的seconds_ ...
MySQL保证主备一致
保证主备一致
在状态1中,虽然节点B没有被直接访问,但是我依然建议你把节点B(也就是备库)设置成只读(readonly)模式。这样做,有以下几个考虑:
有时候一些运营类的查询语句会被放到备库上去查,设置为只读可以防止误操作;
防止切换逻辑有bug,比如切换过程中出现双写,造成主备不一致;
可以用readonly状态,来判断节点的角色。
同步完整流程:
一个事务日志同步的完整过程是这样的:
在备库B上通过change master命令,设置主库A的IP、端口、用户名、密码,以及要从哪个位置开始请求binlog,这个位置包含文件名和日志偏移量。
在备库B上执行start slave命令,这时候备库会启动两个线程,就是图中的io_thread和sql_thread。其中io_thread负责与主库建立连接。
主库A校验完用户名、密码后,开始按照备库B传过来的位置,从本地读取binlog,发给B。
备库B拿到binlog后,写到本地文件,称为中转日志(relay log)。
sql_thread读取中转日志,解析出日志里的命令,并执行。
binlog的格式:
statement ...
MySQL短时提供性能的方法
短时提供性能的方法短连接风暴正常的短连接模式就是连接到数据库后,执行很少的SQL语句就断开,下次需要的时候再重连。如果使用的是短连接,在业务高峰期的时候,就可能出现连接数突然暴涨的情况。
解决方案:第一种方法:先处理掉那些占着连接但是不工作的线程:怎么判断哪些是事务外空闲的呢?
执行show processlist
图中id=4和id=5的两个会话都是Sleep 状态。而要看事务具体状态的话,你可以查information_schema库的innodb_trx表。
这个结果里,trx_mysql_thread_id=4,表示id=4的线程还处在事务中。
因此,如果是连接数过多,你可以优先断开事务外空闲太久的连接;如果这样还不够,再考虑断开事务内空闲太久的连接。
从服务端断开连接使用的是kill connection + id的命令, 一个客户端处于sleep状态时,它的连接被服务端主动断开后,这个客户端并不会马上知道。直到客户端在发起下一个请求的时候,才会收到这样的报错“ERROR 2013 (HY000): Lost connection to MySQL server du ...
MySQL幻读问题
幻读问题这里,我需要对“幻读”做一个说明:
在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。
上面session B的修改结果,被session A之后的select语句用“当前读”看到,不能称为幻读。幻读仅专指“新插入的行”。
产生幻读的原因是,行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。因此,为了解决幻读问题,InnoDB只好引入新的锁,也就是**间隙锁(Gap Lock)**。
这样,当你执行 select * from t where d=5 for update的时候,就不止是给数据库中已有的6个记录加上了行锁,还同时加了7个间隙锁。这样就确保了无法再插入新的记录。也就是说这时候,在一行行扫描的过程中,不仅将给行加上了行锁,还给行两边的空隙,也加上了间隙锁。
跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作。间隙锁之间都不存在冲突关系。但是,间隙锁的引入,可能会导致同样的语句锁住更大的范围,这其实是影响了并发度的。所以间隙锁是在可重复读隔离级别下才会生效的
间隙锁的加 ...