在一个巨大的MySQL生产表上创建一个索引,而不需要表锁定
我需要在~5M行MySQL表上创建一个索引。这是一个生产表,如果我运行CREATEINDEX语句,我担心所有内容都会被完全阻塞 有没有一种方法可以在不阻止插入和选择的情况下创建索引 只是想知道我没有停止,创建索引和重新启动我的系统 [2017]更新:MySQL 5.6支持在线索引更新 在MySQL 5.6及更高版本中,在创建或删除索引时,表仍可用于读写操作。CREATEINDEX或DROPINDEX语句仅在访问表的所有事务完成后才完成,以便索引的初始状态反映表的最新内容。以前,在创建或删除索引时修改表通常会导致死锁,从而取消表上的INSERT、UPDATE或DELETE语句 [2015]更新MySQL 5.5中的表指示块写入 从上面的答案来看: “如果您使用的版本大于5.1索引是在数据库联机时创建的。因此,不用担心,您不会中断生产系统的使用。” 这是****错误****(至少对于MyISAM/InnoDB表是如此,99.999%的人都在使用它。群集版是不同的。) 在创建索引时,对表执行更新操作将被阻止。MySQL在这方面真的非常愚蠢(还有其他一些事情) 测试脚本:在一个巨大的MySQL生产表上创建一个索引,而不需要表锁定,mysql,indexing,production,alter-table,table-locking,Mysql,Indexing,Production,Alter Table,Table Locking,我需要在~5M行MySQL表上创建一个索引。这是一个生产表,如果我运行CREATEINDEX语句,我担心所有内容都会被完全阻塞 有没有一种方法可以在不阻止插入和选择的情况下创建索引 只是想知道我没有停止,创建索引和重新启动我的系统 [2017]更新:MySQL 5.6支持在线索引更新 在MySQL 5.6及更高版本中,在创建或删除索引时,表仍可用于读写操作。CREATEINDEX或DROPINDEX语句仅在访问表的所有事务完成后才完成,以便索引的初始状态反映表的最新内容。以前,在创建或删除索引
(
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):
输出(注意第6个操作如何在完成索引更新所需的~400ms时间内阻塞):
Vs不阻塞的读取操作(交换脚本中的行注释):
在不停机的情况下更新MySQL的模式
Thusfar,据我所知,只有一种方法可以更新MySql模式,而不会出现可用性中断。圆形母版:
- MasterA上运行着MySQL数据库
- 将主机B投入使用,并让它复制来自主机A的写操作(B是A的从机)
- 在主服务器B上执行架构更新。它将在升级过程中落后
- 让B大师跟上。不变:架构更改必须能够处理从下版本架构复制的命令。索引更改符合条件。简单的列添加通常符合条件。删除列?可能不会李>
- 以原子方式将所有客户端从主服务器A交换到主服务器B。如果您希望安全(相信我,确实如此),您应该确保在B进行第一次写入之前将对A的最后一次写入复制到B。如果允许并发写入2+个主机。。。您最好从深层次理解MySQL复制,否则您将走向痛苦的世界。极度疼痛。比如,你有一个自动递增的列吗???你是完蛋了(除非你在一个母版上使用偶数,在另一个母版上使用赔率)。不要相信MySQL复制“做正确的事情”。它不聪明,也救不了你。它只是比从命令行复制二进制事务日志并手动重放它们稍微安全一些。不过,断开所有客户机与旧主机的连接并将其切换到新主机只需几秒钟,比等待一个多小时的模式升级要快得多
- 现在大师B是你的新主人。您有了新的模式。生活是美好的。喝杯啤酒;最坏的情况已经过去了
- 对主控台A重复此过程,升级其模式,使其成为您的新辅助主控台,准备在您的主控台(主控台B现在)断电或刚刚启动并在您身上死亡时接管
- 创建与原始表具有相同结构的新表
- 更新新表上的架构
- 在原始表上添加触发器,以便更改与副本保持同步
- 从原始表中批量复制行
- 将原始表格移到一边,并替换为新表格
- 放下旧桌子
ALTER TABLE
机制已针对MySQL 5.6进行了彻底的重新设计
(对于本主题的独家概述,可以提供一个下午的阅读时间。)
要将索引添加到表,而不使用锁UPDATE
/INSERT
,可以使用以下语句格式:
ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;
如果您真的想确保迁移不会导致站点宕机,那么pt online schema change就是一个不错的选择 正如我在上面的评论中所写的那样,我在生产中有几次pt在线模式更改的经验。我们的主表有20M+记录和一个主->2个只读复制从机。我
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
ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;