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

Заявка за последните N свързани реда на ред

Ако приемем поне Postgres 9.3.

Индекс

Първо, индекс с много колони ще помогне:

CREATE INDEX observations_special_idx
ON observations(station_id, created_at DESC, id)

created_at DESC е малко по-добре, но индексът все пак ще бъде сканиран назад с почти същата скорост без DESC .

Ако приемем created_at е дефиниран NOT NULL , в противен случай помислете за DESC NULLS LAST в индекс и заявка:

  • PostgreSQL сортиране по datetime asc, първо нула?

Последната колона id е полезно само ако получите сканиране само за индекс, което вероятно няма да работи, ако добавяте много нови редове постоянно. В този случай премахнете id от индекса.

По-проста заявка (все още бавна)

Опростете заявката си, вътрешният подселекция не помага:

SELECT id
FROM  (
  SELECT station_id, id, created_at
       , row_number() OVER (PARTITION BY station_id
                            ORDER BY created_at DESC) AS rn
  FROM   observations
  ) s
WHERE  rn <= #{n}  -- your limit here
ORDER  BY station_id, created_at DESC;

Би трябвало да е малко по-бързо, но все пак бавно.

Бърза заявка

  • Ако приемем, че имате относително малко станциите и относително много наблюдения на станция.
  • Приемаме също station_id идентификатор, дефиниран като NOT NULL .

Да бъдем наистина бързо, имате нужда от еквивалента на разхлабено сканиране на индекс (все още не е внедрен в Postgres). Свързан отговор:

  • Оптимизирайте заявката GROUP BY, за да извлечете последния запис на потребител

Ако имате отделна таблица с stations (което изглежда вероятно), можете да емулирате това с JOIN LATERAL (Postgres 9.3+):

SELECT o.id
FROM   stations s
CROSS  JOIN LATERAL (
   SELECT o.id
   FROM   observations o
   WHERE  o.station_id = s.station_id  -- lateral reference
   ORDER  BY o.created_at DESC
   LIMIT  #{n}  -- your limit here
   ) o
ORDER  BY s.station_id, o.created_at DESC;

Ако нямате таблица с stations , следващото най-добро нещо би било да създадете и поддържате такъв. Възможно е да добавите препратка към външен ключ, за да наложите релационната цялост.

Ако това не е опция, можете да дестилирате такава маса в движение. Простите опции биха били:

SELECT DISTINCT station_id FROM observations;
SELECT station_id FROM observations GROUP BY 1;

Но и двете ще се нуждаят от последователно сканиране и ще бъдат бавни. Накарайте Postgres да използва горния индекс (или всеки индекс на btree с station_id). като водеща колона) срекурсивен CTE :

WITH RECURSIVE stations AS (
   (                  -- extra pair of parentheses ...
   SELECT station_id
   FROM   observations
   ORDER  BY station_id
   LIMIT  1
   )                  -- ... is required!
   UNION ALL
   SELECT (SELECT o.station_id
           FROM   observations o
           WHERE  o.station_id > s.station_id
           ORDER  BY o.station_id
           LIMIT  1)
   FROM   stations s
   WHERE  s.station_id IS NOT NULL  -- serves as break condition
   )
SELECT station_id
FROM   stations
WHERE  station_id IS NOT NULL;      -- remove dangling row with NULL

Използвайте го като замяна за stations таблица в горната проста заявка:

WITH RECURSIVE stations AS (
   (
   SELECT station_id
   FROM   observations
   ORDER  BY station_id
   LIMIT  1
   )
   UNION ALL
   SELECT (SELECT o.station_id
           FROM   observations o
           WHERE  o.station_id > s.station_id
           ORDER  BY o.station_id
           LIMIT  1)
   FROM   stations s
   WHERE  s.station_id IS NOT NULL
   )
SELECT o.id
FROM   stations s
CROSS  JOIN LATERAL (
   SELECT o.id, o.created_at
   FROM   observations o
   WHERE  o.station_id = s.station_id
   ORDER  BY o.created_at DESC
   LIMIT  #{n}  -- your limit here
   ) o
WHERE  s.station_id IS NOT NULL
ORDER  BY s.station_id, o.created_at DESC;

Това все пак трябва да е по-бързо от това, което сте имали спорядък на величина .

SQL Fiddle тук (9.6)
db<>Fiddle тук



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. сериен в postgres се увеличава, въпреки че добавих на конфликт не прави нищо

  2. [Видео] Сила на индексиране в PostgreSQL

  3. Преобразуване на юлиански ден в дата в PostgreSQL

  4. Как да конфигурирам HikariCP за postgresql?

  5. Спрете (продължителното) изпълнение на SQL заявка в PostgreSQL, когато сесия или заявки вече не съществуват?