我有一个数据库表,给我插入大量数据时的头痛,错误。让我分解究竟发生了什么,我希望有人对我如何解决这个问题有一些了解。大INNODB表锁定
基本上我有一张表,里面有1100万条记录,它每天都在增长。我们会跟踪用户观看视频的次数及其在该视频中的进度。你可以在下面看到结构是什么样子。我们的设置是一个主数据库,并附有两个从站。每晚我们运行一个cron脚本来编译这个表格中的一些统计数据,并将它们编译成我们仅用于报告的其他表格。这些cron脚本只会在从属设备上执行SELECT语句,并会将其插入主设备上的统计表中(所以它会向下传播)。每次我们运行这个脚本时,就像发条一样,它会锁定我们的制作表。我认为将SELECT移到一个slave上会解决这个问题,因为我们甚至没有用cron写入主表,而是用其他表写,所以我现在困惑什么可能会导致这种锁定。
这似乎似乎每次在主表(主或从)上的大量读取都会锁定主设备。一旦cron完成,表格就会恢复正常性能。
我的问题是关于INNODB的几个级别。我有这样的想法,它可能是索引,会导致这个问题,但也许它是INNODB设置的其他变量,我不完全理解。正如你想象的那样,我想让主人避免这个锁定。我并不关心在这个脚本运行过程中是否挂钩了slave,只要它不会影响我的master db。这在MYSQL中的Slave/Master关系中会发生吗?
获取编译信息的表格是stats_daily,stats_grouped以供参考。
我在这里最大的问题,稍微重申一下,是我不明白什么会导致像这样的锁定。将读取数据从主数据库中取出,只是插入到另一个表中,似乎不应该在主数据表上执行任何操作。我可以看到错误开始流入,但是,在脚本启动3分钟后,脚本停止后它会立即结束。
我正在使用的表格如下。
CREATE TABLE IF NOT EXISTS `stats` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`VID` int(10) unsigned NOT NULL DEFAULT '0',
`UID` int(10) NOT NULL DEFAULT '0',
`Position` smallint(10) unsigned NOT NULL DEFAULT '0',
`Progress` decimal(3,2) NOT NULL DEFAULT '0.00',
`ViewCount` int(10) unsigned NOT NULL DEFAULT '0',
`DateFirstView` int(10) unsigned NOT NULL DEFAULT '0', // Use unixtimestamps
`DateLastView` int(10) unsigned NOT NULL DEFAULT '0', // Use unixtimestamps
PRIMARY KEY (`ID`),
KEY `VID` (`VID`,`UID`),
KEY `UID` (`UID`),
KEY `DateLastView` (`DateLastView`),
KEY `ViewCount` (`ViewCount`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=15004624 ;
有没有人有任何想法或想法呢?
UPDATE: 的错误,我从主数据库
MysqlError: Lock wait timeout exceeded; try restarting transaction
Uncaught exception 'Exception' with message 'invalid query UPDATE stats SET VID = '13156', UID = '73859', Position = '0', Progress = '0.8', ViewCount = '1', DateFirstView = '1375789950', DateLastView = '1375790530' WHERE ID = 14752456
更新查询失败,因为锁定的获得。该查询实际上是有效的。我会得到这些100个,然后我可以随机复制/粘贴这些查询,他们将工作。
UPDATE 2 查询和从克朗脚本解释
查询然在从站(在大括号离开PHP变量供参考):
SELECT
VID,
COUNT(ID) as ViewCount,
DATE_FORMAT(FROM_UNIXTIME(DateLastView), '%Y-%m-%d') AS YearMonthDay,
{$today} as DateModified
FROM stats
WHERE DateLastView >= {$start_date} AND DateLastView <= {$end_date}
GROUP BY YearMonthDay, VID
解释SELECT统计的
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE stats range DateLastView DateLastView 4 NULL 25242 Using where; Using temporary; Using filesort
该结果集循环并插入到编译表中。不幸的是,我不支持使用此批处理插入(我试过),所以我必须一次遍历这些批处理插入,而不是一次向服务器发送一批100或500。这被插入主数据库。
foreach ($results as $result)
{
$query = "INSERT INTO stats_daily (VID, ViewCount, YearMonthDay, DateModified) VALUES ({$result->VID}, {$result->ViewCount}, '{$result->YearMonthDay}', {$today});
DoQuery($query);
}
如果从主设备上看到任何错误,而在设备处理过程中设备停止在从设备上。 – RiggsFolly
我认为你也应该发送你的cronjob脚本的部分内容来查询你运行的是什么查询,并在这些查询上运行EXPLAIN,并在这里发布结果,并提供关于什么查询生成了什么解释的很好的信息。 –
检查你的mysql tmp dir(如果你在linux上可能是/ tmp,看看是否有MYD或MYI文件,如果你运行cronjob make,请使用ll并输入几次关闭时间)。如果因为基于磁盘的临时表被创建而不好,那么会导致性能下降 –