我需要在~5M行MySQL表上创建索引。这是一个生产表,如果我运行CREATE INDEX语句,我担心一切都完整......
有没有办法在不阻塞插入和选择的情况下创建该索引?
只是想知道我没有停下来,创建索引并重启我的系统!
答案 0 :(得分:108)
https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html
在MySQL 5.6及更高版本中,在创建或删除索引时,该表仍可用于读写操作。 CREATE INDEX或DROP INDEX语句仅在完成访问表的所有事务完成后才结束,因此索引的初始状态反映了表的最新内容。以前,在创建或删除索引时修改表通常会导致死锁,从而取消表上的INSERT,UPDATE或DELETE语句。
从上面的答案:
"如果您在数据库联机时创建了使用大于5.1索引的版本。所以不要担心你不会中断生产系统的使用。"
这是**** FALSE **** (至少对于MyISAM / InnoDB表,这是99.999%的人使用。群集版本是不同的。)
在创建索引时,对表执行UPDATE操作将 BLOCK 。对于这个(以及其他一些事情),MySQL真的非常愚蠢。
测试脚本:
(
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架构并且不会出现可用性中断。圆形大师:
更新架构的简便方法不是这样。可在严峻的生产环境中使用;是的。请问,如果有一种更简单的方法可以在不阻止写入的情况下向MySQL表添加索引,请告诉我。
谷歌搜索引导我this article描述了一种类似的技术。更好的是,他们建议在行程中的同一时间饮酒(注意我在阅读文章之前写了我的答案)!
上面我链接的article讨论了一个工具pt-online-schema-change,其工作原理如下:
我自己从未尝试过这个工具。 YMMV
我目前正通过Amazon's RDS使用MySQL。它是一个非常漂亮的服务,它包装和管理MySQL,让您只需一个按钮即可添加新的只读副本,并透明地在硬件SKU上升级数据库。这真的很方便。您无法获得对数据库的超级访问权限,因此您无法直接使用复制(这是一种祝福还是诅咒?)。但是,您可以使用Read Replica Promotion在只读从属设备上更改架构,然后将该从属设备升级为新的主设备。与我上面描述的完全相同的技巧,只是更容易执行。他们仍然没有做太多帮助你完成切换。您必须重新配置并重新启动应用程序。
答案 1 :(得分:53)
正如此blog post概述,InnoDB ALTER TABLE
机制已针对MySQL 5.6进行了全面重新设计。
(有关此主题的独家概述,MySQL documentation可以提供下午的阅读价值。)
要在UPDATE
/ INSERT
上的表格没有锁定的情况下添加索引,可以使用以下语句格式:
ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;
答案 2 :(得分:14)
MySQL 5.6更新(2013年2月):即使使用InnoDB表,您现在也可以在创建索引时执行读写操作 - http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html
在MySQL 5.6及更高版本中,在创建或删除索引时,该表仍可用于读写操作。 CREATE INDEX或DROP INDEX语句仅在完成访问表的所有事务完成后才结束,因此索引的初始状态反映了表的最新内容。以前,在创建或删除索引时修改表通常会导致死锁,从而取消表上的INSERT,UPDATE或DELETE语句。
和:
在MySQL 5.6中,此功能变得更加通用:您可以在创建索引时读取和写入表,并且可以在不复制表的情况下执行更多种类的ALTER TABLE操作,而不会阻止DML操作,或者两者都执行。因此,在MySQL 5.6及更高版本中,我们通常将这组功能称为在线DDL,而不是快速索引创建。
来自http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_fast_index_creation
答案 3 :(得分:3)
如果您确实希望确保迁移不会导致网站崩溃,那么pt-online-schema-change就是您的选择。
正如我在上面的评论中所写,我在生产中有一些pt-online-schema-change的经验。我们有20M +记录的主表和一个主 - > 2个只读复制从属。我已经通过添加新列,更改字符集以及添加多个索引来完成pt-online-schema-change的至少几十次迁移。我们在迁移期间也提供大量的流量,而且我们没有任何打嗝。当然,在运行生产之前,你必须非常彻底地测试所有脚本。
我尝试将更改批量处理为1个脚本,以便pt-online-schema-change只需复制一次数据。因为您将丢失数据,所以要非常小心更改列名。但是,添加索引应该没问题。