PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Изберете първия ред във всяка група GROUP BY?

DISTINCT ON обикновено е най-простият и бърз за това в PostgreSQL .
(За оптимизиране на производителността за определени натоварвания вижте по-долу.)

SELECT DISTINCT ON (customer)
       id, customer, total
FROM   purchases
ORDER  BY customer, total DESC, id;

Или по-кратко (ако не е толкова ясно) с поредни номера на изходните колони:

SELECT DISTINCT ON (2)
       id, customer, total
FROM   purchases
ORDER  BY 2, 3 DESC, 1;

Ако total може да бъде NULL (в никакъв случай няма да навреди, но ще искате да съпоставите съществуващите индекси):

...
ORDER  BY customer, total DESC NULLS LAST, id;

Основни точки

DISTINCT ON е PostgreSQL разширение на стандарта (където само DISTINCT като цяло SELECT списъкът е дефиниран).

Избройте произволен брой изрази в DISTINCT ON клауза, комбинираната стойност на ред дефинира дубликати. Ръководството:

Очевидно два реда се считат за различни, ако се различават в поне една стойност на колоната. Нулевите стойности се считат за равни в това сравнение.

Удебелен акцент мой.

DISTINCT ON може да се комбинира с ORDER BY . Водещи изрази в ORDER BY трябва да е в набора от изрази в DISTINCT ON , но можете свободно да пренареждате реда между тях. Пример.
Можете да добавите допълнителни изрази към ORDER BY за да изберете конкретен ред от всяка група връстници. Или, както се казва в ръководството:

DISTINCT ON израз(ите) трябва да съвпадат с най-лявото ORDER BY израз(и). ORDER BY клаузата обикновено съдържа допълнителен(и) израз(и), които определят желания приоритет на редовете във всеки DISTINCT ON група.

Добавих id като последен елемент за прекъсване на връзките:
"Изберете реда с най-малкия id от всяка група, споделяща най-висок total ."

За да подредите резултатите по начин, който не е съгласен с реда на сортиране, определящ първия за група, можете да вмъкнете над заявката във външна заявка с друга ORDER BY . Пример.

Ако total може да бъде NULL, вие най-вероятно искате реда с най-голямата стойност, различна от нула. Добавете NULLS LAST като демонстрирано. Вижте:

  • Сортиране по колона ASC, но първо NULL стойности?

SELECT списъка не е ограничен от изрази в DISTINCT ON или ORDER BY по всякакъв начин. (Не е необходимо в простия случай по-горе):

  • Не е нужно включва някой от изразите в DISTINCT ON или ORDER BY .

  • Вие можете включете всеки друг израз в SELECT списък. Това е важно за замяната на много по-сложни заявки с подзаявки и агрегатни/прозоречни функции.

Тествах с Postgres версии 8.3 – 13. Но функцията е налице поне от версия 7.1, така че по принцип винаги.

Индекс

Перфектният индексът за горната заявка ще бъде индекс с няколко колони, обхващащ всичките три колони в съвпадаща последователност и със съответстващ ред на сортиране:

CREATE INDEX purchases_3c_idx ON purchases (customer, total DESC, id);

Може да е твърде специализиран. Но използвайте го, ако производителността на четене за конкретната заявка е от решаващо значение. Ако имате DESC NULLS LAST в заявката, използвайте същото в индекса, така че редът на сортиране да съвпада и индексът да е приложим.

Ефективност/Оптимизация на производителността

Претеглете разходите и ползите, преди да създадете персонализирани индекси за всяка заявка. Потенциалът на горния индекс до голяма степен зависи от разпределението на данните .

Индексът се използва, защото предоставя предварително сортирани данни. В Postgres 9.2 или по-нова версия, заявката може да се възползва и от сканиране само на индекс ако индексът е по-малък от основната таблица. Индексът обаче трябва да бъде сканиран изцяло.

Заняколко редове на клиента (висока мощност в колона customer ), това е много ефективно. Още повече, ако все пак имате нужда от сортиран изход. Ползата се свива с нарастващ брой редове на клиент.
В идеалния случай имате достатъчно work_mem да обработи включената стъпка на сортиране в RAM и да не се разлее на диск. Но обикновено се задава work_mem също високо може да има неблагоприятни последици. Помислете за SET LOCAL за изключително големи запитвания. Намерете колко ви трябва с EXPLAIN ANALYZE . Споменаване на „Диск: " в стъпката за сортиране показва необходимостта от повече:

  • Конфигурационен параметър work_mem в PostgreSQL на Linux
  • Оптимизирайте простата заявка, като използвате ПОРЪЧАЙТЕ ПО дата и текст

Замного редове на клиента (ниска мощност в колона customer ), разхлабено сканиране на индекс (известен още като „пропускане на сканиране“) би било (много) по-ефективно, но това не се прилага до Postgres 14. (Разработва се реализация за сканиране само с индекс за Postgres 15. Вижте тук и тук.)
За Postgres 15. сега има по-бързи техники за заявка да замести това. По-специално, ако имате отделна маса с уникални клиенти, което е типичният случай на употреба. Но също и ако не го направите:

  • SELECT DISTINCT е по-бавен от очакваното в моята таблица в PostgreSQL
  • Оптимизиране на заявката GROUP BY за извличане на последния ред на потребител
  • Оптимизиране на груповата максимална заявка
  • Запитване за последните N свързани реда на ред

Референтни показатели

Вижте отделен отговор.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Barman Cloud – Част 2:Облачно архивиране

  2. Разгръщане и конфигуриране на PostgreSQL с Puppet

  3. SQL Between клауза с колони с низове

  4. Не мога да намеря клиентската библиотека на PostgreSQL (libpq)

  5. Разгръщане на клъстер в множество облаци на PostgreSQL