Ryu*_*yuK 5 php mysql sql database indexing
假设我们有一个带有 MySQL 5.6 数据库的 Web 论坛应用程序,许多用户可以 24/7 全天候访问该应用程序。现在有一个这样的表,用于发送给用户的通知的元数据。
| notifications | CREATE TABLE `notifications` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) unsigned NOT NULL,
`message_store_id` bigint(20) unsigned NOT NULL,
`status` varchar(10) COLLATE ascii_bin NOT NULL,
`sent_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`,`sent_date`)
) ENGINE=InnoDB AUTO_INCREMENT=736601 DEFAULT CHARSET=ascii COLLATE=ascii_bin |
Run Code Online (Sandbox Code Playgroud)
该表有 100 万行。有了这个表,某个 message_store_id 由于某种原因突然变得无效,我计划使用单个删除语句删除所有具有该 message_store_id 的记录,例如
DELETE FROM notifications WHERE message_store_id = 12345;
Run Code Online (Sandbox Code Playgroud)
由于这条消息被发送给了如此多的用户,因此这一条语句影响了表的 10%。同时,成千上万的用户一直在访问此通知表,因此必须存在索引。显然,删除记录时重新创建索引的成本非常高,所以我担心这样做会导致服务器资源最大化而导致停机。但是,如果我删除索引,删除记录然后再次添加索引,我必须关闭数据库一段时间,不幸的是我们的服务无法使用。
我希望 MySQL 5.6 不会愚蠢到这个单一的语句可以杀死数据库,但我想它很有可能。我的问题是,对于这种情况,索引重建真的是致命的吗?如果是这样,此操作是否有任何不需要我停止数据库进行维护的好策略?
根据您的应用程序的详细信息,您可以采用很多技巧/策略。
message_store_id,则可以使用分区。按 的值进行分区message_store_id,预先创建 X 个分区(其中 X 是 id 值数量的合理上限),然后您可以通过截断该分区来立即删除该分区中的所有记录。几毫秒的事。缺点:message_store_id必须是主键的一部分。注意:您必须事先创建分区,因为上次我使用它们时,alter table add partition重新创建了整个表,这对于大型表来说是一场灾难。alter table truncate partition对您不起作用,您仍然可以从分区中受益。如果您DELETE在分区上发出 a,通过提供相应的where条件,表的其余部分将不会受到此 DELETE 操作的影响/锁定。删除记录而不锁定数据库太长时间的替代方法:
while (true) {
// assuming autocommit mode
delete from table where {your condition} limit 10000;
// at this moment locks are released and other transactions have a chance
// to do some stuff.
if (affected rows == 0) {
break;
}
// This is a good place to insert sleep(5) to give other transactions
// more time to do their stuff before the next chunk gets deleted.
}
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
1384 次 |
| 最近记录: |