Skip to content

Медленный SELECT при JOIN'е по ключу партиционирования #188

@JanMihail

Description

@JanMihail

Описание проблемы

Есть 2 таблицы со следующей структурой:

CREATE TABLE public.valuation (
    id bigserial NOT NULL,
    cost numeric(20,6) NULL,
    discount numeric(20,6) NULL,
    cost_with_vat numeric(20,6) NULL,
    vat_sum numeric(20,6) NULL,
    vat_rate_code text NULL,
    currency_code text NOT NULL,
    CONSTRAINT valuation_pkey PRIMARY KEY (id)
);

CREATE TABLE public.orders (
    id uuid NOT NULL DEFAULT gen_random_uuid(),
    "number" text NOT NULL,
    paid_online_on_delivery_id int8 NULL,
    CONSTRAINT orders_pkey PRIMARY KEY (id)
);

CREATE UNIQUE INDEX udx_orders_number ON public.orders USING btree (number);

Связь

  valuation.id --> orders.paid_online_on_delivery_id (1 к 1)

Количественные показатели таблиц

SELECT
    COUNT(*),
    MIN(id),
    MAX(id)
FROM
    valuation;
count min max
919648130 2 3581811089
SELECT
    COUNT(*)
FROM
    orders;
count
84808668

Таблица valuation разбита на партиции по диапазонам. Ключ партиционирования - id. Всего 100 партиций.

SELECT 
    *
from
    pathman_partition_list
where
    parent = 'valuation'::regclass

Результат запроса: https://gist.github.com/JanMihail/fd45cfef5ac24fe960e91a92c648b266#file-partitions-csv

Выполняю такой запрос

EXPLAIN (ANALYZE, BUFFERS)
SELECT
    o.number,
    v.id,
    v.cost
FROM
    orders o
JOIN valuation v ON v.id = o.paid_online_on_delivery_id
WHERE
    o.number = '1104290452'

Результат

number id cost
1104290452 3512174003 0.000000
Nested Loop  (cost=0.99..17.04 rows=1 width=14) (actual time=0.130..0.131 rows=1 loops=1)
  Buffers: shared read=9 written=1
  ->  Index Scan using udx_orders_number on orders o  (cost=0.57..8.59 rows=1 width=18) (actual time=0.059..0.060 rows=1 loops=1)
        Index Cond: (number = '1104290452'::text)
        Buffers: shared read=5
  ->  Custom Scan (RuntimeAppend)  (cost=0.43..8.44 rows=1 width=23) (actual time=0.049..0.049 rows=1 loops=1)
        Prune by: (o.paid_online_on_delivery_id = v.id)
        Buffers: shared read=4 written=1
        ->  Index Scan using valuation_3513_pkey on valuation_3513 v_1  (cost=0.42..8.44 rows=1 width=13) (actual time=0.048..0.048 rows=1 loops=1)
              Index Cond: (id = o.paid_online_on_delivery_id)
              Buffers: shared read=4 written=1
Planning time: 12748.652 ms
Execution time: 0.198 ms

Из результатов вижу, что на планирование запроса ушло целых 12 секунд 748 миллисекунд.

Теперь я пробую сделать то же самое, но указываю в запросе конкретную партицию valuation_3513 из предыдущего EXPLAIN и смотрю на результаты.

EXPLAIN (ANALYZE, BUFFERS)
SELECT
    o.number,
    v.cost
FROM
    orders o
JOIN partitions.valuation_3513 v ON v.id = o.paid_online_on_delivery_id
WHERE
    o.number = '1104290452'

Результат

number id cost
1104290452 3512174003 0.000000
Nested Loop  (cost=0.99..17.03 rows=1 width=15) (actual time=0.034..0.035 rows=1 loops=1)
  Buffers: shared hit=9
  ->  Index Scan using udx_orders_number on orders o  (cost=0.57..8.59 rows=1 width=18) (actual time=0.022..0.023 rows=1 loops=1)
        Index Cond: (number = '1104290452'::text)
        Buffers: shared hit=5
  ->  Index Scan using valuation_3513_pkey on valuation_3513 v  (cost=0.42..8.44 rows=1 width=13) (actual time=0.010..0.010 rows=1 loops=1)
        Index Cond: (id = o.paid_online_on_delivery_id)
        Buffers: shared hit=4
Planning time: 0.351 ms
Execution time: 0.083 ms

Время планирования резко уменьшилось до 0.351 миллисекунд. Получается, что в первом запросе 12 секунд потратилось на поиск нужной партиции. Тогда я делаю следующий запрос.

EXPLAIN (ANALYZE, BUFFERS)
SELECT
    id,
    cost
FROM  
    valuation
where
    id = 3512174003

Результат

id cost
3512174003 0.000000
Append  (cost=0.42..8.44 rows=1 width=12) (actual time=0.016..0.017 rows=1 loops=1)
  Buffers: shared hit=4
  ->  Index Scan using valuation_3513_pkey on valuation_3513  (cost=0.42..8.44 rows=1 width=13) (actual time=0.016..0.016 rows=1 loops=1)
        Index Cond: (id = '3512174003'::bigint)
        Buffers: shared hit=4
Planning time: 0.128 ms
Execution time: 0.029 ms

При таком запросе на выбор нужной партиции затрачено всего 0.128 миллисекунд. Почему при JOIN по id (ключ партиционирования) время планирования резко подскакивает до 12 секунд? Что можно сделать, чтобы время планирования стало приемлемым?

Что я пытался делать:

  1. VACUUM ANALYZE всех партиций.
  2. REINDEX всех партиций.
  3. merge_range_partitions первых 80 партиций. По итогу оставалось 20 партиций. Результаты чуть лучше, но всё равно время планирования остаётся в пределах 4-7 секунд.
  4. Увеличение параметра shared_buffers и перезапуск сервера Postgres.

Ничего из этого не дало мне нужного результата.
Прошу помогите мне решить проблему.

Environment

SELECT * FROM pg_extension

extname extowner extnamespace extrelocatable extversion extconfig extcondition
plpgsql 10 11 false 1.0
pg_repack 10 2200 false 1.4.4
pg_trgm 10 2200 true 1.3
pgcrypto 10 2200 true 1.3
uuid-ossp 10 2200 true 1.1
pg_pathman 2672077 2200 false 1.5 {47426753,47426764} {,}

SELECT version()

version
PostgreSQL 10.6 (Ubuntu 10.6-1.pgdg16.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609, 64-bit

SELECT pgpro_version()
SQL Error [42883]: ERROR: function pgpro_version() does not exist

SELECT pgpro_edition()
SQL Error [42883]: ERROR: function pgpro_edition() does not exist

SELECT get_pathman_lib_version()
SQL Error [42883]: ERROR: function get_pathman_lib_version() does not exist

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions