mysql - 从InnoDB删除行非常慢

时间:2014-04-01 11:03:51

标签: mysql sql innodb

我有一个大约有的mysql数据库。 1 TB的数据。表fuelinjection_stroke有apprx。 1.000.000.000行。 DBID是每个插入时自动递增1的主键。

我试图使用一个非常简单的语句删除前1.000.000行:

Delete from fuelinjection_stroke where DBID < 1000000;

此查询在我的专用8核Xeon服务器(32 GB内存,SAS存储)上耗时很长(> 24小时)。

是否可以加快进程?

7 个答案:

答案 0 :(得分:19)

我相信你的桌子会被锁定。我遇到了同样的问题,发现可以很快删除10k记录。所以你可能想编写一个简单的脚本/程序,它将按块删除记录。

   DELETE FROM fuelinjection_stroke WHERE DBID < 1000000 LIMIT 10000;

继续执行它直到它删除所有内容

答案 1 :(得分:5)

你是否被剥夺了空间?停工时间不可能吗?

如果没有,您可以适应新的INT列长度1,并将其默认为1表示“活动”(或任何术语),0表示“非活动”。实际上,如果需要,你可以使用0到9作为10种不同的状态。

添加这个新列将花费很多时间,但是一旦结束,只要你从PRIMARY(就像你使用DELETE一样)执行它,你的UPDATE应该是闪电般快的,并且你没有索引这个新列

InnoDB在如此庞大的表上删除这么长时间的原因是因为群集索引。它根据您的PRIMARY(或者它找到的第一个UNIQUE ......或者无法找到PRIMARY或UNIQUE的感觉)对您的表进行物理排序,因此当您拉出一行时,它会在物理上重新排序您的整个表格用于速度和碎片整理的磁盘。所以不是DELETE花了这么长时间。这行是被删除后的物理重新排序。

当您使用默认值创建新的INT列时,空间将被填充,因此当您更新它时,不需要在您的巨大表格中进行物理重新排序。

我不确定你的模式究竟是什么,但是使用列的行状态要比DELETEing快得多;但是,它需要更多的空间。

尝试设置值:

innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT (for non-windows machine)
innodb_buffer_pool_size=25GB (currently it is close to 21GB)
innodb_doublewrite=0
innodb_support_xa=0
innodb_thread_concurrency=0...1000 (try different values, beginning with 200)

参考文献:

MySQL docs for description of different variables.

MySQL Server Setting Tuning

MySQL Performance Optimization basics

http://bugs.mysql.com/bug.php?id=28382

答案 2 :(得分:3)

你有什么指数?

我认为你的问题是删除是在每次迭代时重建索引。

我删除索引(如果有),执行删除操作,然后重新添加索引。它会快得多,(我想)。

答案 3 :(得分:1)

我遇到了同样的问题,我的表有几个索引,我不想丢弃和重新创建。所以我做了以下事情:

ssh user@remote_host "oozie job -run -D oozie.wf.application.path=hdfs://hdf-example-cluster -D key=value"

大约3分钟内处理了大约220万行。

答案 4 :(得分:0)

您的数据库可能正在检查需要在外键中修改的记录(级联,删除)。

但I-Conica的答案是一个好点(+1)。在完成100000次期间删除单个记录并更新大量索引的过程效率低下。只需删除索引,删除所有记录并再次创建。

当然,检查数据库中是否存在任何类型的锁定。一个用户或应用程序可以锁定记录或表,您的查询将等待用户释放资源或达到超时。检查数据库是否正在执行实际工作或只是等待的一种方法是将连接设置--innodb_lock_wait_timeout参数设置为几秒钟。如果它至少失败,你知道查询是正常的,你需要找到并重新发布该锁。锁的示例是从XXX中选择*用于更新和未通信的事务。

答案 5 :(得分:0)

对于这么长的桌子,我宁愿使用MYISAM,特别是在不需要大量事务的情况下。

答案 6 :(得分:-7)

我不知道确切的问题。但是写另一种删除这些行的方法,请试试这个。

delete from fuelinjection_stroke where DBID in
(
    select top 1000000 DBID  from fuelinjection_stroke 
    order by DBID asc
)