powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Разное поведение запроса с LIMIT 1 на 9.4 и 10
21 сообщений из 21, страница 1 из 1
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674047
egusakova
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть запрос который по неясной причине ведет себя по разному на 9.4 и 10 версии базы

Все примеры ниже приведены со специально установленных серверов с одинаковым набором данных (залит один дамп, 1000000 строк)
Структура базы, индексы и последовательности тоже абсолютно одинаковые

Результаты запуска EXPLAIN ANALYZE соответствуют тому что выдает EXPLAIN и я их не привожу.


На 10-й видно что индексы НЕ используются - Seq Scan

Код: 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.
EXPLAIN  
    SELECT  "articles".*  
        FROM 
            "articles"  
        WHERE 
            "articles"."type" IN ('Tweet') 
        AND 
            "articles"."duplicates_mapped" = 't' 
        AND 
             ("articles"."masked_url_md5" IS NOT NULL) 
        AND 
              ("articles"."proc_phase" != 'culled') 
        AND 
             ("articles"."type" != 'InfoItem') 
        AND  
             "articles"."duplicate" = 'f' 
        AND 
              "articles"."masked_url_md5" IS NULL LIMIT 1;
                                                                                                                 QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.00..2.60 rows=1 width=2329)
   ->  Seq Scan on articles  (cost=0.00..117454.20 rows=45129 width=2329)
         Filter: (duplicates_mapped AND (masked_url_md5 IS NOT NULL) AND (NOT duplicate) AND (masked_url_md5 IS NULL) AND ((proc_phase)::text <> 'culled'::text) AND ((type)::text <> 'InfoItem'::text) AND ((type)::text = 'Tweet'::text))
(3 rows)



На 9-й (запрос тот же просто не отформатирован)
Видно использование индексов Index Scan

Код: sql
1.
2.
3.
4.
5.
6.
EXPLAIN  SELECT  "articles".*  FROM "articles"  WHERE "articles"."type" IN ('Tweet') AND "articles"."duplicates_mapped" = 't' AND  ("articles"."masked_url_md5" IS NOT NULL) AND ("articles"."proc_phase" != 'culled') AND  ("articles"."type" != 'InfoItem') AND  "articles"."duplicate" = 'f' AND  "articles"."masked_url_md5" IS NULL LIMIT 1;
                                                                                QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.42..1.40 rows=1 width=2270)
   ->  Index Scan using new_articles_proc_phase_type_duplicates_mapped_duplicate_ma_idx on articles  (cost=0.42..43172.61 rows=44131 width=2270)
         Index Cond: (((type)::text = 'Tweet'::text) AND (duplicates_mapped = true) AND (duplicate = false) AND (masked_url_md5 IS NOT NULL) AND (masked_url_md5 IS NULL))



Т.е. поведение (и естественно время работы) различное

Есть предположение что планировщик "сильно хитрый" и эврестически определяет "раз там лимит всего 1 то начнем с начала сканить авось быстро найдем нужную запись"


Это предположение подтверждается тем что если переделать запрос то индексы начинают использоваться

Код: 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.
29.
 EXPLAIN  ANALYZE  
