@beduin01

Почему SQL запрос выполняется с разной скоростью?

Есть запрос:
SELECT COUNT(*) FROM xml_files t1

    WHERE NOT EXISTS (SELECT 1
              FROM xml_files t2
              WHERE t1."id" = t2."id" AND
                t1."mydate" < t2."mydate"
            )
    AND t1.insert_status IS NULL
   AND t1.section_name='users' AND t1.region IN ('Moscow') AND t1.xml_date >= to_date('2016', 'YYYY') AND t1.parsing_status IS NULL


Когда выполняю этот запрос в SQL то 10 раз он может выполняться по 90 секунд, а на 11 может выполниться за 5 и потом продолжить выполняться за 5.

Не пойму в чем причина того что в начале выполняется долго. Я бы понял если бы после первого раза, что-то прокэшировалось, но почему-то 1-го раза оказывается не достаточно,

Там какие-то оптимизаторы есть в БД или другая хитрая логика? Просто по прошествии часа история повторяется и запрос опять начинает медленно выполняться.

Оперативки 16GB.
Другой нагрузки нет т.к. поиски причины почему микросеврис получающий COUNT зависает привели именно к тому что периодически COUNT начинает слишком долго обрабатываться.

Размер БД 100GB
shared_buffers = 2048MB
maintenance_work_mem = 256MB

PostgreSQL 13
  • Вопрос задан
  • 723 просмотра
Пригласить эксперта
Ответы на вопрос 1
@galaxy
Когда выполняю этот запрос в SQL то 10 раз он может выполняться по 90 секунд, а на 11 может выполниться за 5 и потом продолжить выполняться за 5.
...
Там какие-то оптимизаторы есть в БД или другая хитрая логика? Просто по прошествии часа история повторяется и запрос опять начинает медленно выполняться.

ну эта картина неудивительная. Почти любой кеш работает по принципу вытеснения LRU (least recently used) данных. Вы повторяете запрос - ваши данные вытесняют то, что было в кеше. Вы прекращаете - другие запросы вытесняют ваши данные.

Далее, судя по плану, вам стоит сделать на таблицы ANALYZE (и, может быть, увеличить статистику - ALTER TABLE SET STATISTICS), т.к. реальное число строк и оценка расходятся весьма сильно.

И, наконец, self-join'а тут можно не делать. Нужен по сути последний по дате документ, так что, с поправкой на составление запросов в уме:
SELECT * FROM (
     SELECT row_number() OVER (PARTITION BY id ORDER BY mydate DESC) as rn,
          t1.* FROM xml_files t1
         AND t1.insert_status IS NULL
        AND t1.section_name='users' AND t1.region IN ('Moscow') AND t1.xml_date >= to_date('2016', 'YYYY') AND t1.parsing_status IS NULL
     ) t
 WHERE rn = 1
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы