Mysql &引用;锁的总数超过了锁表的大小;删除267条记录
我正试图从大约4000万张唱片中删除267张。查询如下所示:Mysql &引用;锁的总数超过了锁表的大小;删除267条记录,mysql,locking,innodb,sql-delete,Mysql,Locking,Innodb,Sql Delete,我正试图从大约4000万张唱片中删除267张。查询如下所示: delete from pricedata where pricedate > '20120413' pricedate是一个char(8)字段 我知道如何调整innodb\u buffer\u pool\u size,但如果可以的话 select from pricedata where pricedate > '20120413' 并获得267条记录(仅此而已),没有错误,为什么它会在删除时阻塞 如果调整innod
delete from pricedata
where
pricedate > '20120413'
pricedate是一个char(8)
字段
我知道如何调整innodb\u buffer\u pool\u size,但如果可以的话
select from pricedata
where
pricedate > '20120413'
并获得267条记录(仅此而已),没有错误,为什么它会在删除时阻塞
如果调整
innodb\u buffer\u pool\u size
不起作用,我该怎么办?您似乎没有关于pricedate
的索引(或者MySQL
出于某种原因没有使用此索引)
使用REPEATABLE READ
(默认事务隔离级别),InnoDB
将共享锁放在查询读取和筛选出的记录上,您似乎没有足够的空间容纳40M
锁
要解决此问题,请使用以下任一解决方案:
pricedate
上创建索引(如果不存在)(可能需要时间)DELETE
FROM pricedata
WHERE pricedate > '20120413'
AND id BETWEEN 1 AND 1000000
DELETE
FROM pricedata
WHERE pricedate > '20120413'
AND id BETWEEN 1000001 AND 2000000
等等(根据需要更改id
范围)。请注意,每条语句都应该在自己的事务中运行(如果AUTOCOMMIT
处于关闭状态,请不要忘记在每条语句之后提交)readcommitted
事务隔离级别运行DELETE
查询。一旦记录被读取,它将使InnoDB解除锁定。如果在语句模式下使用二进制日志,并且不允许binlog不安全查询(这是默认设置),则此操作将不起作用工作原理:将innodb缓冲池大小更改为256M(请参见Quassnoi原始评论下的评论)。(虽然回答较晚,但当人们在谷歌上发现这个问题时,拥有它总是很好的) 不必改变innodb_buffer_pool_大小或创建索引的解决方案可以是限制要删除的行数 因此,在您的案例中,
从pricedata中删除,其中pricedata>“20120413”限制为100代码>例如。
这将删除100行,留下167行。因此,您可以再次运行相同的查询并删除另外100个查询。
在过去的67年里,这很棘手。。。当数据库中剩余的行数小于给定的限制时,您将再次遇到关于锁数的错误。可能是因为服务器将搜索更多匹配的行以填充100行。
在这种情况下,使用limit 67
删除最后一部分。
(当然,您也可以在一开始就使用limit267
)
对于那些喜欢写剧本的人。。。我在bash脚本中使用了一个很好的示例来清理旧数据:
# Count the number of rows left to be deleted
QUERY="select count(*) from pricedata where pricedata > '20120413';"
AMOUNT=`${MYSQL} -u ${MYSQL_USER} -p${MYSQL_PWD} -e "${QUERY}" ${DB} | tail -1`
ERROR=0
while [ ${AMOUNT} -gt 0 -a ${ERROR} -eq 0 ]
do
${LOGGER} " ${AMOUNT} rows left to delete"
if [ ${AMOUNT} -lt 1000 ]
then
LIMIT=${AMOUNT}
else
LIMIT=1000
fi
QUERY="delete low_priority from pricedata where pricedata > '20120413' limit ${LIMIT};"
${MYSQL} -u ${MYSQL_USER} -p${MYSQL_PWD} -e "${QUERY}" ${DB}
STATUS=$?
if [ ${STATUS} -ne 0 ]
then
${LOGGER} "Cleanup failed for ${TABLE}"
ERROR=1
fi
QUERY="select count(*) from pricedata where pricedata > '20120413';"
AMOUNT=`${MYSQL} -u ${MYSQL_USER} -p${MYSQL_PWD} -e "${QUERY}" ${DB} | tail -1`
done
你有关于pricedate
的索引吗?我在发布后不久(不幸的是,在你回复之前)就放了一个索引。它还在建!幸好这是一个周末…@davej:在这么大的桌子上,这至少需要40
分钟,如果你有很多列(或长TEXT
或二进制列),这需要几个小时和几天。如果您没有使用InnoDB 1.1(或插件),则需要花费更多的时间。再次感谢您提供的信息。共有8个字段;“pricedate”是唯一非数字的。有,tho,2个BIGINT(20),所以我不知道这将如何考虑。事实上,我无论如何都得出去几个小时,所以我就让它跑吧。幸好这是在测试数据库上@达维:有了一台像样的服务器,大概需要一两个小时。事实上,6个小时后它还没完成,所以我就把它关掉了。然后,我尝试使用索引重新创建表,然后使用“加载数据填充…”加载表。如果没有索引,文件运行不到40分钟。有了这个指数,它在2小时15分钟内达到了负载的40%左右,并且随着时间的推移而变慢。我使用char格式作为日期字段,因为它在我的应用程序中运行良好,并且更易于加载。现在我想知道我是否应该把它改成一个实际的日期。我假设是因为数字字段更容易索引?还是更容易用作删除查询的条件?非常感谢你的洞察力。