powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / И снова про партиции - почему сканируется пустая таблица родитель?
14 сообщений из 14, страница 1 из 1
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822673
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброе время суток. Имеем PG 9.2 на Gentoo. Скромные 4 ГБ оперативки, из них в shared_buffers = 1900MB. constrain_exclusion = partition.
Есть 2 таблицы, родительские
Код: 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.
CREATE TABLE indexed_result
(
  id bigint NOT NULL DEFAULT nextval('indexed_result__id_seq'::regclass),
  id_article bigint,
  id_spr_object_sin bigint,
  id_spr_object bigint,
  key_in_spr bigint,
  CONSTRAINT pk_indexed_result_ PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
); CREATE TABLE indexed_result_ext
(
  id bigint NOT NULL DEFAULT nextval('indexed_result_ext__id_seq'::regclass),
  pos_start bigint,
  pos_stop bigint,
  par_num bigint,
  phrase_num bigint,
  id_indexed_result bigint,
  id_indexed_words bigint,
  id_article bigint,
  CONSTRAINT pk_indexed_result_ext_ PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);


Триггера на них висят такие
Код: 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.
CREATE OR REPLACE FUNCTION tgf_indexed_result_bef_ins()
  RETURNS trigger AS
$BODY$
declare idx bigint;
declare r text;
BEGIN
  if NEW.id_article is null then idx = 0;
  else idx = NEW.id_article/100000;
  end if;
  --raise notice 'id=%,id_article=%,id_spr_object_sin=%,id_spr_object=%,key_in_spr=%',NEW.id,NEW.id_article,NEW.id_spr_object_sin,NEW.id_spr_object,NEW.key_in_spr;
  r = 'insert into part.indexed_result_'||idx||' (id,id_article,id_spr_object_sin,id_spr_object,key_in_spr) values ('
  ||NEW.id||','||NEW.id_article||','||NEW.id_spr_object_sin||','||NEW.id_spr_object||','||NEW.key_in_spr||');';
  --raise notice '%',r;
  execute r;
  return null;
end;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

CREATE OR REPLACE FUNCTION tgf_indexed_result_ext_bef_ins()
  RETURNS trigger AS
$BODY$
declare idx bigint;
declare r text;
BEGIN
  if NEW.id_article is null then idx = 0;
  else idx = NEW.id_article/100000;
  end if;
  --raise notice 'id=%,par_num=%,phrase_num=%,word=%,id_article=%',NEW.id,NEW.par_num,NEW.phrase_num,NEW.word,NEW.id_article;
  r = 'insert into part.indexed_result_ext_'||idx||' (id_article,pos_start,pos_stop,par_num,phrase_num,id_indexed_result,id_indexed_words,id) values ('
  ||NEW.id_article||','||NEW.pos_start||','||NEW.pos_stop||','||NEW.par_num||','||NEW.phrase_num||','||NEW.id_indexed_result||','||NEW.id_indexed_words||','||NEW.id||');';
  --raise notice '%',r;
  execute r;
  return null;
end;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;



Все работает, данные пишутся (быстро или нет - вопрос отдельный). SELECT COUNT(1) FROM ONLY indexed_result и SELECT COUNT(1) FROM ONLY indexed_result_ext возвращают нули.
Выборка существенно подтормаживает. Причем explain показывает, что партиции используются, однако сканирование родителя все равно идет.
Код: plsql
1.
2.
3.
4.
SELECT ir.id_article, ir.id_spr_object_sin, ir.id_spr_object, 
    ir.key_in_spr, ire.pos_start, ire.pos_stop, ire.par_num, ire.phrase_num, 
    iw.word FROM indexed_result ir, indexed_result_ext ire, indexed_words iw
     WHERE ire.id_article = 1926326 and ir.id_article = 1926326 and ire.id_indexed_result = ir.id AND ire.id_indexed_words = iw.id;



