mysql 在线alter table要小心

mysql 5.6之前, alter table操作对可用性有巨大的冲击(除了纯改表名、不影响任何数据的alter table)。它的原理是, 0. alter table语句开始 1. 等待当前所有操作结束 2. 施加shared table lock,  能读不能写 3. 创建临时表,执行table alteration并将所有数据复制到临时表中 4. 抛弃旧表并把新表改名,完成操作; 在这个点上会对表施加exclusive table lock, 也就是说连读都不行了。 如果表很大,这个过程会导致比较严重的不可用(分钟级或以上).  在5.6之前,有一个针对innodb index的优化:MySQL 5.5, and MySQL 5.1 with the InnoDB Plugin, optimized CREATE INDEX and DROP INDEX to avoid the table-copying behavior 到5.6时,innodb上了一个特性叫做"online ddl", 对于很多alter table操作,可以避免表复制、或/和  dml blocking等。 具体避免哪些,要看具体使用的是哪种alter table操作。请参见: http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html …

mysql 在线alter table要小心 Read More »

mysql: row-level locking 的overhead 更大,兼论myisam的适用场景

row-level locking 的overhead 比table-level locking的overhead更大:  更慢,需要消耗更多内存。 至于为什么?我没读过源码,在网上也没搜到具体的原因。只看到一句勉强可以接受的解释:Row locking is more complex than table locking, and so it’s slower and takes more memory. 不管为什么,这个结论让人有点吃惊,对不对? 另外要注意的是,myisam中shared table lock并不会阻止对表的插入操作,一边读一边插入,MyISAM还是挺快的。 结合以上两点:1.table lock更轻; 2. table lock不阻止插入,如果你的业务不需要事务,又以insert和select为主的话,那么MyISAM是比InnoDB更好的选择。

mysql逻辑架构图

摘自”High Performance MySQL” storage engine只管storage, 不管query parsing之类的; 不过,它会应optimizer的请求告知自己的能力、执行一些操作的代价以及统计信息。

一个慢sql可能会成为害群之马

一条sql执行慢,不仅相关业务受影响,其他业务也可能影响。 数据库连接是有限的,一条慢sql执行慢,就意味着它会在较长时间内占用数据库连接; 如果并发执行慢sql, 很容易占用大量的数据库连接,其他的快sql获取不到连接,执行不了,快sql对应的sql也就受影响了,最终导致整个系统的可用性都出问题。 除了数据库连接,慢SQL(或者大规模数据处理如批量数据清理)还会占用数据库的其他资源。 比如过久占用锁、占用过多CPU/内存等,这些都有可能导致其他sql不能立即执行。 解决方案有: 1. 甄别、改进慢sql. 对于高并发的系统,sql rt应该维持在5ms以内 2. 数据库连接池互相隔离,比如让主干业务独享数据库连接池,其他业务若出现慢sql也不影响主业务。 3. 设置sql执行超时,一段时间内没有执行完强制释放数据库连接。

redo log, undo log中的”do” 都是idempotent的

redo log, undo log中的"do" 都是idempotent的. 所谓的redo, 就是把数据改成log entry所记录的新值;不管故障发生时数据是不是已经为新值,在恢复时把数据设成新值总是无害的,因为“设为新值”这个操作是idempotent的。 undo也一样,即把数据改成旧值。 脑子里要建立这个意识,redo/undo其实都是赋值操作,而不能是“增1”、“减1”这种non-idempotent操作。

数据日志中的checkpoint

根据redo log或undo log进行数据恢复时,是不是要扫描整个数据文件? 那未免太重了。 如果我们可以确信在log的某一点之前,数据都是完整的,那么我们就只需要处理这一点之后的log. 这个点就叫做"checkpoint".  在log中定期地生成checkpoint, 进行数据恢复时再找到最后一个checkpoint, 即可像上面所说的那样节省工作量。 以undo logging为例。生成checkpoint的简单办法是: 引用 1. 禁止启动新的transaction 2. 待所有transaction已经commit或abort 3. 将log flush至disk 4. 在log中生成一个<checkpoint>标识并flush至disk 5. 允许新的transaction 当然这种办法过于粗暴,由于禁止新transaction, 它会导致DB一段时间不可用; 有其他的机制如nonquiscent checkpointing, 可以不影响可用性。 具体就不说了。