WITH T AS (
     SELECT  "articles".*  
     FROM 
       "articles"
      WHERE 
          "articles"."type" IN ('Tweet') 
           AND 
           "articles"."duplicates_mapped" = 't' 
           AND  
           ("articles"."masked_url_md5" IS NOT NULL) 
          AND 
           ("articles"."proc_phase" != 'culled') 
          AND
           ("articles"."type" != 'InfoItem') 
          AND  
          "articles"."duplicate" = 'f' 
          AND  "articles"."masked_url_md5" IS NULL ) SELECT * FROM T  LIMIT  1;
                                                                                                 QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=85877.26..85877.28 rows=1 width=5387) (actual time=123.474..123.474 rows=0 loops=1)
   CTE t
     ->  Bitmap Heap Scan on articles  (cost=4845.05..85877.26 rows=45129 width=2329) (actual time=123.471..123.471 rows=0 loops=1)
           Recheck Cond: (((type)::text = 'Tweet'::text) AND (masked_url_md5 IS NULL) AND ((proc_phase)::text <> 'culled'::text) AND duplicates_mapped AND (NOT duplicate) AND (masked_url_md5 IS NOT NULL))
           ->  Bitmap Index Scan on new_articles_proc_phase_type_duplicates_mapped_duplicate_ma_idx  (cost=0.00..4833.77 rows=45129 width=0) (actual time=123.466..123.466 rows=0 loops=1)
                 Index Cond: (((type)::text = 'Tweet'::text) AND (masked_url_md5 IS NULL))
   ->  CTE Scan on t  (cost=0.00..902.58 rows=45129 width=5387) (actual time=123.473..123.473 rows=0 loops=1)
 Planning time: 0.665 ms
 Execution time: 123.577 ms



Аналогично, если в запрос добавить ORDER BY RANDOM() то индексы начинают использоваться.

- Это поведение настраивается ? Где-то задокументировано? В ченжлоге ничего похожего нет
- И вообще это баг или фича?
- Есть ли идеи как можно изменить поведение кроме как SET enable_seqscan = OFF;
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674064
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egusakova,

Как ни странно именно v10 исходя из статистики ведет себя корректно. :)

Покажите итоги на v10 следующих запросов

explain analyze select * from articles where type='Tweet';
explain analyze select * from articles where masked_url_md5 IS NULL;
explain analyze select * from articles where masked_url_md5 IS NULL AND type='Tweet';

у вас походу корреляция между этими двумя условиями.

Что можно посоветовать
или
v1: индекс на articles(type) where masked_url_md5 IS NULL с последующим analyze articles
или если v1 не помогает то использовать фичу 10 с create statistics:
CREATE STATISTICS ON type, masked_url_md5 FROM articles ;
с последующим analyze articles И проверкой вашего запроса.


Проблема в следующем на самом деле:
-> Bitmap Index Scan on new_articles_proc_phase_type_duplicates_mapped_duplicate_ma_idx (cost=0.00..4833.77 rows=45129 width=0) (actual time=123.466..123.466 rows=0 loops=1)
Index Cond: (((type)::text = 'Tweet'::text) AND (masked_url_md5 IS NULL))

И исходя из статистики 10 поступает более верно... быстрее найти seq scanом 1 строку из 50k в таблице на 1M (это всего 20 строк проверить в среднем) чем лезть в индекс.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674076
egusakova
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
@Maxim Boguk Спасибо за ответ!

Как ни странно именно v10 исходя из статистики ведет себя корректно. :)

Не могу согласится - на реальных данных (а не жалком 1М строк) запрос на 10-м отрабатывает ~800 секунд
а на 9-м меньше 1 секунды
(но результаты explain не отличаются - индекс не используется на 10-ке)

Уточню, что я создала лабу из 2-х линуксов с 9-м и 10-м постгресом и залила туда 1М записей из оригинальной таблицы что б сравнить поведение. На самом деле таблица значительно больше (67 гиг данных)

Собственно сама задача поиска проблемы возникла из-за замедления приложения после перехода на 10-ку

Покажите итоги на v10 следующих запросов


На 9 и на 10 вывод одинаковый
Код: 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.
29.
30.
31.
32.
explain analyze select * from articles where type='Tweet';
                                                      QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------
 Seq Scan on articles  (cost=0.00..112464.54 rows=900568 width=2270) (actual time=4.904..6283.272 rows=902048 loops=1)
   Filter: ((type)::text = 'Tweet'::text)
   Rows Removed by Filter: 97952
 Planning time: 0.238 ms
 Execution time: 6347.023 ms
(5 rows)

[SRC sql]
explain analyze select * from articles where masked_url_md5 IS NULL;
                                                      QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------
 Seq Scan on articles  (cost=0.00..109965.83 rows=370575 width=2270) (actual time=3.447..2085.110 rows=373613 loops=1)
   Filter: (masked_url_md5 IS NULL)
   Rows Removed by Filter: 626387
 Planning time: 1.312 ms
 Execution time: 2108.809 ms
