mysql удалить строки, ограниченные группой - PullRequest
0 голосов
/ 18 октября 2019

У меня большая таблица сообщений со столбцами date и room. и 2 миллиарда строк.

Теперь я хочу сохранить только последние 50 сообщений для каждой комнаты и удалить предыдущие сообщения.

Могу ли я сделать это с помощью быстрого запроса?

этот вопрос уникален, я не нашел другого вопроса для удаления строк по сгруппированному и упорядоченному выбору

Ответы [ 2 ]

0 голосов
/ 18 октября 2019

Вы можете использовать функцию Rank (), чтобы получить 50 лучших результатов для каждой группы, упорядоченной по дате desc, поэтому последние записи будут в топе.
http://www.mysqltutorial.org/mysql-window-functions/mysql-rank-function/
Затем вы оставили присоединиться к этому подзапросу. на вашей таблице по идентификатору (или по комнате и дате, если они уникальны и у вас нет идентификатора в таблице) Последний шаг - отфильтровать все такие результаты, которые имеют нулевое значение в подзапросе, и удалить их.
Полныйкод будет выглядеть примерно так:

DELETE T FROM YOURTABLE T
LEFT JOIN (
    SELECT  *,
        RANK() OVER (PARTITION BY
                     ROOM
                 ORDER BY
                     [DATE] DESC
                ) DATE_RANK
                ) AS T2
ON T.[DATE] = T2.[DATE]
AND T.ROOM = T2.ROOM
AND T2.DATE_RANK<=50
WHERE T2.DATE IS NULL

0 голосов
/ 18 октября 2019

Вы не можете сделать это в быстром запросе. У вас много данных.

Я бы предложил создать новую таблицу. Затем вы можете при необходимости заменить данные в первой таблице.

Возможно, наиболее эффективный способ получить 50 строк - при условии, что date уникален для каждой room:

select t.*
from t
where t.date >= coalesce((select t2.date
                          from t t2
                          where t2.room = t.room
                          order by t2.date desc
                          limit 1
                         ), t.date
                        );

Для этого, чтобы иметь какую-то надежду на производительность, вам нужен индекс для (room, date).

Вы также можете попробовать row_number() в MySQL 8 +:

select . . .   -- list the columns
from (select t.*, row_number() over (partition by room order by date desc) as seqnum
      from t
     ) t
where seqnum <= 50;

Тогда выможно заменить данные, выполнив:

create table temp_t as 
    select . . .   -- one of the select queries here;

truncate table t;  -- this gets rid of all the data, so be careful

insert into t
   select *
   from temp_t;

Массивные вставки намного более эффективны, чем массовые обновления, поскольку старые данные не нужно регистрировать (ни заблокированные страницы, ни другие вещи). ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...