Эффективный выбор отличного (a, b) из большой таблицы - PullRequest
1 голос
/ 16 мая 2019

У меня есть таблица с 54 миллионами строк в БД Postgres 9.6, и я хотел бы найти все отдельные пары из двух столбцов (таких значений около 4 миллионов).У меня есть индекс по двум интересующим колонкам:

create index ab_index on tbl (a, b)

Какой самый эффективный способ получить такие пары?Я пробовал:

select a,b
from tbl
where a>$previouslargesta
group by a,b
order by a,b
limit 1000

А также:

select distinct(a,b)
from tbl
where a>previouslargesta
order by a,b
limit 1000

Также этот рекурсивный запрос:

with recursive t AS (
  select min(a) AS a from tbl
  union all
  select (select min(a) from tickets where a > t.a)
  FROM t)
select a FROM t

Но все это неоправданно.

Есть ли более быстрый способ получить эту информацию?

Ответы [ 2 ]

1 голос
/ 20 мая 2019

В вашей таблице 54 миллиона строк и ...

существует около 4 миллионов таких значений

7,4% всех строк - это высокий процент, индекс в большинстве случаев может помочь только с помощью предварительно отсортированных данных, в идеале при сканировании только по индексу . Существуют более сложные методы для меньших наборов результатов (см. Ниже), и есть намного более быстрых способов подкачки, которые возвращают намного меньше строк за раз (см. Ниже), но для общего случая обычная DISTINCT может быть одним из самых быстрых:

SELECT DISTINCT a, b  -- *no* parentheses
FROM   tbl;
-- ORDER  BY a, b      -- ORDER BY wasn't not mentioned as requirement ...

Не путайте это с DISTINCT ON, для которого потребуются скобки. См:

Индекс B-дерева ab_index, установленный на (a, b), уже является лучшим индексом для этого. Тем не менее, он должен быть отсканирован полностью. Задача состоит в том, чтобы иметь достаточно work_mem для обработки всего в RAM . При стандартных настройках он занимает не менее 1831 МБ на диске, как правило, больше с некоторым раздуванием. Если вы можете себе это позволить, запустите запрос с настройкой work_mem 2 ГБ (или более) в своем сеансе. См:

SET work_mem = '2 GB';
SELECT DISTINCT a, b ...
RESET work_mem;

Таблица только для чтения помогает. В противном случае вам понадобятся достаточно агрессивные настройки VACUUM, чтобы разрешить сканирование только по индексу . И еще немного ОЗУ поможет (с соответствующими настройками) сохранить индекс в кэше.

Также обновите до последней версии Postgres (11.3 на момент написания). Для больших данных было много улучшений.

* * Пейджинг тысяча сорок-девять

Если вы хотите добавить paging , как указано в вашем примере запроса, срочно рассмотрите Сравнение значений ROW . См:

SELECT DISTINCT a, b
FROM   tbl
<b>WHERE  (a, b) > ($previous_a, $previous_b)   -- !!!</b>
ORDER  BY a, b
LIMIT  1000;

рекурсивный CTE

Это также может быть или не быть быстрее для общего большого запроса. Для небольшого подмножества оно становится намного более привлекательным:

WITH RECURSIVE cte AS (
   (  -- parentheses required du to LIMIT 1
   SELECT a, b
   FROM   tbl
   <b>WHERE  (a, b) > ($previous_a, $previous_b)</b>   -- !!!
   ORDER  BY a, b
   LIMIT  1
   )
   UNION ALL
   SELECT x.a, x.b
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT t.a, t.b
      FROM   tbl t
      WHERE  (t.a, t.b) > (c.a, c.b) -- lateral reference
      ORDER  BY t.a, t.b
      LIMIT  1
      ) x
   )
TABLE cte
LIMIT 1000;

Это может отлично использовать ваш индекс и должно быть так же быстро, как он получает .

Дальнейшее чтение:

Для многократного использования и без или с небольшой загрузкой записи в таблицу рассмотрите MATERIALIZED VIEW, основанный на одном из вышеупомянутых запросов - для гораздо более высокой производительности чтения.

0 голосов
/ 30 мая 2019

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

получить отличную А во временную точку

получить четкий B в темп б

пересечь временные значения a и b в декартову временную шкалу

ранжировать абалл (опционально)

создать представление myview как выберите top 1 a, b из таблицы tbl (your_main_table)

присоединиться к temp abALL с myview в temp abCLEAN

ранг abCLEAN здесь, если у вас нет ранга выше

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