#sql #postgresql #optimization #psql
#sql #postgresql #оптимизация #psql
Вопрос:
У меня есть SQL-запрос (упрощенный из реального использования):
SELECT MIN(cola), colb FROM tbl GROUP BY colb;
Но на самом деле мне не нужно минимальное значение — подойдет любое значение cola — оно используется только для отображения примерного значения из группы.
На данный момент PG должен выполнить группу, а затем отсортировать каждую группу по cola, чтобы найти минимальное значение в группе, но это медленно, потому что в каждой группе много записей.
Есть ли у Postgres какой-то FIRST(cola) или ANY(cola), который просто возвращает любую cola, которую он видит первой (как это делает MySQL, когда вы не используете агрегатную функцию), или без необходимости сортировать / считывать cola из каждой строки?
Ответ №1:
Я думаю, что использование DISTINCT ON()
без order by приведет к тому, что вам нужно:
SELECT DISTINCT ON (ColB) ColA, ColB
FROM tbl;
DISTINCT ON (выражение [, …] ) сохраняет только первую строку каждого набора строк, где заданные выражения оцениваются как равные. Выражения DISTINCT ON интерпретируются с использованием тех же правил, что и для ORDER BY (см. Выше). Обратите внимание, что «первая строка» каждого набора непредсказуема, если не используется ORDER BY для обеспечения того, чтобы нужная строка отображалась первой.
Однако, не имея примеров данных для работы, я не могу сравнить, будет ли это превосходить using MIN
или любую другую агрегатную функцию.
Ответ №2:
Это утверждение:
На данный момент PG должен выполнить группу, а затем отсортировать каждую группу по cola, чтобы найти минимальное значение в группе, но это медленно, потому что в каждой группе много записей.
Может логически описывать, что делает Postgres, но не объясняет, что происходит на самом деле.
Postgres — как и в любой базе данных, с которой я знаком, — сохранит «регистр» для минимального значения. По мере поступления новых данных значение в следующей строке сравнивается с минимальным. Если новое значение меньше, оно будет скопировано. Это, кстати, whay min()
, max()
, avg()
, и count()
все быстрее, чем count(distinct)
. Для последнего необходимо поддерживать список значений внутри группы.
distinct on
Подход может быть быстрее, чем group by
. Причина, однако, не в том, что компонент database engine сортирует все значения для заданного colb
, чтобы получить минимум.
Комментарии:
1. Это правда. Я об этом не подумал, и это определенно происходит, когда нет предложения group by . Сохраняет ли он регистр для каждой ГРУППЫ с помощью colb? т.е.. поддерживает ли он регистр MIN(cola) для каждого возможного значения colb?
2. Я предполагаю, что это так. Это была старая технология, когда я начал работать с реляционными базами данных . , , о, я не хочу признавать, сколько лет назад.
Ответ №3:
Попробуйте использовать выборку первой строки в конце вашего sql:
http://www.postgresql.org/docs/8.1/static/sql-fetch.html
SELECT MIN(cola), colb
FROM tbl
GROUP BY colb
FETCH FIRST ROW only;
Ответ №4:
Вдохновленный ответом Гарета выше:
; WITH C as (SELECT *, ROW_NUMBER() OVER (PARTITION BY ColB) as rn FROM tbl)
SELECT *
FROM c
WHERE rn = 1
Не уверен, что он будет работать лучше хуже, чем MIN().