Задание Cron для удаления логически избыточных записей в Postgres SQL - PullRequest
1 голос
/ 14 июня 2019

У меня есть требование удалить записи из таблицы Postgres SQL, в которой более 200 миллионов записей.Таблица не имеет первичного ключа.

Пример содержимого таблицы (закладка - это имя таблицы) выглядит следующим образом:

systemId     filename           mindatetime                 maxdatetime
  70277     monitor_1.dat   2019-04-21 08:00:00 AM      2019-04-21 03:10:00 PM
  10006     monitor_2.dat   2019-04-25 10:00:00 AM      2019-04-25 11:30:00 AM
  10006     monitor_3.dat   2019-04-28 08:00:00 AM      2019-04-28 10:00:00 AM
  10006     monitor_3.dat   2019-04-28 09:00:00 AM      2019-04-28 11:00:00 AM
  10006     monitor_3.dat   2019-04-28 07:00:00 AM      2019-04-28 04:00:00 PM
  8368      monitor_1.dat   2019-05-21 11:00:00 AM      2019-05-21 11:30:00 AM
  8368      monitor_7.dat   2019-05-21 06:00:00 AM      2019-05-21 11:00:00 AM
  8368      monitor_5.dat   2019-05-23 08:00:00 AM      2019-05-23 10:00:00 AM
  72777     monitor_4.dat   2019-04-28 09:00:00 AM      2019-04-29 11:00:00 AM
  72777     monitor_4.dat   2019-04-28 11:00:00 AM      2019-04-29 18:00:00 PM
  72777     monitor_4.dat   2019-04-28 09:30:00 AM      2019-04-29 23:00:00 PM
  12345     monitor_5.dat   2019-04-28 07:00:00 AM      2019-04-28 10:00:00 AM
  12345     monitor_5.dat   2019-04-28 02:00:00 PM      2019-04-28 06:00:00 PM
  12345     monitor_5.dat   2019-04-28 09:00:00 AM      2019-04-28 03:00:00 PM
  10006     monitor_8.dat   2019-04-28 09:00:00 AM      2019-04-29 09:00:00 AM
  10006     monitor_8.dat   2019-04-29 09:01:00 AM      2019-04-30 10:00:00 AM
  10006     monitor_8.dat   2019-04-30 10:01:00 AM      2019-04-30 11:00:00 AM
  10006     monitor_8.dat   2019-05-12 07:00:10.001 AM  2019-05-13 10:00:10.000 AM
  10006     monitor_8.dat   2019-05-15 09:30:10.001 AM  2019-05-18 11:30:10.000 AM

Задание cron должно выполняться по заданному расписанию, чтобыудалите записи, которые являются логически избыточными.

Чтобы объяснить это, давайте возьмем случай systemId '10006', где имя файла - 'monitor_3.dat', имеющее 3 записи с минимальной и максимальной датой времени того же дня.

Логически мы можем удалить записи, имеющие mindatetime 08:00:00 AM и 09:00:00 AM, maxdatetime 10:00:00 AM, 11:00:00 AM, поскольку этот интервал покрывается другой записьюу которого есть время просмотра как 7 часов утра и максимальное время как 4 часа дня.

Таким образом, эти записи попадают под этот интервал, и задание должно идентифицировать такие записи во всей таблице и удалять их.

В этом случае содержимое моей выходной таблицы должно быть:

 systemId    filename           mindatetime                 maxdatetime
  70277     monitor_1.dat   2019-04-21 08:00:00 AM      2019-04-21 03:10:00 PM
  10006     monitor_2.dat   2019-04-25 10:00:00 AM      2019-04-25 11:30:00 AM
  10006     monitor_3.dat   2019-04-28 07:00:00 AM      2019-04-28 04:00:00 PM
  8368      monitor_1.dat   2019-05-21 11:00:00 AM      2019-05-21 11:30:00 AM
  8368      monitor_7.dat   2019-05-21 06:00:00 AM      2019-05-21 11:00:00 AM
  8368      monitor_5.dat   2019-05-23 08:00:00 AM      2019-05-23 10:00:00 AM
  72777     monitor_4.dat   2019-04-28 09:00:00 AM      2019-04-29 23:00:00 PM
  12345     monitor_5.dat   2019-04-28 07:00:00 AM      2019-04-28 06:00:00 PM
  10006     monitor_8.dat   2019-04-28 09:00:00 AM      2019-04-30 11:00:00 AM
  10006     monitor_8.dat   2019-05-12 07:00:10.001 AM  2019-05-13 10:00:10.000 AM
  10006     monitor_8.dat   2019-05-15 09:30:10.001 AM  2019-05-18 11:30:10.000 AM

Размер таблицы превышает 20 ГБ на диске, поэтому я изучал написание процедуры или задания sql для достижения этой цели, но не смог добиться значительного прогресса.Есть идеи или предложения по преодолению этого сложного сценария?

1 Ответ

0 голосов
/ 14 июня 2019

Вы можете использовать tsranges для поиска совпадений. Запрос был бы немного проще, если бы существовал уникальный ключ, и вы можете столкнуться с проблемами, если есть повторяющиеся строки, но вот основная идея:

-- The rows to be deleted:

select * from bookmark WHERE exists
(select 1 from bookmark bm2
  WHERE bm2.systemid = bookmark.systemid
   AND  bm2.filename = bookmark.filename
   AND  (bookmark.systemid, bookmark.filename, bookmark.mindatetime, bookmark.maxdatetime) IS DISTINCT FROM (bm2.systemid, bm2.filename, bm2.mindatetime, bm2.maxdatetime)
   AND tsrange(bookmark.mindatetime, bookmark.maxdatetime, '[]') <@ tsrange(bm2.mindatetime, bm2.maxdatetime, '[]')
);
 systemid |   filename    |     mindatetime     |     maxdatetime
----------+---------------+---------------------+---------------------
    10006 | monitor_3.dat | 2019-04-28 08:00:00 | 2019-04-28 10:00:00
    10006 | monitor_3.dat | 2019-04-28 09:00:00 | 2019-04-28 11:00:00
    72777 | monitor_4.dat | 2019-04-28 11:00:00 | 2019-04-29 18:00:00


-- Delete them like so:

delete from bookmark WHERE exists
(select 1 from bookmark bm2
  WHERE bm2.systemid = bookmark.systemid
   AND  bm2.filename = bookmark.filename
   AND  (bookmark.systemid, bookmark.filename, bookmark.mindatetime, bookmark.maxdatetime) IS DISTINCT FROM (bm2.systemid, bm2.filename, bm2.mindatetime, bm2.maxdatetime)
   AND tsrange(bookmark.mindatetime, bookmark.maxdatetime, '[]') <@ tsrange(bm2.mindatetime, bm2.maxdatetime, '[]')
);

Обратите внимание, что это не совсем соответствует ожидаемому результату из-за опечатки в ваших данных. Эти две строки не перекрываются:

72777 | monitor_4.dat | 2019-04-28 09:00:00 | 2019-04-29 11:00:00
72777 | monitor_4.dat | 2019-04-28 09:30:00 | 2019-04-29 23:00:00

Если вы действительно не хотите обновить и удалить? В этом случае вам лучше всего создать новую таблицу и переименовать ее:

CREATE TABLE bookmark_load AS 
  SELECT systemid, filename, min(mindatetime), max(maxdatetime)
  FROM bookmark
  GROUP BY systemid, filename;

ALTER TABLE bookmark RENAME TO bookmark_old;
ALTER TABLE bookmark_load RENAME TO bookmark;

Конечно, вы не можете вставлять новые данные в закладки при этом.

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