проблемы оптимизации запросов postgres - PullRequest
4 голосов
/ 22 июня 2011

Ниже приведены два запроса postgres, которые почти идентичны, но выдают совершенно разные планы запросов и время выполнения. Я предполагаю, что первый запрос быстрый, потому что есть только 196 записей form_instance, где form_id = 'W40', тогда как есть 7000, где form_id = 'W30L'. Но почему переход с 200 до 7000 записей (что мне кажется относительно незначительным) вызывает такое ошеломительное увеличение времени запроса? Я пытался проиндексировать данные различными способами, чтобы ускорить это, но в основном сбит с толку. Как я могу ускорить это? (Обратите внимание, что схемы для обеих таблиц включены внизу).

explain analyze select form_id,form_instance_id,answer,field_id
from form_instances,field_instances 
where workflow_state = 'DRqueued' and form_instance_id = form_instances.id 
and field_id in ('Book_EstimatedDueDate','H_SubmittedDate','H_Ccode','miscarriage','miscarriage_of_multiple','stillbirth','AP_IUFD_of_multiple','maternal_death','birth_includes_transport','newborn_death','H_Pid','H_Mid1','H_Mid2','H_Mid3')
and (form_id = 'W40');

QUERY PLAN                                                                                                                                
 Nested Loop  (cost=0.00..70736.14 rows=4646 width=29) (actual time=0.000..20.000 rows=2399 loops=1)
   ->  Index Scan using form_id_and_workflow_state on form_instances  (cost=0.00..1041.42 rows=507 width=8) (actual time=0.000..0.000 rows=196 loops=1)
         Index Cond: (((form_id)::text = 'W40'::text) AND ((workflow_state)::text = 'DRqueued'::text))
   ->  Index Scan using index_field_instances_on_form_instance_id on field_instances  (cost=0.00..137.25 rows=17 width=25) (actual time=0.000..0.102 rows=12 loops=196)
         Index Cond: (field_instances.form_instance_id = form_instances.id)
         Filter: ((field_instances.field_id)::text = ANY ('{Book_EstimatedDueDate,H_SubmittedDate,H_Ccode,miscarriage,miscarriage_of_multiple,stillbirth,AP_IUFD_of_multiple,maternal_death,birth_includes_transport,newborn_death,H_Pid,H_Mid1,H_Mid2,H_Mid3}'::text[]))
 Total runtime: 30.000 ms
(7 rows)

explain analyze select form_id,form_instance_id,answer,field_id 
from form_instances,field_instances 
where workflow_state = 'DRqueued' and form_instance_id = form_instances.id 
and field_id in ('Book_EstimatedDueDate','H_SubmittedDate','H_Ccode','miscarriage','miscarriage_of_multiple','stillbirth','AP_IUFD_of_multiple','maternal_death','birth_includes_transport','newborn_death','H_Pid','H_Mid1','H_Mid2','H_Mid3') 
and (form_id = 'W30L');

QUERY PLAN                                                                                                                             
 Hash Join  (cost=34300.46..160865.40 rows=31045 width=29) (actual time=65670.000..74960.000 rows=102777 loops=1)
   Hash Cond: (field_instances.form_instance_id = form_instances.id)
   ->  Bitmap Heap Scan on field_instances  (cost=29232.57..152163.82 rows=531718 width=25) (actual time=64660.000..72800.000 rows=526842 loops=1)
         Recheck Cond: ((field_id)::text = ANY ('{Book_EstimatedDueDate,H_SubmittedDate,H_Ccode,miscarriage,miscarriage_of_multiple,stillbirth,AP_IUFD_of_multiple,maternal_death,birth_includes_transport,newborn_death,H_Pid,H_Mid1,H_Mid2,H_Mid3}'::text[]))
         ->  Bitmap Index Scan on index_field_instances_on_field_id  (cost=0.00..29099.64 rows=531718 width=0) (actual time=64630.000..64630.000 rows=594515 loops=1)
               Index Cond: ((field_id)::text = ANY ('{Book_EstimatedDueDate,H_SubmittedDate,H_Ccode,miscarriage,miscarriage_of_multiple,stillbirth,AP_IUFD_of_multiple,maternal_death,birth_includes_transport,newborn_death,H_Pid,H_Mid1,H_Mid2,H_Mid3}'::text[]))
   ->  Hash  (cost=5025.54..5025.54 rows=3388 width=8) (actual time=980.000..980.000 rows=10457 loops=1)
         ->  Bitmap Heap Scan on form_instances  (cost=90.99..5025.54 rows=3388 width=8) (actual time=10.000..950.000 rows=10457 loops=1)
               Recheck Cond: (((form_id)::text = 'W30L'::text) AND ((workflow_state)::text = 'DRqueued'::text))
               ->  Bitmap Index Scan on form_id_and_workflow_state  (cost=0.00..90.14 rows=3388 width=0) (actual time=0.000..0.000 rows=10457 loops=1)
                     Index Cond: (((form_id)::text = 'W30L'::text) AND ((workflow_state)::text = 'DRqueued'::text))
 Total runtime: 75080.000 ms

