对表中的分组列仅保留最后两行

问题描述 投票:1回答:1

我有一个表“历史”,大约300.000行,每天都有新的数据。我想只保留每个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

请记住,我想在表格中保留最后两行,所以我限制2,2000。如果我找到匹配的行,我将id放在一个名为idList的数组中。

最后一步

我以这种方式删除数组中的所有id:

DELETE FROM History WHERE id in ($idList)

这一切似乎都不是最好的表现,因为我必须用额外的查询来检查每个组合。有没有办法让一个删除语句能够避免额外的40.000额外查询?

编辑更新:我使用AWS Aurora DB

mysql group-by sql-delete sqlperformance
1个回答
0
投票

如果您使用的是MySQL 8+,那么在此处继续使用一种概念上简单的方法是使用CTE来识别您希望保留的每组前两行。然后,删除其架构/ ID对未出现在此白名单中的任何记录:

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)
);
© www.soinside.com 2019 - 2024. All rights reserved.