2017-01-25 4 views
0

У меня есть этот запрос PostgresPostgres не Использование другого плана запроса для высших смещений

explain SELECT "facilities".* FROM "facilities" INNER JOIN 
resource_indices ON resource_indices.resource_id = facilities.uuid WHERE 
(client_id IS NULL OR (client_tag=NULL AND client_id=7)) 
AND (ARRAY['country:india']::varchar[] && resource_indices.tags) 
AND "facilities"."is_listed" = 't' 
ORDER BY resource_indices.name LIMIT 11 OFFSET 100; 

Обратите внимание на смещение. Когда смещение меньше 200, оно использует индекс и отлично работает. План запроса для этого как следовать

   QUERY PLAN 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=23416.57..24704.45 rows=11 width=1457) (actual time=41.951..43.035 rows=11 loops=1) 
    -> Nested Loop (cost=0.71..213202.15 rows=1821 width=1457) (actual time=2.107..43.007 rows=211 loops=1) 
     -> Index Scan using index_resource_indices_on_name on resource_indices (cost=0.42..190226.95 rows=12460 width=28) (actual time=2.096..40.790 rows=408 loops=1) 
       Filter: ('{country:india}'::character varying[] && tags) 
       Rows Removed by Filter: 4495 
     -> Index Scan using index_facilities_on_uuid on facilities (cost=0.29..1.83 rows=1 width=1445) (actual time=0.005..0.005 rows=1 loops=408) 
       Index Cond: (uuid = resource_indices.resource_id) 
       Filter: ((client_id IS NULL) AND is_listed) 
Planning time: 1.259 ms 
Execution time: 43.121 ms 
(10 rows) 

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

  QUERY PLAN 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=34508.62..34508.65 rows=11 width=1457) (actual time=136.288..136.291 rows=11 loops=1) 
    -> Sort (cost=34507.62..34512.18 rows=1821 width=1457) (actual time=136.224..136.268 rows=411 loops=1) 
     Sort Key: resource_indices.name 
     Sort Method: top-N heapsort Memory: 638kB 
     -> Hash Join (cost=29104.96..34419.46 rows=1821 width=1457) (actual time=23.885..95.099 rows=6518 loops=1) 
       Hash Cond: (facilities.uuid = resource_indices.resource_id) 
       -> Seq Scan on facilities (cost=0.00..4958.39 rows=33790 width=1445) (actual time=0.010..48.732 rows=33711 loops=1) 
        Filter: ((client_id IS NULL) AND is_listed) 
        Rows Removed by Filter: 848 
       -> Hash (cost=28949.21..28949.21 rows=12460 width=28) (actual time=23.311..23.311 rows=12601 loops=1) 
        Buckets: 2048 Batches: 1 Memory Usage: 814kB 
        -> Bitmap Heap Scan on resource_indices (cost=1048.56..28949.21 rows=12460 width=28) (actual time=9.369..18.710 rows=12601 loops=1) 
          Recheck Cond: ('{country:india}'::character varying[] && tags) 
          Heap Blocks: exact=7334 
          -> Bitmap Index Scan on index_resource_indices_on_tags (cost=0.00..1045.45 rows=12460 width=0) (actual time=7.680..7.680 rows=13889 loops=1) 
           Index Cond: ('{country:india}'::character varying[] && tags) 
Planning time: 1.408 ms 
Execution time: 136.465 ms 
(18 rows) 

Как это разрешить? Спасибо

ответ

1

Это неизбежно, потому что нет другого способа реализовать LIMIT 10 OFFSET 10000, но для извлечения первых 10010 строк и выброса всех, кроме последних 10. Это связано с тем, что все увеличивается с увеличением смещения.

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

OFFSET является злым, и вы должны избегать его в большинстве случаев. Прочитайте what Markus Winand has to say about this topic, в частности, как разбивать результирующие наборы без OFFSET.