(5 rows)


[SRC sql]
explain analyze select * from articles where masked_url_md5 IS NULL AND type='Tweet';
                                                      QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------
 Seq Scan on articles  (cost=0.00..112464.54 rows=333900 width=2270) (actual time=7.074..2132.089 rows=334019 loops=1)
   Filter: ((masked_url_md5 IS NULL) AND ((type)::text = 'Tweet'::text))
   Rows Removed by Filter: 665981
 Planning time: 0.257 ms
 Execution time: 2152.956 ms
(5 rows)





v1: индекс на articles(type) where masked_url_md5 IS NULL с последующим analyze articles


Код: sql
1.
2.
CREATE INDEX eg_1 ON public.articles  USING btree (type) where masked_url_md5 IS NULL;
CREATE INDEX



Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
 EXPLAIN ANALYZE   SELECT  "articles".*  FROM "articles"  WHERE "articles"."type" IN ('Tweet') AND "articles"."duplicates_mapped" = 't' AND  ("articles"."masked_url_md5" IS NOT NULL) AND ("articles"."proc_phase" != 'culled') AND  ("articles"."type" != 'InfoItem') AND  "articles"."duplicate" = 'f' AND  "articles"."masked_url_md5" IS NULL LIMIT 1;
                                                                                                                 QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.00..2.58 rows=1 width=2416) (actual time=542.519..542.519 rows=0 loops=1)
   ->  Seq Scan on articles  (cost=0.00..117458.00 rows=45474 width=2416) (actual time=542.517..542.517 rows=0 loops=1)
         Filter: (duplicates_mapped AND (masked_url_md5 IS NOT NULL) AND (NOT duplicate) AND (masked_url_md5 IS NULL) AND ((proc_phase)::text <> 'culled'::text) AND ((type)::text <> 'InfoItem'::text) AND ((type)::text = 'Tweet'::text))
         Rows Removed by Filter: 1000000
 Planning time: 0.403 ms
 Execution time: 542.559 ms
(6 rows)



Т.е насколько можно судить индекс все так же не используется.

или если v1 не помогает то использовать фичу 10 с create statistics:
CREATE STATISTICS ON type, masked_url_md5 FROM articles ;
с последующим analyze articles И проверкой вашего запроса.


Код: sql
1.
2.
3.
4.
# CREATE STATISTICS eg_1  ON type, masked_url_md5 FROM articles;
CREATE STATISTICS
#  analyze articles;
ANALYZE



Тут видно что запрос действительно медленный :
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
EXPLAIN ANALYZE   SELECT  "articles".*  FROM "articles"  WHERE "articles"."type" IN ('Tweet') AND "articles"."duplicates_mapped" = 't' AND  ("articles"."masked_url_md5" IS NOT NULL) AND ("articles"."proc_phase" != 'culled') AND  ("articles"."type" != 'InfoItem') AND  "articles"."duplicate" = 'f' AND  "articles"."masked_url_md5" IS NULL LIMIT 1;
                                                                                                                 QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.00..2.58 rows=1 width=2416) (actual time=525.965..525.965 rows=0 loops=1)
   ->  Seq Scan on articles  (cost=0.00..117458.00 rows=45474 width=2416) (actual time=525.963..525.963 rows=0 loops=1)
         Filter: (duplicates_mapped AND (masked_url_md5 IS NOT NULL) AND (NOT duplicate) AND (masked_url_md5 IS NULL) AND ((proc_phase)::text <> 'culled'::text) AND ((type)::text <> 'InfoItem'::text) AND ((type)::text = 'Tweet'::text))
         Rows Removed by Filter: 1000000
 Planning time: 0.438 ms
 Execution time: 526.010 ms
(6 rows)



