在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分钟。
答案 0 :(得分:0)
在3个单独的DELETE
查询中执行此操作并没有错。
优点:
缺点:
我建议您采用更优化的方式:
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在引用行之前删除引用行的问题;但你已经声明你没有那些。