redo log + undo log一起上

undo logging和 redo logging各有优缺点,一个需要频繁flush to disk, 一个需要较大的buffer. 如何同时避免这两种缺点?让buffer manager按最佳性能策略决定何时flush, 而不必考虑log的问题。 办法就是redo log + undo log一起上. 对于每个数据改动,记录 <Transaction T, 数据X, 旧值,新值>. 唯一的约束是,在将数据改动flush至disk之前,保证相应的log entry已经写至disk. 数据恢复时,把commited transaction全部redo一遍,再把incomplete transaction全部undo一遍。

通过archiving恢复数据的一般策略

一般来说,会做一个full dump, 然后周期性地进行incremental dump. incremental dump只记录那些改变过的数据。 数据恢复时,将full dump和若干incremental dump依次写回到数据库中。 问题是,在dump过程中数据仍会被改动,这些改动可能不会被记到dump中。要解决这个问题,可以在dump过程中记录undo log或redo log,恢复数据时,搞完dump后,再根据log做数据恢复。 这个log不能跟源数据放在同一个disk里。既然要用archiving机制做数据恢复,就意味着DB已经出现media failure, 如果log跟DB数据放在一起,那log很可能也已经丢了。

根据redo log恢复数据

redo logging机制的基本原理是: 进行数据恢复时,对Incompleted Transaction不做处理;而对Committed Transaction,把记录了的数据改动再重现做一遍。 记录log 引用 Start Transaction T … 记录:X被修改后的值是A 记录:Y被修改后的值是B 记录:X被修改后的值是C … Commit Transaction T 根据log恢复 1. 从上往下扫log文件 2. 遇到Commit Transaction时,依次…, 将X的值改回为A, Y的值的改会为B,  X的值改为C… 可靠性如何保证? Redo logging要求一个transaction的所有log entry都已经写入disk了,才能把数据改动写入disk. 进行数据恢复时,根据这个规则, 对于Incomplete Transaction我们可以断定数据改动还没写入disk, 所以可以直接忽略; 而对于Commited Transaction, 数据改动可能已经写入disk,也可能未写入, 这时只须根据log把数据改动做一遍,可能白做,但绝对无害。 Redo Logging的缺点 在把一个transaction的所有log entry flush to disk之前,还不能flush数据改动; 也就是说,要有足够大的buffer, 容纳这些数据改动,直到transaction结束. 所以,redo logging可能比较占用内存。

根据undo log恢复数据

undo logging机制的基本原理是: 进行数据恢复时,对于Committed Transaction不做处理,对于Incomplete Transaction,则将相关数据写回成Transaction开始前的旧值。 记录log 引用 Start Transaction T … 记录:X被修改前的值是A 记录:Y被修改前的值是B 记录:X被修改前的值是C … Commit Transaction T 根据log恢复 1. 从下往上扫log文件 2. 遇到有Start无Commit的Transaction时,依次将…, X的值改回为C, Y的值改回为B, X的值的改回为A. 可靠性如何保证? 1. Undo logging要求所有数据改动都已经写入disk了,才能将Commit Transaction这种log entry写入disk,这就保证commited transaction相关的数据改动已经真的持久化了。 2. Undo Logging还要求先在log文件中记录数据的旧值,再将数据改动持久化。当发生断电时,数据改动可能已经持久化,也可能还没有; 进行数据恢复时不必管有没有,一律把数据恢复成旧值即可,有可能是多余的,也有可能不是,总之对数据一致性是无害的。 Undo Logging的缺点 必须先将数据改动写入disk, 才能标识一个Transaction的结束; 也就是说,要完成一个Transaction, 必须将数据改动写入disk, 不能再在buffer里放着。缺点就是,数据改动可能没有累积到一定的量,就要从buffer中flush中去,所以I/O读写可能会比较频繁。