在MySQL中使用多个DELETE而不是JOIN DELETE

时间:2016-10-19 20:01:22

标签: mysql sql join sql-delete delete-row

在MySQL中,我想删除表t1中的行以及表t2中满足某些条件的所有相关行(比如某种状态)。

我知道我可以这样做:

DELETE t1 FROM t1 INNER JOIN t2
WHERE t1.some_id = t2.some_id
AND t1.status=3;

但是t2中有一些未被t1引用的悬空数据,我也希望删除它(它和旧的数据库)。我想我可以为此进行外连接,并使用内部连接进行UNION。但它变得更复杂,因为我需要删除大约10个表中的行,所有表都与ID相关。最终的结果是一个疯狂的大问题。

所以我做到了这一点:

DELETE FROM t1
WHERE status=3;

DELETE FROM t2 
WHERE some_id NOT IN (SELECT some_ID FROM t1)

DELETE FROM t3 
WHERE some_id NOT IN (SELECT some_ID FROM t2)
所有表格的

等等。这样,所有未引用的数据都将被删除,并且更具可读性。请注意,没有外键,我无法更改表格(所以忘记"级联删除")。

那么,那是错的吗? 这样做的缺点是什么呢?

由于

编辑: 表很大,t1有50万行,t2有3百万行,其他8个表不到50万行。但我也删除了大量数据,大约75%。

编辑2: 好的,我会向您展示真实的东西,而不仅仅是一个例子。 这样做的目的是在osTicket中删除大约250000张旧票(在备份之后)。

在VM中工作,我首先尝试了这个:

DELETE ticket, thread, event, cdata, user, email, email_info
FROM       ost_ticket            AS ticket 
INNER JOIN ost_ticket_thread     AS thread 
INNER JOIN ost_ticket_event      AS event
INNER JOIN ost_ticket__cdata     AS cdata
INNER JOIN ost_user              AS user
INNER JOIN ost_user_email        AS email
INNER JOIN ost_ticket_email_info AS email_info
WHERE ticket.ticket_id = thread.ticket_id
AND   ticket.ticket_id = event.ticket_id
AND   ticket.ticket_id = cdata.ticket_id
AND   ticket.user_id   = user.id
AND   ticket.user_id   = email.user_id
AND   thread.id        = email_info.thread_id
AND   ticket.status_id=3 
AND   (ticket.closed < DATE_SUB(NOW(), INTERVAL 30 DAY));

只清除7个表,我需要添加至少2-3个表。也许更多。运行需要15分钟,并在那里留下大量未引用的数据。

然后我去了(在一个刷新的虚拟机中)

START TRANSACTION;
DELETE FROM ost_ticket WHERE status_id=3 AND (closed < DATE_SUB(NOW(), INTERVAL 30 DAY));
DELETE FROM ost_ticket_thread WHERE ticket_id NOT IN (SELECT ticket_id FROM ost_ticket);
DELETE FROM ost_ticket_event WHERE ticket_id NOT IN (SELECT ticket_id FROM ost_ticket);
DELETE FROM ost_ticket__cdata WHERE ticket_id NOT IN (SELECT ticket_id FROM ost_ticket);
DELETE FROM ost_user WHERE id NOT IN (SELECT DISTINCT user_id FROM ost_ticket);
DELETE FROM ost_user_email WHERE user_id NOT IN (SELECT id FROM ost_user);
DELETE FROM ost_ticket_email_info WHERE thread_id NOT IN (SELECT id FROM ost_ticket_thread);
COMMIT;

它会将所有数据输出并运行8分钟。

2 个答案:

答案 0 :(得分:0)

在3个单独的DELETE查询中执行此操作并没有错。 优点:

  • 更具可读性
  • 它没有做重连接(如果表很大) - 在某些情况下它可能会执行得更快

缺点:

  • 如果表很大,那么第二个和第三个查询可能会很慢,因为子查询选择将返回大量数据....
  • 你会在3个步骤而不是一个步骤中删除 - 这意味着你会在第一个删除查询后的t2和t3中有数据,在第二个删除后的t3中...这取决于应用程序可能是好的或不是

我建议您采用更优化的方式:

DELETE FROM t3 
WHERE some_id IN (SELECT some_ID FROM t2 
WHERE some_id IN (SELECT some_ID FROM t1 WHERE status=3))

DELETE FROM t2 
WHERE some_id IN (SELECT some_ID FROM t1 WHERE status=3)

DELETE FROM t1
WHERE status=3;

如果您删除 t1 中的较少行而不是 t1 中的行(删除后)订单会更快。不要忘记在上一个查询中从t1删除,因为上面的删除取决于t1 :)。但是这个顺序只有在级联删除的时候才有效(应该删除的t1行与t2和t3相关)

答案 1 :(得分:0)

使用像这样的多表删除语法有什么特别的错误吗?

DELETE t1, t2, t3 
FROM t1 
INNER JOIN t2 ON t1.some_ID = t2.some_ID
INNER JOIN t3 ON t2.some_ID = t3.some_ID
WHERE t1.status=3
;

我知道如果你有外键,这有时会引起MySQL在引用行之前删除引用行的问题;但你已经声明你没有那些。