Для сравнения с 9-ки
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
EXPLAIN ANALYZE   SELECT  "articles".*  FROM "articles"  WHERE "articles"."type" IN ('Tweet') AND "articles"."duplicates_mapped" = 't' AND  ("articles"."masked_url_md5" IS NOT NULL) AND ("articles"."proc_phase" != 'culled') AND  ("articles"."type" != 'InfoItem') AND  "articles"."duplicate" = 'f' AND  "articles"."masked_url_md5" IS NULL LIMIT 1;
                                                                                        QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.42..1.40 rows=1 width=2270) (actual time=0.003..0.003 rows=0 loops=1)
   ->  Index Scan using new_articles_proc_phase_type_duplicates_mapped_duplicate_ma_idx on articles  (cost=0.42..43172.61 rows=44131 width=2270) (actual time=0.002..0.002 rows=0 loops=1)
         Index Cond: (((type)::text = 'Tweet'::text) AND (duplicates_mapped = true) AND (duplicate = false) AND (masked_url_md5 IS NOT NULL) AND (masked_url_md5 IS NULL))
 Planning time: 0.303 ms
 Execution time: 0.038 ms
(5 rows)




Проблема в следующем на самом деле:
-> Bitmap Index Scan on new_articles_proc_phase_type_duplicates_mapped_duplicate_ma_idx (cost=0.00..4833.77 rows=45129 width=0) (actual time=123.466..123.466 rows=0 loops=1)
Index Cond: (((type)::text = 'Tweet'::text) AND (masked_url_md5 IS NULL))

И исходя из статистики 10 поступает более верно... быстрее найти seq scanом 1 строку из 50k в таблице на 1M (это всего 20 строк проверить в среднем) чем лезть в индекс.

Это пояснение мне к сожалению не ясно.
Дядя, я не настоящий сварщик (с) (я DBA поневоле - надо решить задачу переезда и опыт с постгресом очень небольшой)

>быстрее найти seq scanом 1
Это полный перебор, разве нет? Т.е возможно я не верно интерпретирую то что показывает EXPLAIN

Я читала вывод так "планировщик считает что для 1М записей он найдет то 1 что требуется по лимиту и соответствует условию просто перебором в лоб (так как ему нужна всего одна запись)"
Но так как по факту в таблице таких записей нет - то запрос фактически исполняется медленно и эквивалентен "SELECT "articles".* FROM "articles";"

Можете пожалуйста пояснить подробнее (или дать ссылку на правильное место в документации)
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674086
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egusakova,

Ваша проблема
"Но так как по факту в таблице таких записей нет - то запрос фактически исполняется медленно и эквивалентен "SELECT "articles".* FROM "articles";""
при том что планировщик считает что их в вашей тестовой таблице rows=44131 штук
отсюда все проблемы.

Надо разбираться где у вас статистика кривая (по какому набору условий в вашем запросе).

Впрочем для начала объясните наличие в запросе одновременно
"articles"."masked_url_md5" IS NOT NULL
и
"articles"."masked_url_md5" IS NULL

Чтобы это значило кроме попытки специально сломать планировщику мозг :)
?

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674087
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egusakova,

Кстати ну очень интересно что на десятке показывает

explain analyze select * from articles where ("articles"."masked_url_md5" IS NOT NULL) and ("articles"."masked_url_md5" IS NULL);

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674159
egusakova
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Впрочем для начала объясните наличие в запросе одновременно
"articles"."masked_url_md5" IS NOT NULL
и
"articles"."masked_url_md5" IS NULL

Это очень хороший вопрос. Запрос выдернут из логов приложения и я перепроверила - NULL/NOT NULL там не параметризируются.
Похоже на ошибку/опечатку.

Чтобы это значило кроме попытки специально сломать планировщику мозг :)
?

