Гость
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Блокировки при вставке в таблицу / 12 сообщений из 12, страница 1 из 1
02.12.2018, 16:37
    #39741707
bff7755a
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
Есть задача пересоздать таблицу с 1 млрд строк с минимальным простоем. Я придумал навесить на старую таблицу триггер, который будет обновлять или добавлять данные в новой таблице при изменении данных в старой и после этого пакетно копировать данные из старой таблицы в новую. В таблице есть индексированное поле created_at (дата вставки записи) и я решил использовать его для разбиения строк на пакеты и копировать данные по одному дню. Для того, чтобы процесс можно было распараллелить я создал табличку, в которую записывается дата, данные за которую сейчас переносятся. На момент вставки в эту таблицу берётся advisory lock и освобождается сразу же после вставки. Заодно логируется некоторая элементарная статистика. Процедура выглядит следующим образом:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
create or replace
function public.packages_catchup() returns integer as $$
declare
    vResult integer; vCurrentDate date;
    vAdvisoryLockID integer := 1984;
    vMinDate date := '2017-07-18'; /* select min(created_at) from packages; */
begin
    /* In order to hold lock as less as possible we
       use advisory locks instead of common locks, because
       command locks are always held until end of transaction */
    perform pg_advisory_lock(vAdvisoryLockID);

    select coalesce(max(day) + interval '1 day', vMinDate)
      from public.package_catchup_log
      into vCurrentDate;

    insert into public.package_catchup_log (day)
    values (vCurrentDate);

    perform pg_advisory_unlock(vAdvisoryLockID);

    insert into public.packages_new
    select * from public.packages p
    where created_at >= vCurrentDate and
          created_at < vCurrentDate + interval '1 day' and
          not exists (
            select *
              from public.packages_new pn
             where pn.id = p.id and
                   created_at >= vCurrentDate and
                   created_at < vCurrentDate + interval '1 day'
          );

    get diagnostics vResult := ROW_COUNT;

    raise warning 'public.packages_catchup(): % rows have been moved', vResult;

    update public.package_catchup_log
       set rows_count = vResult,
           dt_end = clock_timestamp()
     where day = vCurrentDate;

    return vResult;
end;
$$ language plpgsql;



Проблема в том, что если запустить процедуру в двух параллельных транзакциях, одна из транзакций начинает висеть в ожидании, пока не закончится первая. И судя по pg_locks проблема не в advisory locks. Я не понимаю, откуда вообще берётся блокировка при вставке. Может, знающие умы что-нибудь дельное посоветуют? Где и что я упустил?
...
Рейтинг: 0 / 0
02.12.2018, 16:49
    #39741711
bff7755a
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
Судя по логам, блокировка возникает при вставке в индекс, навешенный на новую таблицу.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
(42498) 2018-12-02 13:45:07 UTC [15447] STATEMENT:  /*NO LOAD BALANCE*/ SELECT now(), public.packages_catchup();
(42496) 2018-12-02 13:45:07 UTC [15446] LOG:  duration: 109388.232 ms  statement: /*NO LOAD BALANCE*/ SELECT now(), public.packages_catchup();
(48792) 2018-12-02 13:45:33 UTC [16494] LOG:  process 16494 still waiting for ShareLock on transaction 996384294 after 1000.083 ms
(48792) 2018-12-02 13:45:33 UTC [16494] DETAIL:  Process holding the lock: 16493. Wait queue: 16494.
(48792) 2018-12-02 13:45:33 UTC [16494] CONTEXT:  while inserting index tuple (5860744,4) in relation "packages_new_pkey"
	SQL statement "insert into public.packages_new
	    select * from public.packages p
	    where created_at >= vCurrentDate and
	          created_at < vCurrentDate + interval '1 day' and
	          not exists (
	            select *
	              from public.packages_new pn
	             where pn.id = p.id and
	                   created_at >= vCurrentDate and
	                   created_at < vCurrentDate + interval '1 day'
	          )"
	PL/pgSQL function packages_catchup() line 21 at SQL statement
