我有一个庞大的MySQL(InnoDB)数据库,会话表中有数百万行,这些行是由与我们相同的服务器上运行的无关,故障的爬虫创建的。不幸的是,我现在必须解决这个问题。
如果我尝试truncate table sessions;
,似乎需要花费相当长的时间(超过30分钟)。我不关心数据;我只想让桌子尽快消失。有没有更快的方法,还是我必须在一夜之间坚持下去?
答案 0 :(得分:124)
(由于Google的搜索结果有所提高,我认为更多的指示可能会很方便。)
MySQL有一种方便的方法来创建像现有表这样的空表,以及一个原子表重命名命令。总之,这是清除数据的快捷方式:
CREATE TABLE new_foo LIKE foo;
RENAME TABLE foo TO old_foo, new_foo TO foo;
DROP TABLE old_foo;
完成
答案 1 :(得分:47)
最快的方法是使用DROP TABLE完全删除表并使用相同的定义重新创建它。如果表上没有外键约束,那么你应该这样做。
如果你使用的MySQL版本大于5.0.3,这将通过TRUNCATE自动发生。您也可以从手册中获得一些有用的信息,它描述了TRUNCATE如何使用FK约束。 http://dev.mysql.com/doc/refman/5.0/en/truncate-table.html
编辑:TRUNCATE与drop或DELETE FROM不同。对于那些对差异感到困惑的人,请查看上面的手册链接。如果可以的话,TRUNCATE将与drop一样(如果没有FK),否则它就像DELETE FROM而没有where子句。
答案 2 :(得分:7)
难道你不能抓住架构下拉表并重新创建吗?
答案 3 :(得分:7)
我发现使用MySQL执行此操作的最佳方法是:
DELETE from table_name LIMIT 1000;
或10,000(取决于它发生的速度)。
将其放入循环中,直到删除所有行。
请尝试这样做,因为它实际上会起作用。这需要一些时间,但它会奏效。
答案 4 :(得分:3)
drop table
应该是摆脱它的最快方法。
答案 5 :(得分:1)
你试过用“掉线”吗?我已经在超过20GB的表上使用它,它总是在几秒钟内完成。
答案 6 :(得分:1)
如果您只是想完全摆脱桌面,为什么不简单地放弃呢?
答案 7 :(得分:1)
截断很快,通常在几秒或更短的时间。如果花了30分钟,你可能有一些外键引用你正在截断的表。可能还存在锁定问题。
Truncate实际上和人们可以清空表一样有效,但是你可能必须删除外键引用,除非你想要擦除这些表。
答案 8 :(得分:0)
我们遇到了这些问题。我们不再将数据库用作Rails 2.x和cookie存储的会话存储。但是,放弃桌子是一个不错的解决方案。您可能需要考虑停止mysql服务,暂时禁用日志记录,以安全模式启动,然后执行drop / create。完成后,再次打开日志记录。
答案 9 :(得分:0)
我不确定为什么这么长时间。但也许尝试重命名,并重新创建一个空白表。然后你可以删除“额外”表而不用担心需要多长时间。
答案 10 :(得分:0)
searlea的answer很不错,但正如评论中所述,你在战斗中丢失了外键。 此解决方案类似:truncate在一秒钟内执行,但保留外键。
诀窍是我们禁用/启用FK检查。
SET FOREIGN_KEY_CHECKS=0;
CREATE TABLE NewFoo LIKE Foo;
insert into NewFoo SELECT * from Foo where What_You_Want_To_Keep
truncate table Foo;
insert into Foo SELECT * from NewFoo;
SET FOREIGN_KEY_CHECKS=1;
我的问题是:由于一个疯狂的脚本,我的表是用于7.000.000垃圾行。我需要删除此表中99%的数据,这就是为什么我需要在删除之前将我想保留的内容复制到tmp表中。
我需要保留的这些Foo行取决于具有外键和索引的其他表。
类似的东西:
insert into NewFoo SELECT * from Foo where ID in (
SELECT distinct FooID from TableA
union SELECT distinct FooID from TableB
union SELECT distinct FooID from TableC
)
但是这个查询总是在1小时后超时。 所以我必须这样做:
CREATE TEMPORARY TABLE tmpFooIDS ENGINE=MEMORY AS (SELECT distinct FooID from TableA);
insert into tmpFooIDS SELECT distinct FooID from TableB
insert into tmpFooIDS SELECT distinct FooID from TableC
insert into NewFoo SELECT * from Foo where ID in (select ID from tmpFooIDS);
我的理论,因为索引设置正确,我认为填充NewFoo的两种方式应该是相同的,但实际上它没有。
这就是为什么在某些情况下,你可以这样做:
SET FOREIGN_KEY_CHECKS=0;
CREATE TABLE NewFoo LIKE Foo;
-- Alternative way of keeping some data.
CREATE TEMPORARY TABLE tmpFooIDS ENGINE=MEMORY AS (SELECT * from Foo where What_You_Want_To_Keep);
insert into tmpFooIDS SELECT ID from Foo left join Bar where OtherStuff_You_Want_To_Keep_Using_Bar
insert into NewFoo SELECT * from Foo where ID in (select ID from tmpFooIDS);
truncate table Foo;
insert into Foo SELECT * from NewFoo;
SET FOREIGN_KEY_CHECKS=1;