# \d form_instances                                        Table "public.form_instances"     Column      |            Type             |                          Modifiers                          
-----------------+-----------------------------+-------------------------------------------------------------
 id              | integer                     | not null default nextval('form_instances_id_seq'::regclass)
 form_id         | character varying(255)      | 
 created_at      | timestamp without time zone | 
 updated_at      | timestamp without time zone | 
 created_by_id   | integer                     | 
 updated_by_id   | integer                     | 
 workflow        | character varying(255)      | 
 workflow_state  | character varying(255)      | 
 validation_data | text                        | 
Indexes:
    "form_instances_pkey" PRIMARY KEY, btree (id)
    "form_id_and_workflow_state" btree (form_id, workflow_state)
    "index_form_instances_on_form_id" btree (form_id)
    "index_form_instances_on_workflow_state" btree (workflow_state)

# \d field_instances
                                        Table "public.field_instances"
      Column      |            Type             |                          Modifiers                           
------------------+-----------------------------+--------------------------------------------------------------
 id               | integer                     | not null default nextval('field_instances_id_seq'::regclass)
 form_instance_id | integer                     | 
 created_at       | timestamp without time zone | 
 updated_at       | timestamp without time zone | 
 created_by_id    | integer                     | 
 updated_by_id    | integer                     | 
 field_id         | character varying(255)      | 
 answer           | text                        | 
 state            | character varying(255)      | 
 explanation      | text                        | 
 idx              | integer                     | not null default 0
Indexes:
    "field_instances_pkey" PRIMARY KEY, btree (id)
    "field_instances__lower_answer" btree (lower(answer))
    "index_field_instances_on_answer" btree (answer)
    "index_field_instances_on_field_id" btree (field_id)
    "index_field_instances_on_field_id_and_answer" btree (field_id, answer)
    "index_field_instances_on_form_instance_id" btree (form_instance_id)
    "index_field_instances_on_idx" btree (idx)

Ответы [ 2 ]

1 голос
/ 25 июня 2011

Я не уверен, откуда взялись числа в вашем резюме, потому что второй опубликованный план запроса выводит 102777 строк, а первый выводит 2399 строк.Это в 43 раза больше строк, поэтому тот факт, что выбирается совершенно другой план запроса, неудивителен.Что касается того, почему разница во времени выполнения даже больше, чем это, оптимизатор делает умеренную ошибку в оценке чувствительности фильтров form_id и workflow_state.Возможно, вы захотите увеличить значение default_statistics_target для этой базы данных и снова запустить ANALYZE, что особенно верно, если вы используете PostgreSQL 8.3, где значение по умолчанию довольно низкое.См. Настройка сервера PostgreSQL для получения дополнительной информации об этом параметре.

Вполне возможно, что разница между ними настолько велика просто потому, что все данные, необходимые для ответа на маленький запрос, уже находятсяв памяти, в то время как больший требует больше доступа к диску для ответа.Выполнение каждого запроса более одного раза может пролить некоторый свет на улучшение времени выполнения после считывания данных в кэш.REINDEX, который вы сделали, мог бы сжать индекс настолько, что он поместился бы в кеш в обоих случаях, таким образом решив проблему на данный момент.Этот индекс может снова «раздуться».

1 голос
/ 22 июня 2011

Ранее комментарий, но, поскольку он, похоже, решил проблему, я перейду к фактическому ответу.

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

Так что вы можете vacuum full analyze;

Кроме того, другие команды, которые могут существенно помочь, включаютreindex и / или cluster.

OP указали, что vacuum не помогло, но reindex помогло.

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