Postgres 9.6 выбирает неверный план запросов после миграции в базу данных под большой нагрузкой - PullRequest
0 голосов
/ 29 января 2019

Мы очень часто выполняем миграцию, и то, что начиналось как обычная миграция, заставило Postgres выбрать плохой план запросов, который вызвал очень медленные запросы.Запросы были настолько плохими, что в итоге наш сайт отключился.

Миграция сняла нулевое ограничение для существующей таблицы.В этом примере он удалял нулевое ограничение для items.store_id.

Индексы в таблице items:

CREATE INDEX index_items_store_id ON public.items USING btree (store_id)
CREATE INDEX index_items_on_department_id ON public.items USING btree (department_id)
CREATE INDEX index_items_on_deleted_at ON public.items USING btree (deleted_at)
CREATE UNIQUE INDEX items_pkey ON public.items USING btree (id)

Пример запроса:

SELECT "stores".*
  FROM "stores"
 WHERE "stores"."organization_id" = 1337
   AND "stores"."store_status_id" = 1
   AND (EXISTS (SELECT "items".*
                  FROM "items"
                 INNER JOIN "departments"
                    ON "departments"."id" = "items"."department_id"
                 WHERE "items"."deleted_at" IS NULL
                   AND ("items"."department_id" IS NOT NULL)
                   AND (items.store_id = stores.id)
                   AND "items"."job_application_status_id" = 3
                   AND "departments"."department_status_id" = 3));

План неверных запросов:

Nested Loop  (cost=216890.17..217379.24 rows=192 width=1236)
   ->  HashAggregate  (cost=216889.74..216891.74 rows=200 width=4)
         Group Key: items.store_id
         ->  Merge Join  (cost=2.13..216769.74 rows=48000 width=4)
               Merge Cond: (departments.id = items.department_id)
               ->  Index Scan using departments_pkey on departments  (cost=0.41..10394.19 rows=8925 width=4)
                     Filter: (department_status_id = 3)
               ->  Index Scan using index_items_on_department_id on items  (cost=0.55..309417.94 rows=8 8783 width=8)
                     Index Cond: (department_id IS NOT NULL)
                     Filter: ((deleted_at IS NULL) AND (job_application_status_id = 3))
   ->  Index Scan using stores_pkey on stores  (cost=0.42..2.43 rows=1 width=1236)
         Index Cond: (id = items.store_id)
         Filter: ((organization_id = 1337) AND (store_status_id = 1))

хороший план запросов:

Nested Loop Semi Join  (cost=1.26..4566.90 rows=21 width=1236)
   ->  Index Scan using index_stores_on_organization_id on stores  (cost=0.42..2236.83 rows=385 width=1236)
         Index Cond: (organization_id = 1337)
         Filter: (store_status_id = 1)
   ->  Nested Loop  (cost=0.84..6.04 rows=1 width=4)
         ->  Index Scan using index_gh_job_app_store_id on items  (cost=0.43..5.46 rows=1 width=8)
               Index Cond: (store_id = stores.id)
               Filter: ((deleted_at IS NULL) AND (department_id IS NOT NULL) AND (job_application_status_id = 3))
         ->  Index Scan using departments_pkey on departments  (cost=0.41..0.57 rows=1 width=4)
               Index Cond: (id = items.department_id)
               Filter: (department_status_id = 3)

После выполнения ANALYZE для таблицы items Postgres выбрал хороший планировщик запросов, и все снова было хорошо.Мы попытались воспроизвести эту миграцию локально и в других промежуточных средах и не смогли воспроизвести.Мы также делали этот тип миграций раньше много раз и никогда не сталкивались с подобными проблемами.Мы подозреваем, что это связано с количеством запросов, которые эта таблица получает в любой момент времени, поэтому трудно воспроизвести.

Но у нас нет большого опыта в том, как Postgres выбирает лучший планировщик запросов икак мы можем избежать этого в будущем.Если у кого-то есть идеи о том, почему это произошло или как этого избежать, это будет с благодарностью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...