Код: sql
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.
Nested Loop  (cost=3853.48..206077.91 rows=11 width=90)
  Output: ir.id_article, ir.id_spr_object_sin, ir.id_spr_object, ir.key_in_spr, ire.pos_start, ire.pos_stop, ire.par_num, ire.phrase_num, iw.word
  ->  Hash Join  (cost=3853.48..205989.95 rows=11 width=72)
        Output: ir.id_article, ir.id_spr_object_sin, ir.id_spr_object, ir.key_in_spr, ire.pos_start, ire.pos_stop, ire.par_num, ire.phrase_num, ire.id_indexed_words
        Hash Cond: (ire.id_indexed_result = ir.id)
        ->  Append  (cost=0.00..202130.07 rows=1259 width=48)
              ->  Seq Scan on public.indexed_result_ext ire  (cost=0.00..199794.00 rows=1 width=48) --ЗАЧЕМ ВОТ ЭТО ДЕЛАЕТСЯ???
                    Output: ire.pos_start, ire.pos_stop, ire.par_num, ire.phrase_num, ire.id_indexed_result, ire.id_indexed_words
                    Filter: (ire.id_article = 1926326)
              ->  Bitmap Heap Scan on part.indexed_result_ext_19 ire  (cost=26.03..2336.07 rows=1258 width=48)
                    Output: ire.pos_start, ire.pos_stop, ire.par_num, ire.phrase_num, ire.id_indexed_result, ire.id_indexed_words
                    Recheck Cond: (ire.id_article = 1926326)
                    ->  Bitmap Index Scan on idx_indexed_result_ext_19_id_article  (cost=0.00..25.71 rows=1258 width=0)
                          Index Cond: (ire.id_article = 1926326)
        ->  Hash  (cost=3823.09..3823.09 rows=2431 width=40)
              Output: ir.id_article, ir.id_spr_object_sin, ir.id_spr_object, ir.key_in_spr, ir.id
              ->  Append  (cost=0.00..3823.09 rows=2431 width=40)
                    ->  Seq Scan on public.indexed_result ir  (cost=0.00..0.00 rows=1 width=40)
                          Output: ir.id_article, ir.id_spr_object_sin, ir.id_spr_object, ir.key_in_spr, ir.id
                          Filter: (ir.id_article = 1926326)
                    ->  Bitmap Heap Scan on part.indexed_result_19 ir  (cost=47.14..3823.09 rows=2430 width=40)
                          Output: ir.id_article, ir.id_spr_object_sin, ir.id_spr_object, ir.key_in_spr, ir.id
                          Recheck Cond: (ir.id_article = 1926326)
                          ->  Bitmap Index Scan on idx_indexed_result_19_id_article  (cost=0.00..46.53 rows=2430 width=0)
                                Index Cond: (ir.id_article = 1926326)
  ->  Index Scan using pk_indexed_words on public.indexed_words iw  (cost=0.00..7.99 rows=1 width=34)
        Output: iw.id, iw.word
        Index Cond: (iw.id = ire.id_indexed_words)



Вопрос - зачем выполняется "Seq Scan on public.indexed_result_ext ire (cost=0.00..199794.00 rows=1 width=48)", если партицированные таблицы существуют ив ыборки по ним успешно прошли "Bitmap Heap Scan on part.indexed_result_ext_19 ire (cost=26.03..2336.07 rows=1258 width=48)" за время, в 100 раз меньшее?
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822708
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakama,

потому что так устроено
и в родительской таблице тоже могут быть строки
только вы время неверно смотрите... explain показывает ожидаемое время а не реальное
реальное - explain analyze только
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822712
/\/\/\/\/\/\
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
kamakama...
Вопрос - зачем выполняется "Seq Scan on public.indexed_result_ext ire (cost=0.00..199794.00 rows=1 width=48)", если партицированные таблицы существуют ив ыборки по ним успешно прошли "Bitmap Heap Scan on part.indexed_result_ext_19 ire (cost=26.03..2336.07 rows=1258 width=48)" за время, в 100 раз меньшее?

Как зачем? Там нашлась как минимум одна строка, удовлетворяющая результату. Это на дочерние таблицы есть четкие ограничения на таблицу, а в родительской может быть все что угодно. То что это "все что угодно" распихивается триггером по дочерним - это частный случай здесь и сейчас, то есть далеко не правило, на которое можно надежно опираться.
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822724
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim Boguk,

Специально для обеих таблиц сделал VACCUM и ANALYZE. После чего сделал рельный запрос. Помогло, статистика была старой. Но эффективность такой организации партицирования вызывает большие сомнения. Возможно, что наследуемые таблицы - это просто притянуто за уши и невозможно конкретно указать, что это - партиция и не нужно шарится в родителе.

Тему можно закрывать
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822815
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Хотя сейчас по мере работы возник еще один вопрос. Вот есть схема с партициями, и для id родителя указан "id bigint NOT NULL DEFAULT nextval('indexed_result__id_seq'::regclass)". И теперь выполняем insert в родитля, причем хотим, чтоб он вернул id
(типа insert into indexed_result ... returning id into id_indexed_result). Но в таблице нет записей и стало быть, вернется null (что и происходит в реальности).

Отдельный сиквенс для Id каждой партиции дать нельзя (наследование же), так как же заставить эту конструкцию работать?
Или никак и присвоение id руками делать?
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822821
Фотография Misha Tyurin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakama,

можно в триггере партицирования возвращать new только с id, остальное занулять. тогда в родителе будут жить только айдишки и ретурнинг будет работать.

но тогда скорее всего надо будет переделать доступ к партициям, на вариант, когда явно партиция с клиента выбирается.
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822829
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakama,

