PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Kueri N baris terkait terakhir per baris

Dengan asumsi setidaknya Postgres 9.3.

Indeks

Pertama, indeks multikolom akan membantu:

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

created_at DESC sedikit lebih cocok, tetapi indeks masih akan dipindai mundur dengan kecepatan yang hampir sama tanpa DESC .

Dengan asumsi created_at didefinisikan NOT NULL , jika tidak, pertimbangkan DESC NULLS LAST dalam indeks dan permintaan:

  • Urutkan PostgreSQL berdasarkan datetime asc, null dulu?

Kolom terakhir id hanya berguna jika Anda hanya mendapatkan pemindaian indeks saja, yang mungkin tidak akan berfungsi jika Anda menambahkan banyak baris baru terus-menerus. Dalam hal ini, hapus id dari indeks.

Kueri yang lebih sederhana (masih lambat)

Sederhanakan kueri Anda, subpilihan bagian dalam tidak membantu:

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;

Seharusnya sedikit lebih cepat, tapi tetap lambat.

Kueri cepat

  • Dengan asumsi Anda memiliki relatif sedikit stasiun dan relatif banyak pengamatan per stasiun.
  • Juga dengan asumsi station_id id didefinisikan sebagai NOT NULL .

Menjadi benar-benar cepat, Anda memerlukan pemindaian indeks yang longgar (belum diimplementasikan di Postgres). Jawaban terkait:

  • Optimalkan kueri GROUP BY untuk mengambil data terbaru per pengguna

Jika Anda memiliki tabel terpisah dari stations (yang tampaknya mungkin), Anda dapat meniru ini dengan 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;

Jika Anda tidak memiliki tabel stations , hal terbaik berikutnya adalah membuat dan memeliharanya. Mungkin menambahkan referensi kunci asing untuk menegakkan integritas relasional.

Jika itu bukan pilihan, Anda dapat menyaring tabel seperti itu dengan cepat. Opsi sederhananya adalah:

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

Tetapi keduanya akan membutuhkan pemindaian berurutan dan lambat. Jadikan Postgres menggunakan indeks di atas (atau indeks btree apa pun dengan station_id sebagai kolom utama) dengan CTE rekursif :

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

Gunakan itu sebagai pengganti drop-in untuk stations tabel dalam kueri sederhana di atas:

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;

Ini masih harus lebih cepat dari yang Anda miliki dengan urutan besarnya .

SQL Fiddle di sini (9.6)
db<>biola di sini



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Masukkan data dan atur kunci asing dengan Postgres

  2. Memahami Dan Membaca Katalog Sistem PostgreSQL

  3. Ekstrak Bulan dari Tanggal di PostgreSQL

  4. Panda menulis kerangka data ke skema postgresql lainnya

  5. Menulis kueri untuk beberapa tabel di php