Да, похоже, но почему 10-й сходит с ума а 9-й нет? Не ясно :(


Кстати ну очень интересно что на десятке показывает
explain analyze select * from articles where ("articles"."masked_url_md5" IS NOT NULL) and ("articles"."masked_url_md5" IS NULL);



10-ка (c дополнительным индексом и CREATE STATISTICS eg_1 ON type, masked_url_md5 FROM articles;
что, похоже, влияет на скорость работы)
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
explain analyze select * from articles where ("articles"."masked_url_md5" IS NOT NULL) and ("articles"."masked_url_md5" IS NULL);
                                                    QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
 Seq Scan on articles  (cost=0.00..109963.57 rows=232509 width=2416) (actual time=515.865..515.865 rows=0 loops=1)
   Filter: ((masked_url_md5 IS NOT NULL) AND (masked_url_md5 IS NULL))
   Rows Removed by Filter: 1000000
 Planning time: 0.293 ms
 Execution time: 515.898 ms
(5 rows)



9-ка
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
explain analyze select * from articles where ("articles"."masked_url_md5" IS NOT NULL) and ("articles"."masked_url_md5" IS NULL);
                                                     QUERY PLAN
---------------------------------------------------------------------------------------------------------------------
 Seq Scan on articles  (cost=0.00..109965.83 rows=233178 width=2270) (actual time=2049.254..2049.254 rows=0 loops=1)
   Filter: ((masked_url_md5 IS NOT NULL) AND (masked_url_md5 IS NULL))
   Rows Removed by Filter: 1000000
 Planning time: 0.224 ms
 Execution time: 2049.289 ms
(5 rows)


Разница в 4 раза


Это не "боевая" база - не ясно как могла "сломаться" статистика - тут за все время жизни была только одна операция записи - загрузка данных из файла
Остальные запросы - SELECT
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674221
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egusakova,

1)При смене major версии базы конкретный запрос может стать как быстрее так и медленнее.

2)Чем более кривой запрос - тем больше шансы на то что план поедет в сторону замедления при смене major версии базы.

3)В данном конкретном случае - наиболее правильно исправить заведомо неверный запрос.

4)Еще может быть разница в настройках 9.4 и 10.0 инсталляций которая влияет на выбор плана.


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674389
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Bogukegusakova,

Как ни странно именно v10 исходя из статистики ведет себя корректно. :)


хмм очень странное утверждение.
он должен вертать пустое мн-во мгновенно , не лазая в статистику. найдя 2 взаимоисключающих ещё во время разбора


итого -- ещё одно подтверждение невероятного колхоза в планировщике пж.
что в 9 что в 10

и чем дальше в лес, тем партизанен наваристей
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674417
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwqMaxim Bogukegusakova,

Как ни странно именно v10 исходя из статистики ведет себя корректно. :)


хмм очень странное утверждение.
он должен вертать пустое мн-во мгновенно , не лазая в статистику. найдя 2 взаимоисключающих ещё во время разбора


Я написал исходя из СТАТИСТИКИ а не из здравого смысла.

Никто не заморочился проверкой на то что в запросе может быть 2 взаимоисключающих IS NULL/IS NOT NULL потому что такое в нормальном случае не возникает а на все возможные странные вещи эвристики писать - индусов не напасешься.
Я даже баг репорт писать не стал чтобы не выглядеть идиотом. :)

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674464
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim BogukЯ даже баг репорт писать не стал чтобы не выглядеть идиотом. :)

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru

писать идиотам что они идиоты -- действительно дело сомнительной полезности.

улыбаемся и машем

