【问题标题】:Keep only last two rows for grouped columns in table仅保留表中分组列的最后两行
【发布时间】:2019-04-10 06:12:03
【问题描述】:

我有一个包含大约 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】:

    如果您使用的是 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)
    );
    

    【讨论】:

    • 不幸的是,我们在这里使用 AWS Aurora...所以不可能在那里使用 CTE
    • @Marco 然后尝试直接在删除查询中内联 CTE。
    • 不允许在同一张表的子查询中执行 DELETE,例如 DELETE FROM History WHERE id in (SELECT id from History WHERE ...)
    • @Marco 是的,如果您将子查询包装在另一个子查询中,就像我在上面所做的那样。如果您确实收到错误消息,请将其粘贴到此处,我可以尝试编辑我的答案。
    • 我收到以下错误:SQL Fehler (1064): You have an error in your SQL syntax;检查与您的 MySQL 服务器版本相对应的手册,以在第 7 行的 '(PARTITION BY refSchema, refId ORDER BY importAt DESC) rn FROM Histor' 附近使用正确的语法
    猜你喜欢
    • 2017-10-23
    • 2019-07-03
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    • 1970-01-01
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多