2015-03-31 85 views
1

我试图优化我的查询,但是当我尝试使用此查询增加一些指标:ADD INDEX崩溃的MySQL

ALTER TABLE `user` ADD INDEX `last_activity_date` (`last_activity_date`); 

...崩溃我的MySQL服务器。我的意思是我的网站不再回应,我的查询也没有执行。我唯一的解决方案是重新启动MySQL。这真的很烦人,因为我有一个应用程序,数百名用户显然无法在崩溃时使用它。

我有一个MySQL日志文件,但我没有看到它的任何错误。你认为这里有什么问题?难道是因为有些用户在添加索引时正在与数据库交互?我使用InnoDB。

我有超过100.000记录在user表看起来像:

CREATE TABLE `user` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
 `encrypt_id` varchar(255) DEFAULT NULL, 
 `register_date` datetime DEFAULT NULL, 
 `last_login_date` datetime DEFAULT NULL, 
 `username` varchar(255) DEFAULT NULL, 
 `password` varchar(255) DEFAULT NULL, 
 `email` varchar(255) DEFAULT NULL, 
 `banned` int(11) DEFAULT NULL, 
 `banned_reason` text, 
 `first_step_form` int(11) DEFAULT '0', 
 `status` int(11) DEFAULT NULL, 
 `referer` varchar(255) DEFAULT NULL, 
 `rank` int(11) DEFAULT NULL, 
 `fb_id` bigint(20) DEFAULT NULL, 
 `last_activity_date` datetime DEFAULT NULL, 
 PRIMARY KEY (`id`), 
 KEY `last_activity_date` (`last_activity_date`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
+0

你可以发布更多的信息,比如'user'表中的记录数......一个SHOW CREATE TABLE就像'user''''语句吗? – cerd 2015-03-31 19:50:27

+0

[在没有表锁定的情况下在一个巨大的mysql生产表上创建索引]的可能的重复(http://stackoverflow.com/questions/4244685/create-an-index-on-a-huge-mysql-production-table-without -table-locking) – 2015-03-31 19:52:12

+1

你是如何确定mysql崩溃的?你确定它不只是创建索引?用一张足够大的表创建索引可能不仅仅是一眨眼的工作 - 我想我已经看到索引创建时间超过了30秒,所以我想它可能会更进一步。 – Kritner 2015-03-31 19:52:23

回答

2

假设你的网站非常活跃,你有100000个用户,并且last_activity_date字段在每次用户做某事(任何事情)时都会更新,那么在该字段上应用索引可能会造成严重破坏。很多行可能需要花费几分钟时间才能应用,如果它不锁定用户,那么索引永远不会被创建,因为在用户不断更改字段之前,它必须保持更新才能完成更新锁定用户以防止出现这种情况)。

像last_activity_date那样对字段进行索引的唯一原因是针对它运行报表(例如,在过去30天内谁做了某些用户的操作)或定期维护(禁用未在其中执行任何操作的用户最近30天)。如果是这种情况,则最好创建一个辅助表并使用用户表数据加载它,然后在该表上应用索引。您的报告不会针对实时数据 - 但您的报告不应该需要即时结果。每天更新一次次表可能不会很长 - 也许几分钟 - 并且它不会锁定过程中的用户。

+0

这是个好主意!我会尝试使用用户表的副本。 是的,我的网站非常活跃。我正在努力改进MySQL查询,因为我的服务器实际上非常慢。 – fraxool 2015-03-31 20:21:57

+0

冥想是一把双刃剑。是的,他们在查询时会提高性能 - 但更新时会影响性能。这是一个权衡。如果您的表格主要用于查询,那么添加索引将有所帮助 - 并且可能会有很大帮助。但是,如果您主要更新表 - 例如对last_activity_date进行了大量更改 - 那么添加索引实际上会损害您的整体性能,因为数据库必须更新该索引。 – Russ 2015-03-31 20:25:41

2

如果你有一些使用表和ALTER TABLE用户需要一点时间来执行,你是耗尽内存。这就是你在错误日志中没有看到任何东西的原因。您的内存不足,因为您有一对多连接,因为用户在Alter表查询运行时正在获取元数据数据锁定等待超时。

我不得不在表格上添加一个索引,并在前几天在生产中创建了4200万条记录。花了10分钟才完成。数据库每分钟读取17k以上。我有PROCESSLIST开放和杀害任何查询,其state显示的元数据锁定等待超时,这样我就没有能像这样被确定我最糟糕的情况下下降:

innodb_buffer_pool_size + key_buffer_size + max_connections * (sort_buffer_size + read_buffer_size + binlog_cache_size) + max_connections * 2MB

如果你没有这些参数设置正确并且达到最大连接数量时,可能会导致内存不足,导致服务器崩溃。

+0

大部分正确。尽管如此,最大化连接只与切断内存相关。那些确实是两种独立的失败模式。人们可能会感觉到MySQL服务器没有响应(并且无法获得新的连接),只是基于长时间运行的锁定进程而达到max_connections阈值,而没有接近内存分配限制(这通常会导致MySQL更频繁地开始分页到磁盘)。类似地,只是由于负载的高并发性而没有达到最大连接,可能会遇到内存问题。 – 2015-03-31 20:13:46

+0

基于这种失败的时间匹配“ADD INDEX”操作,我想冒险猜测OP由于连接堆栈而失败。 – 2015-03-31 20:16:15

+0

同意。感谢您添加并澄清我的答案。我只是指出了一个潜在的问题,不是必要的原因。也就是说,如果参数设置不正确,并且由于锁定等待超时而导致连接太多,则服务器可能会OOMing。 – BK435 2015-03-31 20:30:28