|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
Доброго дня, коллеги. Возникла непонятная (и неприятная) ситуация с использованием индексированной временной таблицы. Такое ощущение, что Postgres не учитывает в статистике то, что во временной таблице столбец проиндексирован. Версия Postgres 10.3 Описание проблемы: Есть временная таблица с одним столбцом и индексом по нему. Она пустая (это важно): Код: sql 1. 2. 3. 4.
После её создания выполнено Код: sql 1.
План выполнения запроса (сформированный прямо в ХП) показывает 60 сек. Если использовать такую же таблицу, но не временную, то план запроса показвает 0.103 ms Запрос всегда возвращает 0 записей (так и должно быть). Сам запрос: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.
План запроса для случая временной таблицы: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.
План запроса для случая обычной таблицы: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20.
Правильно ли я понимаю, что суть проблемы в том, что екзекутор не видит индекса во временной таблице? Если да, то как ему явно на него указать? ... |
|||
:
Нравится:
Не нравится:
|
|||
01.05.2018, 16:48 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
Ещё в дополнение: И получение плана запроса и открытие курсора по запросу выполняется с использованием "execute" (open <CURSOR> no scroll for execute). Есть предположение, что у хранимой процедуры и запросов выполняемых в ней через "execute" разные планнеры, и планнер для "execute" не видит, что временная таблица содержит индекс и проанализирована. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.05.2018, 21:38 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
sKotПлан запроса для случая временной таблицы: Код: sql 1.
План запроса для случая обычной таблицы: Код: sql 1.
Если только вы не перепутали местами результаты explain - то индекс планировщик как раз использует там где он оказывается не нужен, а очень сильно дешевле сначала пройти seqscan'ом по tmp_deps_id и определить, что там нифига нет и не выполнять остальной запрос вообще. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.05.2018, 22:16 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
sKotЕсть временная таблица с одним столбцом и индексом по нему. Она пустая (это важно): Вот именно что важно, см. https://www.postgresql.org/docs/current/static/sql-analyze.html (в конце): "If the table being analyzed is completely empty, ANALYZE will not record new statistics for that table. Any existing statistics will be retained." ... |
|||
:
Нравится:
Не нравится:
|
|||
01.05.2018, 22:25 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
Melkij, спасибо за ответ. Местами не перепутал. В случае с временной таблицей видно, что планировщик сначала начинает джойнить таблицы в которых по нескольку миллионов записей, а потом Nested Loop'ом приделывает к результирующему множеству пустую временную таблицу. В данном примере и временная и постоянная таблицы tmp_deps_id пусты. При этом, в случае постоянной таблицы планировщик идёт от неё, а в случае временной - от других таблиц. ... |
|||
:
Нравится:
Не нравится:
|
|||
03.05.2018, 00:43 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
PgSQLanonymous3, спасибо, похоже то что надо. Но вот вопрос: как указазать планировщику, что таблица пуста, и пусть он идёт от неё? ... |
|||
:
Нравится:
Не нравится:
|
|||
03.05.2018, 00:45 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
sKotPgSQLanonymous3, спасибо, похоже то что надо. Но вот вопрос: как указазать планировщику, что таблица пуста, и пусть он идёт от неё? Можно, например, указать, что в ней 1 row (планировщик всё равно никогда не делает "нулевых" оценок): Код: sql 1. 2. 3.
... |
|||
:
Нравится:
Не нравится:
|
|||
03.05.2018, 01:16 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
sKot, судя по исходникам получается, что если таблица пустая (relpages = 0), то планировщик оценивает что в ней 10 страниц и число строк из расчета того, что эти все страницы заняты записями средней ширины (2260 строк в данном случае). если поле id в пустой таблице предполагается что будет уникальным, можно еще попробовать уникальный индекс создать вместо обычного. но не факт что этого будет достаточно, чтобы выбрать оптимальный план. ... |
|||
:
Нравится:
Не нравится:
|
|||
03.05.2018, 09:38 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
AlexiussKot, судя по исходникам получается, что если таблица пустая (relpages = 0), то планировщик оценивает что в ней 10 страниц и число строк из расчета того, что эти все страницы заняты записями средней ширины (2260 строк в данном случае). если поле id в пустой таблице предполагается что будет уникальным, можно еще попробовать уникальный индекс создать вместо обычного. но не факт что этого будет достаточно, чтобы выбрать оптимальный план. ну разве ж он не душка ? кто помнит, где он ещё с потолка берёт предположения ? что, насчет CTE или any (ARRAY(select ...))). не говоря о предположениях об отсутствии корелляции, при наличии у него под носом именно что специального составного инд-а. ну и т.п. ... |
|||
:
Нравится:
Не нравится:
|
|||
03.05.2018, 09:58 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
qwwq, это похоже на баг: https://github.com/postgres/postgres/blob/master/src/backend/optimizer/util/plancat.c#L957 там дальше идет проверка Код: plaintext 1. 2. 3. 4. 5. 6. 7.
но она не срабатывает т.к. строкой ранее 10 страниц в curpages записали. попробую в pgsql-bugs написать. я думаю такая магия в планировщике еще много где есть( ... |
|||
:
Нравится:
Не нравится:
|
|||
03.05.2018, 11:06 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
Alexius, спасибо. Уникальный индекс не получится, т.к. могут быть дубли. Это в конкретном случае она пустая, а во общем случае в ней может быть несколько тысяч записей. Но, если в ней записи есть, то запрос не тормозит, и быстро выбирает 50 первых записей. Насколько я понял, если таблица пустая, то планировщик всегда будет считать, что в ней 10 страниц? ... |
|||
:
Нравится:
Не нравится:
|
|||
04.05.2018, 00:36 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
PgSQLanonymous3, интересное предложение. Попробую сделать так, может поможет. Но, т.к. задача была срочная, то я её решил по-другому: сначала сделал select exists на наличие привязанных к департаментам договоров, и, если их нет, то я просто не выполняю запрос Код: plsql 1. 2. 3. 4. 5. 6. 7.
Результирующий запрос генерируется автоматически, так что это можно. Несколько костыльно, конечно... ... |
|||
:
Нравится:
Не нравится:
|
|||
04.05.2018, 00:47 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
qwwq, тоже спасибо :) СТЕ не пробовал, исходя из того, что, насколько я понимаю, СТЕ сделано для того, чтобы не джойнить запрос внутри from'а, или использовать этот запрос несколько раз. А вот насчёт (ARRAY(select ...)) не очень понял, т.е. не знаком с этим. Составных индексов нет, но все столбцы, используемые в запросе проиндексированы (btree) ... |
|||
:
Нравится:
Не нравится:
|
|||
04.05.2018, 00:52 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
PgSQLanonymous3, поробовал Код: sql 1. 2. 3.
Не помогло. Сделал Код: sql 1. 2. 3. 4. 5. 6. 7. 8.
работает за ~2 сек на таблице CONTRACT ~6млн записей и таблице TMP_DEPS_ID (0 - 2000) записей. удовлетворился результатом. Сделано, конечно сложно, т.к. потом на основании этого select exists принимается решение о добавлении в запрос конструкции вида Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.
, но работает довольно эффективно, запросы выполняются от 1 до 5 сек (на разных наборах данных). Всем спасибо, вопрос можно считать закрытым (за исключением того, что я так и не понял из-за чего была проблема с запросом повременной таблице, но это, скорее, к доктору) ... |
|||
:
Нравится:
Не нравится:
|
|||
04.05.2018, 03:43 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
sKotНасколько я понял, если таблица пустая, то планировщик всегда будет считать, что в ней 10 страниц? строго говоря: если таблица занимает на диске меньше 10 страниц, relpages = 0 (обновляется autovacuum/autoanalyze) и у нее нет отнаследованных таблиц - то считаем что она занимает 10 страниц. господа разработчики пишут, что это не баг и так и было задумано: Andrew GierthAs the large comment immediately above explains, it is indeed intended behavior. The reason is that over-estimating usually doesn't cause too much harm, but under-estimating tends to blow things up in certain critical cases (such as causing foreign-key checks to do sequential scans on tables during a data-loading transaction). It's actually still possible to trigger those kinds of pathological cases, but in between the estimation hacks and the plan cache, you have to work a lot harder at it. Consider for example: create table tree (id integer primary key, parent_id integer references tree); insert into tree values (1, null); vacuum analyze tree; -- now relpages=1 reltuples=1 begin; insert into tree select i, i-1 from generate_series(2,10) i; insert into tree select i, i-1 from generate_series(11,100000) i; commit; That last insert could take maybe half an hour to run, because the FK check has a query plan - established as a generic plan since the middle insert ran it more than 5 times - with the small table size leading to a sequential scan. Without the vacuum analyze that I stuck in there, the code in plancat.c avoids this problem by treating the table as large enough to require an indexscan from the start. As the comment says, this does mean we don't handle the case when the table really is empty and stays empty. But this should be very rare compared to the case where the table starts out empty but then has rows added. sKotPgSQLanonymous3, поробовал Код: sql 1. 2. 3.
Не помогло. странно, по идее должно было помочь. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.05.2018, 13:14 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
Alexius, я немного упростил сам запрос, теперь он такой: Код: sql 1. 2. 3. 4. 5. 6. 7. 8.
Он отрабатывает в пределах 3-4 сек и в случае вставки строки (INSERT INTO TMP_DEPS_ID VALUES(0);) и без неё. Я выполнил запрос раз 10, результат плавает в пределах (3,4) и я так и не понял помогает этот insert или нет. Очевидно, в новом запросе планнер использует индекс. PS: <ОсновнаяТаблица> может быть разной, но это не сильно сказывается на результате. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.05.2018, 13:28 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
AlexiussKotНасколько я понял, если таблица пустая, то планировщик всегда будет считать, что в ней 10 страниц? строго говоря: если таблица занимает на диске меньше 10 страниц, relpages = 0 (обновляется autovacuum/autoanalyze) и у нее нет отнаследованных таблиц - то считаем что она занимает 10 страниц. господа разработчики пишут, что это не баг и так и было задумано: я правильно понимаю, что для "ванилы" мало, что не комитят нормально, но как я где-то наткнулся, ещо и вычищают старые наработки (где-то не то в пп, не то в блогах их). пропал калабуховский дом то-то планировщик -- как дурень деревенский, чем дальше, тем страньше а где энтот эндрю трудоустроен ? в ынтерпрайзе ? пойду аракалоедов порадую. хехе. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.05.2018, 14:00 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
да, а 1С где--то пыталась бороцца с отсутствием динамической "статистики" в транзах с мильонными вставками/апдейтами. даже якобы патчик какой-то лет 5 тому назад придумывал к своей сборке 8.2 ... |
|||
:
Нравится:
Не нравится:
|
|||
04.05.2018, 14:12 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
qwwqя правильно понимаю, что для "ванилы" мало, что не комитят нормально, но как я где-то наткнулся, ещо и вычищают старые наработки (где-то не то в пп, не то в блогах их). О чём вообще речь? Да, неадекватные "наработки" вычищают, к счастью. И? qwwqто-то планировщик -- как дурень деревенский, чем дальше, тем страньше По-моему, наоборот --- чем дальше, тем лучше. Нормальный планировщик, кстати (а из opensource databases, скорее всего, лучший). qwwqа где энтот эндрю трудоустроен ? в ынтерпрайзе ? Нет. (Подозреваю, что уже нигде.) ... |
|||
:
Нравится:
Не нравится:
|
|||
04.05.2018, 21:57 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
qwwqа где энтот эндрю трудоустроен ? в ынтерпрайзе ? Andrew Gierth, он же RhodiumToad — коммитер проекта. В деталях проекта вообще и планировщика в частности разбирается неплохо. Политика проекта направлена на обеспечение приемлемых планов в большинстве случаев, и именно по этому многие угловые оптимизации отклоняют, т.к. делая хорошо для узкого числа запросов, в среднем планировщик начинает производить планы хуже. Текущее поведение выбрано из расчёта того, что автовакуум может не успеть обработать таблицу (а в случае с временной он никогда её не обработает) и в “среднем” будет лучше считать таблицу маленькой (10 страниц), но не пустой. Текущее поведение сделано умышленно. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.05.2018, 23:05 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
vyegorovqwwqа где энтот эндрю трудоустроен ? в ынтерпрайзе ? Andrew Gierth, он же RhodiumToad — коммитер проекта. В деталях проекта вообще и планировщика в частности разбирается неплохо. Политика проекта направлена на обеспечение приемлемых планов в большинстве случаев, и именно по этому многие угловые оптимизации отклоняют, т.к. делая хорошо для узкого числа запросов, в среднем планировщик начинает производить планы хуже. Текущее поведение выбрано из расчёта того, что автовакуум может не успеть обработать таблицу (а в случае с временной он никогда её не обработает) и в “среднем” будет лучше считать таблицу маленькой (10 страниц), но не пустой. Текущее поведение сделано умышленно. repeat, please я какбе на этом уровне "вражеской мовою" владею по поводу умыслов -- "дурная голова, " далее по тексту. когда и если кто задумает разгребать -- утонет, жалко его да, чем кончилась борьба 1С с плохими планами для времянок в том числе ? был у них патч ? или там все на том же уровне -- плюс -минус лапоть ? помнтися они махом вхерачивали 100500 записей (не во времянку тоже) в новый период, и начинали гонять в живой табличке иттерации с планами типа 6 вложенных нестодов по якобы пустой области статистики. и били себя пяткой в грудь, что преодолели... -- эти 10 страхоё страниц -- не оттуда часом ноги ? или они в своём патчике честно "дирти--статистику" прикидывают с меньшими лаптями, но не раскрывают ? ... |
|||
:
Нравится:
Не нравится:
|
|||
05.05.2018, 01:51 |
|
Индексы во временных таблицах
|
|||
---|---|---|---|
#18+
PgSQLanonymous3 По-моему, наоборот --- чем дальше, тем лучше. Нормальный планировщик, кстати кому и кобыла , как говаривал турецкоподданный зато работка у кодеров не переведётся -- запинывать планы переписыванием запросов всякий раз, когда очередной оптимум пройден и всё опять подказливает тут я очередной вывих оптимайзера встречал недели 2 тому -- при луз-индскане по 2-му полю в сложносоставном , практически кластерном инд-е. пришлось чуть подпихнуть 21374138 (спойлер). -- "многодумал" вместо того , чтобв сикнуть по инд-у, эта гнида решила инд--скан!! по тому!! же !! индексу с фильтром напролом от достигнутого. в расчете на независимость, видимо. твою ж богадушумать. а там -- кластерная кладка. хорошо -- запрос был скорее факультативный. из спорт интереса. т.ч. как говаривал вовочка, "-- планировщик вам хорош ?! ...ну извините !" ... |
|||
:
Нравится:
Не нравится:
|
|||
05.05.2018, 02:17 |
|
|
start [/forum/topic.php?fid=53&msg=39640457&tid=1995790]: |
0ms |
get settings: |
9ms |
get forum list: |
13ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
44ms |
get topic data: |
11ms |
get forum data: |
3ms |
get page messages: |
55ms |
get tp. blocked users: |
1ms |
others: | 16ms |
total: | 158ms |
0 / 0 |