Вы описали основные "бяки" в работе с партиционированием в PostgreSQL. Да, это способ выкрутиться при отсутствии полноценной поддержки. И да, он далек от идеала.

Для последовательностей -- да, нужно присваивать ID явно.
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822839
Alexius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakama,

я когда-то для returning писал ужасный костыль в виде нескольких триггеров.

в before insert триггере делалась вставка в партиции и возвращался new. в after insert эта запись удалялась из родительской таблицы. по-другому вроде бы сделать тогда нельзя было. не знаю, изменилось ли сейчас что-то.


shared_buffers = 1900MB может быть не совсем оптимальное значение если на сервере только база.
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822843
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Понятно, спасибо. Но решать таким образом проблемы - костылеобразно:(
Ведь главный козырь партиции - то, что ее можно внедрить прозрачно по отношении к остальному коду, типа клиент этого и не заметит. А тут, если обращение к таблицам не изолировано процедурами, прозрачностью и не пахнет
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822851
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexius,

почему неправильно? Только база. Просто объемы данных у нас таковы, что все активно используемые таблицы и индексы (даже после партиций) влезают в 2,5 ГБ + 400M запас. Объем разделяемой памяти выделели системщики в 3 гига, метров 200 под остальными приложениям
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38822871
кактотак
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexiuskamakama,

я когда-то для returning писал ужасный костыль в виде нескольких триггеров.

в before insert триггере делалась вставка в партиции и возвращался new. в after insert эта запись удалялась из родительской таблицы. по-другому вроде бы сделать тогда нельзя было.да, это работает.
можно всю вставку в партиции перенести в after. С соответсвующим DELETE из ONLY корня. тогда returning тоже будет работать.

интересный теор вопрос -- пухнет ли предок на незавершённых вставках.


[Тут интересен еще случай с мигрирующим UDATE, который превращается delete + INSERT, но не с точки зрения returning, а с т.з. генерации событий для, скажем, триггерной передачи их в другую бд]. -- многовато событий по итогу получается (update -- поскольку в немигрирующем случае передаем его, delete -- поскольку таки удалили, и (re) insert -- поскольку таки вставили. А если мишень партицирована иначе -- то главное не ошибнуться с порядком событий - с ONLY и явным адресом там не очевидно).
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38823072
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakamaПонятно, спасибо. Но решать таким образом проблемы - костылеобразно:(
Ведь главный козырь партиции - то, что ее можно внедрить прозрачно по отношении к остальному коду, типа клиент этого и не заметит. А тут, если обращение к таблицам не изолировано процедурами, прозрачностью и не пахнет

единтвенное что ломается это returning так что не так плохо
а запросы на партиционированную таблицу всеравно переделывать зачастую приходится (так как надо явным образом условия выбора партиции добавлять в запрос)

PS: осмысленность вашей схемы партиционирования (критерий выделения партиций) - под большим вопросом, т.е. может быть в вашей конкретной ситуации это и правильно но вообще почти всегд партиционирование по чему то кроме даты оказывается лишним. Да и размеры партици какие то неудачные (если в партициях меньше миллиона а лучше 10M строк - они обычно не актуальны).

PPS: больше 100 партиций делать не стоит в базе они линейным поиском выбираются

PPPS: обращение к пусто родительской таблице - штука почти бесплатная.
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38824102
Alexius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kamakamaAlexius,

почему неправильно? Только база. Просто объемы данных у нас таковы, что все активно используемые таблицы и индексы (даже после партиций) влезают в 2,5 ГБ + 400M запас. Объем разделяемой памяти выделели системщики в 3 гига, метров 200 под остальными приложениям

обычно рекомендуется выставлять shared buffers в ~25%/~75% от размера доступной памяти постгресу (- память на коннекты) чтобы уменьшить эффект от двойного кэширования.

раз все, что нужно в 2.5ГБ влезает, может быть стоит поднять размер поближе к этому значению, хотя разницы возможно большой и не будет.
...
Рейтинг: 0 / 0
И снова про партиции - почему сканируется пустая таблица родитель?
    #38825422
kamakama
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alexius,

У нас есть мастер-таблица,которая генерирует ключи, служащие основанием для партиции. Сейчас там 2М записей и ее бить не нужно (пока). Но эти ключи используются в качестве вторичных для других объектов, которых существенно больше (примерно в 10-12 раз). И уже эти таблицы получаются примерно по 1-1.2М строк. Собственно, для ускорения рабты именно с вторичными объектами, а не с первичными и затевалась эта схема. Да, есть минус, что при обращении нужно использовать всегда мастер ключ, но у нас это 95% запросов. А на 5% найдем кастомное решение
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / И снова про партиции - почему сканируется пустая таблица родитель?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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