在巨大的 MySQL 生产表上创建索引,无需表锁定
我需要在大约 5M 行的 MySQL 表上创建索引。这是一个生产表,如果我运行 CREATE INDEX 语句,我担心所有内容都会被完全阻塞...
有没有办法在不阻止插入和选择的情况下创建该索引?
只是想知道我不必停止,创建索引并重新启动我的系统!
I need to create an index on a ~5M rows MySQL table. It is a production table, and I fear a complete block of everything if I run a CREATE INDEX statement...
Is there a way to create that index without blocking inserts and selects?
Just wondering I have not to stop, create index and restart my system!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
[2017] 更新:MySQL 5.6 支持在线索引更新
https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes< /a>
[2015] 更新表索引会阻止 MySQL 5.5 中的写入
从上面的答案中:
这是 ****FALSE* ***(至少对于 MyISAM / InnoDB 表,这是 99.999% 的人使用的表。集群版本不同。)
在表上执行 UPDATE 操作将阻塞,而正在创建索引。 MySQL 在这方面(以及其他一些事情)真的非常非常愚蠢。
测试脚本:
我的服务器(InnoDB):
输出(注意第 6 个操作如何阻塞完成索引更新所需的约 400 毫秒):
与不阻塞的读取操作(交换脚本中的行注释):
更新 MySQL没有停机的模式
到目前为止,我所知道的只有一种方法可以更新 MySql 模式并且不会遭受可用性中断。循环主控:
这不是更新架构的简单方法。能适应恶劣的生产环境;是的。拜托,拜托,拜托,如果有一种更简单的方法可以在不阻止写入的情况下向 MySQL 表添加索引,请告诉我。
谷歌搜索引导我找到这篇文章 它描述了类似的技术。更好的是,他们建议在程序的同一点喝酒(请注意,我在阅读文章之前写了答案)!
Percona 的 pt-online-schema-change
文章我在上面链接了有关工具的讨论,pt-online-schema-change,其工作原理如下:
我自己从未尝试过该工具。 YMMV
RDS
我目前通过 Amazon 的 RDS 使用 MySQL。这是一项非常漂亮的服务,它封装并管理 MySQL,让您只需一个按钮即可添加新的只读副本,并跨硬件 SKU 透明地升级数据库。真的很方便。您无法获得对数据库的超级访问权限,因此您无法直接破坏复制(这是福还是祸?)。但是,您可以使用 读取副本升级以在只读从属设备上更改架构,然后将该从属设备升级为新的主设备。与我上面描述的技巧完全相同,只是更容易执行。他们在切换方面仍然没有多大帮助。您必须重新配置并重新启动您的应用程序。
[2017] Update: MySQL 5.6 has support for online index updates
https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes
[2015] Updating table indicies blocks writes in MySQL 5.5
From the answer above:
This is ****FALSE**** (at least for MyISAM / InnoDB tables, which is what 99.999% of people out there use. Clustered Edition is different.)
Doing UPDATE operations on a table will BLOCK while the index is being created. MySQL is really, really stupid about this (and a few other things).
Test Script:
My Server (InnoDB):
Output (notice how the 6th operation blocks for the ~400ms it takes to finish the index update):
Vs read operations which don't block (swap the line comment in the script):
Updating MySQL's Schema without downtime
Thusfar, there's only one method I know of to update a MySql schema and not suffer an availability outage. Circular masters:
An easy way to update schema this isn't. Workable in a serious production environment; yes, it is. Please, please, please, if there is an easier way to add an index to a MySQL table without blocking writes, let me know.
Googling lead me to this article which describes a similar technique. Even better, they advise drinking at the same point in the proceedure (Note that I wrote my answer before reading the article)!
Percona's pt-online-schema-change
The article I linked above talks about a tool, pt-online-schema-change, that works as follows:
I've never tried the tool myself. YMMV
RDS
I'm currently using MySQL through Amazon's RDS. It's a really nifty service that wraps up and manages MySQL, letting you add new read replicas with a single button and transparently upgrade the database across hardware SKU's. It's really convenient. You don't get SUPER access to the database, so you can't screw with replication directly (is this a blessing or curse?). However, you can use Read Replica Promotion to make your schema changes on a read-only slave, then promote that slave to become your new master. Exactly the same trick as I described above, just vastly easier to execute. They still don't do much to help you with the cut-over. You have to reconfigure and restart your app.
正如这篇博客文章概述的,InnoDB ALTER TABLE 机制已针对 MySQL 5.6 进行了完全重新设计。
(有关此主题的独家概述,MySQL 文档< /a> 可以提供一个下午的阅读量。)
要向无锁表添加索引,导致
UPDATE
/INSERT
,可以使用以下语句格式:As this blog post outlines, the InnoDB
ALTER TABLE
mechanism has been completely redesigned for MySQL 5.6.(For an exclusive overview of this topic, the MySQL documentation can provide an afternoon's worth of reading.)
To add an index to a table without a lock resulting on
UPDATE
/INSERT
, the following statement format can be used:MySQL 5.6 更新(2013 年 2 月):现在,即使使用 InnoDB 表创建索引,您也可以执行读写操作 - http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html
和:
来自 http://dev.mysql.com/doc/refman/ 5.6/en/glossary.html#glos_fast_index_creation
MySQL 5.6 update (feb 2013): You can now perform read and write operations while an index is being created even with InnoDB tables - http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html
and:
from http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_fast_index_creation
如果您确实想确保迁移不会导致站点瘫痪,那么 pt-online-schema-change 就是您的最佳选择。
正如我在上面的评论中所写,我在生产中拥有一些使用 pt-online-schema-change 的经验。我们有 20M+ 记录的主表和一个主表 -> 2 个只读复制从站。我已经使用 pt-online-schema-change 完成了至少数十次迁移,从添加新列、更改字符集到添加多个索引。我们在迁移期间也提供大量流量,并且没有出现任何问题。当然,在生产环境中运行之前,您必须非常彻底地测试所有脚本。
我尝试将更改批量合并到 1 个脚本中,以便 pt-online-schema-change 只需复制数据一次。更改列名称时要非常小心,因为您会丢失数据。不过,添加索引应该没问题。
pt-online-schema-change is the way to go if you really want to make sure that the migration will not bring down the site.
As I wrote in the above comment, I have several experiences with pt-online-schema-change in production. We have our main table of 20M+ records and a master -> 2 read-only replication slaves. I've done at least a dozens of migrations with pt-online-schema-change from adding a new column, changing charset, to adding several indices. We serve tons of traffic during the migration time as well and we have not had any hiccup. Of course you'd have to test all the scripts very thoroughly before running on production.
I tried to batch up the changes into 1 script so that pt-online-schema-change only have to copy the data once. And be very careful with changing column name since you will loose your data. However, adding an index should be fine.