我有一个约30万行的“历史”表,每天都有新数据填充。我只想保留每个refSchema / refId组合的最后两行。
实际上我是这样的:
第一步:
SELECT refSchema,refId FROM History GROUP BY refSchema,refId
通过此语句,我得到了所有组合(大约40.000)。
第二步:
我运行一个foreach,以查找上面查询的现有行,如下所示:
SELECT id
FROM History
WHERE refSchema = ? AND refId = ? AND state = 'done'
ORDER BY importedAt
DESC LIMIT 2,2000
请记住,我要保留表中的最后两行,因此我限制为22000。如果找到匹配的行,则将 id 放入名为idList的数组中。
最终步骤
我以这种方式删除数组中的所有ID:
DELETE FROM History WHERE id in ($idList)
这似乎并不是最好的性能,因为我必须检查每个组合并附加查询。有没有办法让一个delete语句神奇地避免40.000个额外的查询?
编辑更新:我使用AWS Aurora DB
答案 0 :(得分:0)
如果您使用的是MySQL 8+,则从概念上讲,此处进行的一种简单方法是使用CTE标识要保留的每个组的前两行。然后,删除其架构/标识对不是出现在此白名单中的所有记录:
WITH cte AS (
SELECT refSchema, refId
FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY refSchema, refId ORDER BY importedAt DESC) rn
FROM History
) t
WHERE rn IN (1, 2)
)
DELETE
FROM History
WHERE (refSchema, refId) NOT IN (SELECT refSchema, refId FROM cte);
如果您不能使用CTE,请尝试内联以上CTE:
DELETE
FROM History
WHERE (refSchema, refId) NOT IN (
SELECT refSchema, refId
FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY refSchema, refId ORDER BY importedAt DESC) rn
FROM History
) t
WHERE rn IN (1, 2)
);