我正在尝试开发一个查询,该查询将删除数据库中除最近添加的行之外的所有行。这基于Timestamp字段,存储为字符串和存储为字符串的User ID字段..
table.Timestamp -> text field
table.Retrieving_User -> text field
这是我开发的查询。我们在这个数据库中有大约50K的记录,运行速度非常慢。我希望它不是因为我正在进行的字符串转换,因为这需要完成。
DELETE
FROM `table` main
WHERE (main.Retrieving_User, STR_To_DATE( main.Timestamp , '%a %b %d %H:%i:%s CST %Y' )) NOT IN
(SELECT sub.Retrieving_User, MAX( STR_To_DATE( sub.Timestamp , '%a %b %d %H:%i:%s CST %Y' ))
FROM `table` sub
WHERE sub.Retrieving_User = 'userID'
GROUP BY sub.Retrieving_User )
AND main.Retrieving_User = 'userID'
有没有人知道我正在尝试做的更有效的方式?
答案 0 :(得分:1)
这样的事情可能会更快,因为它不会使用可能在内存表中反复循环的IN语句。备份并尝试
DELETE
FROM `table` main
WHERE STR_To_DATE( main.Timestamp , '%a %b %d %H:%i:%s CST %Y' )<
(SELECT MAX( STR_To_DATE( sub.Timestamp , '%a %b %d %H:%i:%s CST %Y' )
FROM `table` sub
WHERE sub.Retrieving_User = main.Retrieving_User )
AND main.Retrieving_User = 'userID'
答案 1 :(得分:1)
每当你删除很多行并且你保留的行数比你要删除的行数要少得多时,来自MySQL documentation的这个技巧非常有效:
如果要从大表中删除多行,则可能会超出 锁定InnoDB表的表大小。要避免这个问题,或者干脆 为了最小化表保持锁定的时间,以下内容 策略(根本不使用DELETE)可能会有所帮助:
Select the rows not to be deleted into an empty table that has the same structure as the original table: INSERT INTO t_copy SELECT * FROM t WHERE ... ; Use RENAME TABLE to atomically move the original table out of the way and rename the copy to the original name: RENAME TABLE t TO t_old, t_copy TO t; Drop the original table: DROP TABLE t_old;
使用MyISAM改善删除时间的另一种方法是使用DELETE QUICK,然后使用OPTIMIZE TABLE,也可以使用MySQL文档:
如果要从表中删除多行,可能会更快 使用DELETE QUICK后跟OPTIMIZE TABLE。这重建了 索引而不是执行许多索引块合并操作。
此处IvoTops answer进行了优化。我们只是将日期转换回字符串,因此我们不必在外部查询中再次进行转换:
DELETE
FROM `table` main
WHERE main.Timestamp <>
(SELECT DATE_FORMAT(MAX(STR_To_DATE( sub.Timestamp , '%a %b %d %H:%i:%s CST %Y'), '%a %b %d %H:%i:%s CST %Y')
FROM `table` sub
WHERE sub.Retrieving_User = main.Retrieving_User )
AND main.Retrieving_User = 'userID'
答案 2 :(得分:0)
我认为您的性能问题与NOT IN语句有关。
你可能会更好DELETE `table`
FROM `table` main,
(SELECT sub.Retrieving_User, MAX( STR_To_DATE( sub.Timestamp , '%a %b %d %H:%i:%s CST %Y' )) maxTime
WHERE sub.Retrieving_User = 'userID'
GROUP BY sub.Retrieving_User) sub
WHERE STR_To_DATE( main.Timestamp , '%a %b %d %H:%i:%s CST %Y' ) < sub.maxTime
AND main.Retrieving_User = 'userID';