Код: 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.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
SELECT id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3,ck4, ci
FROM trash.ngrams4w
where null is not null
---------
'Result  (cost=0.00..0.00 rows=0 width=152) (actual time=0.001..0.001 rows=0 loops=1)'
'  Output: id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3, ck4, ci'
'  One-Time Filter: false'
'Planning time: 0.032 ms'
'Execution time: 0.010 ms'
----------------------
SELECT id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3,ck4, ci
FROM trash.ngrams4w
where
keyword_1 is null 
and keyword_1 is not null
-------------------------
'Index Scan using ngrams4w_keyword_1_keyword_2_keyword_3_keyword_4_id_idx on trash.ngrams4w  (cost=0.56..8.57 rows=1 width=71) (actual time=0.003..0.003 rows=0 loops=1)'
'  Output: id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3, ck4, ci'
'  Index Cond: ((ngrams4w.keyword_1 IS NULL) AND (ngrams4w.keyword_1 IS NOT NULL))'
'Planning time: 0.106 ms'
'Execution time: 0.031 ms'
-----------
SELECT id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3,ck4, ci
FROM trash.ngrams4w
where
keyword_1 <'a'
and keyword_1 > 'b'
--------------
'Index Scan using ngrams4w_keyword_1_keyword_2_keyword_3_keyword_4_id_idx on trash.ngrams4w  (cost=0.56..8.57 rows=1 width=71) (actual time=0.015..0.015 rows=0 loops=1)'
'  Output: id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3, ck4, ci'
'  Index Cond: ((ngrams4w.keyword_1 < 'a'::text) AND (ngrams4w.keyword_1 > 'b'::text))'
'  Buffers: shared hit=4'
'Planning time: 0.138 ms'
'Execution time: 0.033 ms'
---------------
SELECT id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3,ck4, ci
FROM trash.ngrams4w
where
ck1 < 0
and ck1 > 0
--------------
'Gather  (cost=1000.00..66357.99 rows=1 width=71) (actual time=3140.231..3140.231 rows=0 loops=1)'
'  Output: id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3, ck4, ci'
'  Workers Planned: 4'
'  Workers Launched: 4'
'  Buffers: shared hit=598 read=50139 dirtied=14 written=14'
'  ->  Parallel Seq Scan on trash.ngrams4w  (cost=0.00..65357.89 rows=1 width=71) (actual time=3138.187..3138.187 rows=0 loops=5)'
'        Output: id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3, ck4, ci'
'        Filter: ((ngrams4w.ck1 < 0) AND (ngrams4w.ck1 > 0))'
'        Rows Removed by Filter: 791487'
'        Buffers: shared hit=374 read=50139 dirtied=14 written=14'
'        Worker 0: actual time=3137.655..3137.655 rows=0 loops=1'
'          Buffers: shared hit=104 read=12442 dirtied=4 written=4'
'        Worker 1: actual time=3137.453..3137.453 rows=0 loops=1'
'          Buffers: shared hit=78 read=10199 dirtied=1 written=1'
'        Worker 2: actual time=3137.920..3137.920 rows=0 loops=1'
'          Buffers: shared hit=68 read=9353 dirtied=4 written=4'
'        Worker 3: actual time=3137.920..3137.920 rows=0 loops=1'
'          Buffers: shared hit=52 read=8006 dirtied=1 written=1'
'Planning time: 0.064 ms'
'Execution time: 3141.713 ms'



д,б. (лавров)
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674724
PgSQLanonymous3
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwqписать идиотам что они идиоты -- действительно дело сомнительной полезности.

Действительно. Поэтому это сообщение --- не тебе, а другим читающим тему.

qwwqулыбаемся и машем

Если действительно интересно, используем:
Код: sql
1.
SET constraint_exclusion = on;

Повторяем приведённые тесты, улыбаемся веселее.

Дело в том, что целью планировщиков (во всех СУБД!) не является построение наилучших планов запросов.

Их цель --- построение приемлемых планов за приемлемое время, вот и всё.
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674734
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PgSQLanonymous3,

Интересный эффект с constraint_exclusion. И опять вы показали какие то незнакомые для меня стороны базы.
Hmm...

PS: автору топика - включите в конфиге constraint_exclusion=on на 10той версии и проблема уйдет. Это не значит что такие запросы надо использовать впрочем.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674748
Andy_OLAP
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egusakovaЕсть запрос который по неясной причине ведет себя по разному на 9.4 и 10 версии базы



На 10-й видно что индексы НЕ используются - Seq Scan


На 9-й (запрос тот же просто не отформатирован)
Видно использование индексов Index Scan


- Это поведение настраивается ? Где-то задокументировано? В ченжлоге ничего похожего нет

