在 MySQL 5.6或更高版本中,当创建或删除索引时,表仍然可用于读写操作。CREATE INDEX 或 DROP INDEX 语句仅在访问该表的所有事务完成之后才结束,因此索引的初始状态反映该表的最新内容。以前,在创建或删除索引时修改表通常会导致死锁,从而取消表上的 INSERT、 UPDATE 或 DELETE 语句。
(
for n in {1..50}; do
#(time mysql -uroot -e 'select * from website_development.users where id = 41225\G'>/dev/null) 2>&1 | grep real;
(time mysql -uroot -e 'update website_development.users set bio="" where id = 41225\G'>/dev/null) 2>&1 | grep real;
done
) | cat -n &
PID=$!
sleep 0.05
echo "Index Update - START"
mysql -uroot website_development -e 'alter table users add index ddopsonfu (last_name, email, first_name, confirmation_token, current_sign_in_ip);'
echo "Index Update - FINISH"
sleep 0.05
kill $PID
time mysql -uroot website_development -e 'drop index ddopsonfu on users;'
我的服务器(InnoDB) :
Server version: 5.5.25a Source distribution
输出(注意第6个操作是如何阻塞完成索引更新所需的 ~ 400ms 的) :
1 real 0m0.009s
2 real 0m0.009s
3 real 0m0.009s
4 real 0m0.012s
5 real 0m0.009s
Index Update - START
Index Update - FINISH
6 real 0m0.388s
7 real 0m0.009s
8 real 0m0.009s
9 real 0m0.009s
10 real 0m0.009s
11 real 0m0.009s
相对于不会阻塞的读操作(交换脚本中的行注释) :
1 real 0m0.010s
2 real 0m0.009s
3 real 0m0.009s
4 real 0m0.010s
5 real 0m0.009s
Index Update - START
6 real 0m0.010s
7 real 0m0.010s
8 real 0m0.011s
9 real 0m0.010s
...
41 real 0m0.009s
42 real 0m0.010s
43 real 0m0.009s
Index Update - FINISH
44 real 0m0.012s
45 real 0m0.009s
46 real 0m0.009s
47 real 0m0.010s
48 real 0m0.009s
不停机地更新 MySQL 的 Schema
到目前为止,据我所知,只有一种方法可以更新 MySql 模式而不会出现可用性中断。通告:
主 A 上运行着您的 MySQL 数据库
让主 B 服务,并让它从主 A 复制写操作(B 是 A 的奴隶)
在主 B 上执行模式更新。它将在升级过程中落后
让 B 少爷跟上。不变性: 您的模式更改必须能够处理从降级模式复制的命令。索引更改符合条件。简单的列添加通常符合条件。移除一根柱子?可能不会。
将所有客户从 A 主机交换到 B 主机。如果你想要安全(相信我,你做的) ,你应该确保最后一次写到 A 被复制到 B 之前 B 采取它的第一次写。如果你允许对2 + master 进行并发写操作,... ... 那么你最好在深层次上理解 MySQL 复制,否则你将面临一个痛苦的世界。极度痛苦。比如,你有没有一个专栏是“自动增加”? ? ?你完蛋了(除非你在一个主人身上使用偶数,在另一个主人身上使用赔率)。不要信任 MySQL 复制来“做正确的事情”。它不聪明,也救不了你。与从命令行复制二进制事务日志并手动重放它们相比,这只是稍微不那么安全。尽管如此,断开所有客户机与旧主机的连接并将它们切换到新主机只需几秒钟的时间,这比等待数小时的模式升级要快得多。
现在 B 师父是你们的新师父。您有了新的模式。生活真美好。喝杯啤酒吧,最糟糕的已经过去了。
对主人 A 重复这个过程,升级他的模式,这样他就成为你的新的次级主人,准备好在你的主要主人(现在的主人 B)失去能量或者刚刚起死回生的情况下接管你的工作。
这不是更新模式的简单方法。在严肃的生产环境中是可行的; 是的,它是可行的。请,请,请,如果有一个更简单的方法添加一个索引到 MySQL 表不阻塞写,让我知道。
在 MySQL 5.6或更高版本中,当创建或删除索引时,表仍然可用于读写操作。CREATE INDEX 或 DROP INDEX 语句仅在访问该表的所有事务完成之后才结束,因此索引的初始状态反映该表的最新内容。以前,在创建或删除索引时修改表通常会导致死锁,从而取消表上的 INSERT、 UPDATE 或 DELETE 语句。
以及:
在 MySQL 5.6中,这个特性变得更加通用: 您可以在创建索引时对表进行读写操作,并且可以执行更多类型的 ALTER TABLE 操作,而无需复制表、无需阻塞 DML 操作,或者两者兼而有之。因此,在 MySQL 5.6或更高版本中,我们通常将这组特性称为在线 DDL,而不是快速索引创建。