我正在尝试删除大约4000万条记录中的267条记录。查询如下所示:
delete from pricedata
where
pricedate > '20120413'
pricingate是char(8)
字段。
我知道如何调整innodb_buffer_pool_size
,但如果可以的话
select from pricedata
where
pricedate > '20120413'
并获得267条记录(这就是全部),没有错误,为什么它会删除?
如果调整innodb_buffer_pool_size
不起作用,我该怎么办?
答案 0 :(得分:7)
您似乎没有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
关闭,请不要忘记在每个语句后提交。)
使用DELETE
事务隔离级别运行READ COMMITTED
查询。一旦读取,它将使InnoDB
从记录中解除锁定。如果您使用二进制日志语句模式并且不允许binlog-unsafe查询(这是默认设置),则无效。
答案 1 :(得分:4)
(一个迟到的答案,但是当人们在谷歌中发现这个问题时,alwayx很好用)
无需更改innodb_buffer_pool_size或创建索引的解决方案可以限制要删除的行数。
因此,在您的情况下DELETE from pricedata where pricedata > '20120413' limit 100;
例如。
这将删除100行并留下167。因此,您可以再次运行相同的查询并删除另一个100。
对于最后的67,它很棘手......当数据库中剩余的行数小于给定的限制时,你将再次得到关于锁数的错误。可能是因为服务器将搜索更多匹配的行以填充100。
在这种情况下,请使用limit 67
删除最后一部分。
(当然你也可以在开头使用limit 267
)
对于那些喜欢编写脚本的人...我在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
答案 2 :(得分:2)
什么有效:将innodb_buffer_pool_size更改为256M(请参阅Quassnoi原始评论下的评论)。