Сохраняйте только последние две строки для сгруппированных столбцов в таблице - PullRequest
1 голос
/ 10 апреля 2019

У меня есть таблица «История» с около 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

Пожалуйста, имейте в виду, что я хочу держать последние две строки в моей таблице, поэтому я ограничиваюсь 22000. Если я нахожу подходящие строки, я помещаю id в массив с именем idList.

Последний шаг

Я удаляю все идентификаторы из массива следующим образом:

DELETE FROM History WHERE id in ($idList)

Похоже, что это не самая лучшая производительность, потому что я должен проверять каждую комбинацию с помощью дополнительного запроса. Есть ли способ иметь один оператор delete, который помогает избежать 40 000 дополнительных запросов?

Редактировать обновление: Я использую AWS Aurora DB

1 Ответ

0 голосов
/ 10 апреля 2019

Если вы используете 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)
);
...