我需要你的一些建议。 有一些巨大的表(innodb),有大约600kk(6亿)行。 MySQL版本是5.5。实时/生产系统中的DB。 结构示例:
CREATE TABLE `rows` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`str_id` varchar(255) NOT NULL,
`file_id` int(11) unsigned NOT NULL,
`upload_date` datetime NOT NULL,
`acticity_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `MSGID_INDEX` (`str_id`),
) ENGINE=InnoDB
此时一切顺利,但我们需要从表中删除垃圾行,删除子句是:
WHERE file_id = 0 AND activity_date < (NOW() - INTERVAL 7 DAY)
表满垃圾行~50-60%(300-400kk)。所以我们需要删除很多行,逻辑方式是尝试用块删除,但问题是我们没有索引(file_id,activity_date),所以删除需要太多时间。 例如(尝试1k到100k,最佳(按时间)是100k):
DELETE from rows WHERE file_id = 0 AND activity_date < (NOW() - INTERVAL 7 DAY) LIMIT 100000;
执行~5-6分钟,这需要太长时间。 也许我们需要添加索引(file_id,activity_date)到表(我们有5.5 mysql版本)然后尝试删除,但它是生产数据库,所以添加索引可能会导致一些锁,另一种方法是继续逐步删除行? 无论如何,我们需要添加索引,但如果我们在清除数据库中的垃圾后执行此操作会更好。 有什么建议吗?
UPD
似乎是我找到满意的解决方案(我使用5k块,但不保证这个5k将从DB中删除,它是我的数据库的最佳变体,并且需要几秒钟)相对于我的任务,使用id字段就像行reducer一样。感谢您的意见!方法,简单的bash脚本:
#!/bin/bash
trap "exit" INT
COUNTER=1
LIMIT=5000
START=1300000000
while :
do
date1=$(date +"%s")
Q="DELETE FROM TABLE WHERE id > $(($START + $LIMIT)) AND id < $(($START + 2*$LIMIT)) AND YOUR_CLAUSE LIMIT $LIMIT;"
mysql -D DB_NAME -uroot -p"PASS" -e "$Q"
date2=$(date +"%s")
diff=$(($date2-$date1))
echo "chunk($Q) deleted -- $COUNTER, $(($diff / 60)) minutes and $(($diff % 60)) seconds elapsed."
COUNTER=$[$COUNTER +1]
START=$(($START + $LIMIT))
#sleep 1
done
谢谢!
答案 0 :(得分:2)
LIMIT 100000
太多了。 1000就足够了。
如果id
和activity_date
齐头并进,那么查询应该可以正常工作,直到您到达最后一个。那时它会扫描整个桌子并且是一种麻烦。
如果它们不能齐头并进,DELETE将变得越来越慢,因为它必须跨越新的&#39;带有&#39; old&#39;的行IDS。
最好根据id
对表格进行分块。我在my blog中详细介绍了这一点。
请注意,它使用LIMIT 1000,1来查找到达的距离 - 它将触摸1000行,然后删除最多 1000行。这使得努力始终受到限制。
是的,这将需要&#34;天&#34;完成。那时,你也可以重新开始!
如果您没有file_id=0
测试:
更好(将来)将表格设为PARTITION BY RANGE(TO_DAYS(activitydate))
。那么DROP PARTITION
将是即时的。我在another blog中详细介绍了详细信息,包括示例代码。
更好(也许)将转换为PARTITIONing now ,方法是复制 &#34; new&#34;数据。这个一次过程就像
CREATE TABLE new (...) PARTITION BY ...;
INSERT INTO new SELECT * FROM rows WHERE activitydate > NOW() - INTERVAL 7 DAY;
RENAME TABLE rows TO old, new TO rows;
DROP TABLE old;
这将是完成整个任务的最快方法。未来的DELETE将由DROP PARTITION
完成,这是即时的。但是...... INSERT...SELECT
需要很长时间,而且在发生这种情况时你不应该写rows
。
所以,你选择:
警告:FOREIGN KEYS
和某些UNIQUE
限制不适用于PARTITION
。