...
Рейтинг: 0 / 0
02.12.2018, 17:07
    #39741714
Melkij
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
bff7755aЕсть задача пересоздать таблицу с 1 млрд строк с минимальным простоем.
А какая задача изначальная? Может, банальный pg_repack?

bff7755aЯ не понимаю, откуда вообще берётся блокировка при вставке
Уникальные индексы есть?
...
Рейтинг: 0 / 0
02.12.2018, 17:16
    #39741716
bff7755a
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
MelkijА какая задача изначальная? Может, банальный pg_repack?

Изначально вакуум работает по таблице очень долго (больше недели), было установлено, что в версиях 9.5.* до 9.5.15 есть баг, когда вакуум работает бесконечно если на таблице есть битые индексы, но обновление до 9.5.15 не помогло, поэтому решили перенести таблицу, так как xid не бесконечный и до wraparound осталось около 1 млрд транзакций.

bff7755aЯ не понимаю, откуда вообще берётся блокировка при вставке
Уникальные индексы есть?[/quot]
Есть, PK по id. Это поле типа uuid (к сожалению).
...
Рейтинг: 0 / 0
02.12.2018, 17:42
    #39741721
Melkij
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
bff7755a,

ну вот pg_repack и воспользуйтесь.
...
Рейтинг: 0 / 0
02.12.2018, 17:46
    #39741723
bff7755a
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
Melkijbff7755a,ну вот pg_repack и воспользуйтесь.
У меня есть подозрения, что с таблицей (или индексами на ней) что-то не то. Стороннее расширение тоже не факт что с этим справится, поэтому выбрали гарантированный вариант. А вопрос всё-таки был про блокировки.
...
Рейтинг: 0 / 0
02.12.2018, 17:50
    #39741724
bff7755a
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
И, кстати, pg_repack замораживает строки? Иначе в моём случае он будет бесполезен.
...
Рейтинг: 0 / 0
02.12.2018, 18:07
    #39741729
bff7755a
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
bff7755aИ, кстати, pg_repack замораживает строки? Иначе в моём случае он будет бесполезен.
Прочитал документацию. Он пересоздаёт таблицу на самом деле, так что всё OK. Можно попробовать.
...
Рейтинг: 0 / 0
02.12.2018, 18:19
    #39741733
Melkij
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
bff7755a,

pg_repack делает копию таблицы через insert select, строит индексы, нагоняет diff который записал триггером, затем подменяет relfilenode и прочие зависимости, relfrozenxid тоже обновляет. Потому что все данные были скопированы только что.
И это сильно быстрее и надёжнее, чем вы сейчас будете отлаживать в спехе аналогичный велосипед.

bff7755aА вопрос всё-таки был про блокировки.
Так на уникальных индексах и стоите вероятно. Где-нибудь из package_catchup_log
...
Рейтинг: 0 / 0
02.12.2018, 18:30
    #39741735
bff7755a
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
Melkij, есть только одна проблема. Уже работает prevent wraparound vacuum. А с ним у pg_repack похоже бывают некотрые конфликты ( https://github.com/reorg/pg_repack/issues/148).
...
Рейтинг: 0 / 0
02.12.2018, 19:01
    #39741736
Melkij
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
bff7755a,

create index concurrently pg_repack делает если запросили пересборку только индексов --only-indexes
В этом случае логика работы в принципе по другому пути идёт и сама таблица никак не затрагивается.
...
Рейтинг: 0 / 0
10.12.2018, 09:55
    #39745133
bff7755a
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Блокировки при вставке в таблицу
Melkij, спасибо за совет. pg_repack мне помог. Отработал на базе с 3000 TPS, блокировки были только в начале и в самом конце, когда он переключал таблицы.
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Блокировки при вставке в таблицу / 12 сообщений из 12, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]