PostgreSQL увеличивает группу более чем на 30 миллионов строк - PullRequest
0 голосов
/ 10 ноября 2018

Есть ли способ увеличить скорость динамической группы по запросу? У меня есть таблица с 30 миллионами строк.

create table if not exists tb
(
    id serial not null constraint tb_pkey primary key,
    week integer,
    month integer,
    year integer,
    starttime varchar(20),
    endtime varchar(20),
    brand smallint,
    category smallint,
    value real
);

На приведенный ниже запрос уходит 8,5 секунды.

SELECT category from tb group by category

Есть ли способ увеличить скорость. Я пытался с и без индекса.

1 Ответ

0 голосов
/ 11 ноября 2018

Для этого точного запроса, не совсем; выполнение этой операции требует сканирования каждой строки. Обойти это невозможно.

Но если вы хотите быстро получить набор уникальных категорий и у вас есть индекс для этого столбца, вы можете использовать вариант примера WITH RECURSIVE, показанный здесь при редактировании вопроса ( посмотрите в конец вопроса):

Подсчет отдельных строк с использованием рекурсивного cte по непонятному индексу

Вам нужно будет изменить его, чтобы он возвращал набор уникальных значений вместо их подсчета, но это выглядит как простое изменение:

testdb=# create table tb(id bigserial, category smallint);
CREATE TABLE
testdb=# insert into tb(category) select 2 from generate_series(1, 10000)
testdb-# ;
INSERT 0 10000
testdb=# insert into tb(category) select 1 from generate_series(1, 10000);
INSERT 0 10000
testdb=# insert into tb(category) select 3 from generate_series(1, 10000);
INSERT 0 10000
testdb=# create index on tb(category);
CREATE INDEX
testdb=# WITH RECURSIVE cte AS
  (
     (SELECT category
      FROM tb
      WHERE category >= 0
      ORDER BY 1
      LIMIT 1)
   UNION ALL SELECT
     (SELECT category
      FROM tb
      WHERE category > c.category
      ORDER BY 1
      LIMIT 1)
   FROM cte c
   WHERE category IS NOT NULL)
SELECT category
FROM cte
WHERE category IS NOT NULL;
 category 
----------
        1
        2
        3
(3 rows)

А вот и EXPLAIN ANALYZE:

    QUERY PLAN                                                                         
-----------------------------------------------------------------------------------------------------------------------------------------------------------
 CTE Scan on cte  (cost=40.66..42.68 rows=100 width=2) (actual time=0.057..0.127 rows=3 loops=1)
   Filter: (category IS NOT NULL)
   Rows Removed by Filter: 1
   CTE cte
     ->  Recursive Union  (cost=0.29..40.66 rows=101 width=2) (actual time=0.052..0.119 rows=4 loops=1)
           ->  Limit  (cost=0.29..0.33 rows=1 width=2) (actual time=0.051..0.051 rows=1 loops=1)
                 ->  Index Only Scan using tb_category_idx on tb tb_1  (cost=0.29..1363.29 rows=30000 width=2) (actual time=0.050..0.050 rows=1 loops=1)
                       Index Cond: (category >= 0)
                       Heap Fetches: 1
           ->  WorkTable Scan on cte c  (cost=0.00..3.83 rows=10 width=2) (actual time=0.015..0.015 rows=1 loops=4)
                 Filter: (category IS NOT NULL)
                 Rows Removed by Filter: 0
                 SubPlan 1
                   ->  Limit  (cost=0.29..0.36 rows=1 width=2) (actual time=0.016..0.016 rows=1 loops=3)
                         ->  Index Only Scan using tb_category_idx on tb  (cost=0.29..755.95 rows=10000 width=2) (actual time=0.015..0.015 rows=1 loops=3)
                               Index Cond: (category > c.category)
                               Heap Fetches: 2
 Planning time: 0.224 ms
 Execution time: 0.191 ms
(19 rows)

Количество циклов, которое он должен выполнить для узла сканирования WorkTable, будет равно количеству уникальных категорий, которые у вас есть плюс одна, поэтому он должен оставаться очень быстрым, скажем, до сотен уникальных значений.

Другой способ, которым вы можете воспользоваться, - это добавить еще одну таблицу, в которой вы просто храните уникальные значения tb.category, и логика приложения проверяет эту таблицу и вставляет их значение при обновлении / вставке этого столбца. Это также может быть сделано на стороне базы данных с помощью триггеров; это решение также обсуждается в ответах на связанный вопрос.

...