Ой-вей, ну что Вы таки говорите, что нигде нет. Они же предупреждали, что в 10-ке будут активно развивать параллелизм. Помнится, что полгода назад Кори Такер пытал разработчиков, почему у него на 9.6 и 10.3 разные планы выполнения. Сначала Дэвид Роули из 2ndquadrant, потом Том Лейн подключился. Выясняли, что планировщик таки думает, что parallel seqscan в 10-ке будет быстрее, чем nonparallel indexscan. А самое забавно, что было удаление из таблицы с использованием WHERE NOT EXISTS и условий через OR, а внутри был select 1 .... При этом удаление никак не параллельная операция.

То есть планировщик смотрит исключительно на условие типа select 1 или limit 1 - и в 10-ке начинает думать, что все легко и просто . То есть придется его учить через явный вывод limit 1 из куска, который поступает на анализатор, вот это "SELECT * FROM T LIMIT 1" - очень правильный путь. Не нужно бороться с планировщиком, нужно подсказать анализатору.
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674878
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PgSQLanonymous3Если действительно интересно, используем:
Код: sql
1.
SET constraint_exclusion = on;

Повторяем приведённые тесты, улыбаемся веселее.


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

Код: 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.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
SET constraint_exclusion = on;
---------------
SELECT id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3,ck4, ci
FROM trash.ngrams4w
where null is not null
---------
'Result  (cost=0.00..0.00 rows=0 width=152) (actual time=0.001..0.001 rows=0 loops=1)'
'  Output: id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3, ck4, ci'
'  One-Time Filter: false'
'Planning time: 0.032 ms'
'Execution time: 0.010 ms'
----------------------
SELECT id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3,ck4, ci
FROM trash.ngrams4w
where
keyword_1 is null 
and keyword_1 is not null
-------------------------
'Result  (cost=0.00..0.00 rows=0 width=152) (actual time=0.001..0.001 rows=0 loops=1)'
'  Output: id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3, ck4, ci'
'  One-Time Filter: false'
'Planning time: 0.037 ms'
'Execution time: 0.012 ms'
-----------
SELECT id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3,ck4, ci
FROM trash.ngrams4w
where
keyword_1 <'a'
and keyword_1 > 'b'
--------------
'Result  (cost=0.00..0.00 rows=0 width=152) (actual time=0.001..0.001 rows=0 loops=1)'
'  Output: id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3, ck4, ci'
'  One-Time Filter: false'
'Planning time: 0.050 ms'
'Execution time: 0.010 ms'
---------------
SELECT id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3,ck4, ci
FROM trash.ngrams4w
where
ck1 < 0
and ck1 > 0
--------------
'Result  (cost=0.00..0.00 rows=0 width=152) (actual time=0.000..0.000 rows=0 loops=1)'
'  Output: id, keyword_1, keyword_2, keyword_3, keyword_4, ck1, ck2, ck3, ck4, ci'
'  One-Time Filter: false'
'Planning time: 0.041 ms'
'Execution time: 0.010 ms'




ПС: всё ещё ждём-с выкладок по некошерному рекавери. ну или каких иных пояснений
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674880
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
зы было

Код: sql
1.
2.
3.
show constraint_exclusion
-----
'partition'
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674907
xojenisoj
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
PgSQLanonymous3Если действительно интересно, используем:
Код: sql
1.
SET constraint_exclusion = on;

Повторяем приведённые тесты, улыбаемся веселее.

В настоящее время исключение по ограничению разрешено по умолчанию только в условиях, возникающих при реализации секционированных таблиц. Включение этой возможности для всех таблиц влечёт дополнительные издержки на планирование, довольно заметные для простых запросов, но никакого выигрыша это не приносит. Если вы не применяете секционированные таблицы, лучше всего полностью отключить эту возможность.
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674957
Andy_OLAP
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
egusakova@Maxim Boguk Спасибо за ответ!

Как ни странно именно v10 исходя из статистики ведет себя корректно. :)

Не могу согласится - на реальных данных (а не жалком 1М строк) запрос на 10-м отрабатывает ~800 секунд
а на 9-м меньше 1 секунды
(но результаты explain не отличаются - индекс не используется на 10-ке)

Уточню, что я создала лабу из 2-х линуксов с 9-м и 10-м постгресом и залила туда 1М записей из оригинальной таблицы что б сравнить поведение. На самом деле таблица значительно больше (67 гиг данных)


Можете пожалуйста пояснить подробнее (или дать ссылку на правильное место в документации)
9.4 и установка work_mem - у Вас получается lossy/exact pages for bitmap heap scan. Серверы под версиями 9.4 и 10 настроены абсолютно одинаково по всем переменным?
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39674961
Andy_OLAP
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xojenisojЕсли вы не применяете секционированные таблицы, лучше всего полностью отключить эту возможность.
А если таблицы секционированные - лучше срочно накатить 10.4, хотя бы по причине "Correctly enforce any CHECK constraints on individual partitions during COPY to a partitioned table".
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39675312
PgSQLanonymous3
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xojenisojВ настоящее время исключение по ограничению разрешено по умолчанию только в условиях, возникающих при реализации секционированных таблиц. Включение этой возможности для всех таблиц влечёт дополнительные издержки на планирование, довольно заметные для простых запросов, но никакого выигрыша это не приносит. Если вы не применяете секционированные таблицы, лучше всего полностью отключить эту возможность.
Так это именно та мысль, которую я хотел донести (просто другими словами).
В PostgreSQL это, кстати, особенно выражено.

IMHO, как минимум, по двум простым причинам:
1. Архитектура планировщика (а она "классическая", такая ещё в System R была, кажется) не очень-то удобна для контроля времени планирования, а, наоборот, располагает к "as fast as possible".
2. "Личная" причина: представьте, сидит кто-нибудь из committer-ов и думает: "На какой бы из (допустим) 20 возможных проектов улучшения планировщика мне потратить время моей единственной жизни ? Может, сделать его более терпимым к коду идиотов людей, которые пишут лишние или противоречащие друг другу условия, недетерминированные запросы, или даже просто неидиоматический SQL?"
Как вы думаете, как они себе отвечают на этот вопрос? ;)
У разработчиков какой-нибудь другой, коммерческой СУБД (которым платят и "заказывают музыку"), наверное, есть и другой ответ на этот вопрос...
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39675422
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PgSQLanonymous3,

допустим генерирует автомат мильон условий. и таких автоматов много.
"тысячи их"
и в кажинном таком автомате прикажете свой анализатор условий -- предпланировщик рисовать ?
ась ?

то то и оно то

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


ну вы с вашим зеркалом с двух рук по македонски можете дальше побеседовать, потешить т.с. публику
...
Рейтинг: 0 / 0
Разное поведение запроса с LIMIT 1 на 9.4 и 10
    #39675940
egusakova
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Коллеги, огромное спасибо за ответы - моя проблема так или иначе решена.

Проблема в коде который действительно генерировал неверный запрос - исправили со стороны кода а не со стороны базы (хотя это и не то чего мне хотелось бы)


@Maxim Boguk: СПАСИБО!
Внимательность - Ваше "второе Я"
Все действительно настолько очевидно, но только если знать в чем дело.

@Andy_OLAP
9.4 и установка work_mem - у Вас получается lossy/exact pages for bitmap heap scan. Серверы под версиями 9.4 и 10 настроены абсолютно одинаково по всем переменным?


Конечно, сервера для тестов ставила "с нуля" с дефолтными настройками, а потом проверяла значения всех переменных (и сравнивая с продакшен/стейджинг установками)

Все одинаково с точностью до путей/имен файлов
Я не смогла найти никаких настроек которые бы _явно_ отличались

Аналогично сравнила конфиги - значимой разницы не нашла

Возможно есть какие-то "скрытые" умолчания но опять же нагуглить что-либо не вышло.
...
Рейтинг: 0 / 0
21 сообщений из 21, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Разное поведение запроса с LIMIT 1 на 9.4 и 10
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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