производительность postgres_fdw низкая

12

Следующий запрос на иностранном языке занимает около 5 секунд для выполнения на 3,2 миллиона строк:

SELECT x."IncidentTypeCode", COUNT(x."IncidentTypeCode") 
FROM "IntterraNearRealTimeUnitReflexes300sForeign" x 
WHERE x."IncidentDateTime" >= '05/01/2016' 
GROUP BY x."IncidentTypeCode" 
ORDER BY 1;

Когда я выполняю тот же запрос в обычной таблице, он возвращается через 0,6 секунды. Планы выполнения довольно разные:

Нормальная таблица

Sort  (cost=226861.20..226861.21 rows=4 width=4) (actual time=646.447..646.448 rows=7 loops=1) 
  Sort Key: "IncidentTypeCode" 
  Sort Method: quicksort  Memory: 25kB 
  -> HashAggregate (cost=226861.12..226861.16 rows=4 width=4) (actual  time=646.433..646.434 rows=7 loops=1)
     Group Key: "IncidentTypeCode"
     -> Bitmap Heap Scan on "IntterraNearRealTimeUnitReflexes300s" x  (cost=10597.63..223318.41 rows=708542 width=4) (actual time=74.593..342.110 rows=709376 loops=1) 
        Recheck Cond: ("IncidentDateTime" >= '2016-05-01 00:00:00'::timestamp without time zone) 
        Rows Removed by Index Recheck: 12259 
        Heap Blocks: exact=27052 lossy=26888
        -> Bitmap Index Scan on idx_incident_date_time_300  (cost=0.00..10420.49 rows=708542 width=0) (actual time=69.722..69.722 rows=709376 loops=1) 
           Index Cond: ("IncidentDateTime" >= '2016-05-01 00:00:00'::timestamp without time zone) 

Planning time: 0.165 ms 
Execution time: 646.512 ms

Иностранный стол

Sort  (cost=241132.04..241132.05 rows=4 width=4) (actual time=4782.110..4782.112 rows=7 loops=1)   
  Sort Key: "IncidentTypeCode" 
  Sort Method: quicksort  Memory: 25kB
  -> HashAggregate  (cost=241131.96..241132.00 rows=4 width=4) (actual time=4782.097..4782.100 rows=7 loops=1)
     Group Key: "IncidentTypeCode"
     -> Foreign Scan on "IntterraNearRealTimeUnitReflexes300sForeign" x  (cost=10697.63..237589.25 rows=708542 width=4) (actual time=1.916..4476.946 rows=709376 loops=1) 

Planning time: 1.413 ms 
Execution time: 4782.660 ms

Я думаю, что я плачу высокую цену за GROUP BYпредложение, которое не передается на сторонний сервер, когда я EXPLAIN VERBOSE:

SELECT
    "IncidentTypeCode"
FROM
    PUBLIC ."IntterraNearRealTimeUnitReflexes300s"
WHERE
    (
        (
            "IncidentDateTime" >= '2016-05-01 00:00:00' :: TIMESTAMP WITHOUT TIME ZONE
        )
    )

Это возвращает 700 тыс. Строк. Есть ли способ обойти это?

Я потратил много времени, читая эту страницу документации вчера, и подумал, что нашел свой ответ с установкой use_remote_estimateна true, но это не имело никакого эффекта.

У меня есть доступ к стороннему серверу для создания объектов, если это необходимо. Значение метки времени в WHEREпредложении может быть любым; он не приходит из списка предопределенных значений.

J-DAWG
источник
3
В 9.6 есть некоторые улучшения, которые могут быть интересны: wiki.postgresql.org/wiki/NewIn96#postgres_fdw
Джек говорит, что попробуйте topanswers.xyz
Когда вы говорите, что обычная таблица против чужой, вы используете одну и ту же таблицу (локально и удаленно) или фактически разные таблицы (она читается так, как будто они есть), если они различаются, проверьте индексацию на удаленном сервере и убедитесь, что они одинаковы. как вы , кажется, читает совершенно разные источники информации , IntterraNearRealTimeUnitReflexes300sForeignпротив IntterraNearRealTimeUnitReflexes300sи idx_incident_date_time_300 я полагаю , что 300S из них то же самое, но это может быть стоит проверить , если idx_incident_date_time_300существует индекс на внешнем сервере
Ste ДФ
2
Насколько я понимаю, агрегаты (COUNT) не отправляются на удаленный сервер, что объясняет длительное время запроса. Кажется, эта функция появится в pg 10 - depesz.com/2016/10/25/…
Джером ВАГНЕР
@JeromeWAGNER - Великолепно
J-DawG

Ответы:

7

Если вы используете use_remote_estimate, обязательно запустите ANALYZE чужую таблицу (я вижу, что оценки довольно близки с возвращенными значениями, вы, вероятно, сделали это) Кроме того, улучшения версии не доступны в версии <9.5. Я также предполагаю, что у вас есть такая же структура таблиц на удаленном сервере (включая индексы). Если требуется растровое изображение из-за низкой мощности, он не будет использовать индекс из-за ограничений механизма push-down. Возможно, вы захотите уменьшить количество возвращаемых строк для принудительного сканирования индекса BTREE ( диапазоны временных отметок). К сожалению, не существует чистого способа избежать SeqScan на удаленном сервере, если фильтр возвращает + 10% строк таблицы (может изменить этот процент, если планировщик считает, что сканирование всей таблицы дешевле, чем чтение с поиском). Если вы используете SSD, вы, вероятно, найдете полезную настройку random_page_cost).

Вы можете использовать CTE для изоляции поведения GROUP BY:

WITH atable AS (
    SELECT "IncidentTypeCode"
    FROM PUBLIC ."IntterraNearRealTimeUnitReflexes300s"
    WHERE 
       ("IncidentDateTime" 
              BETWEEN '2016-05-01 00:00:00'::TIMESTAMP WITHOUT TIME ZONE 
                  AND '2016-05-02 00:00:00'::TIMESTAMP WITHOUT TIME ZONE)
)
SELECT atable."IncidentTypeCode", COUNT(atable.IncidentTypeCode) 
FROM atable
GROUP BY atable."IncidentTypeCode" 
ORDER BY atable."IncidentTypeCode";
3manuek
источник
1
Производительность была одинаковой при использовании CTE. Попробую настройки random_page_cost, хотя. Благодарность!
J-DawG