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

Cara yang tepat untuk mengakses baris terbaru untuk setiap pengidentifikasi individu?

Berikut adalah perbandingan kinerja cepat untuk kueri yang disebutkan dalam pos ini.

Penyiapan saat ini :

Tabel core_message memiliki 10.904.283 baris dan ada 60.740 baris di test_boats (atau 60.740 mmsi berbeda dalam core_message ).

Dan saya menggunakan PostgreSQL 11.5

Kueri menggunakan pemindaian hanya indeks :

1) menggunakan DISTINCT ON :

SELECT DISTINCT ON (mmsi) mmsi 
FROM core_message;

2) menggunakan RECURSIVE dengan LATERAL :

WITH RECURSIVE cte AS (
   (
   SELECT mmsi
   FROM   core_message
   ORDER  BY mmsi
   LIMIT  1
   )
   UNION ALL
   SELECT m.*
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT mmsi
      FROM   core_message
      WHERE  mmsi > c.mmsi
      ORDER  BY mmsi
      LIMIT  1
      ) m
   )
TABLE cte;

3) Menggunakan tabel tambahan dengan LATERAL :

SELECT a.mmsi
FROM test_boats a
CROSS JOIN LATERAL(
    SELECT b.time
    FROM core_message b
    WHERE a.mmsi = b.mmsi
    ORDER BY b.time DESC
    LIMIT 1
) b;

Kueri tidak menggunakan pemindaian hanya indeks :

4) menggunakan DISTINCT ON dengan mmsi,time DESC INDEX :

SELECT DISTINCT ON (mmsi) * 
FROM core_message 
ORDER BY mmsi, time desc;

5) menggunakan DISTINCT ON dengan mundur mmsi,time UNIQUE CONSTRAINT :

SELECT DISTINCT ON (mmsi) * 
FROM core_message 
ORDER BY mmsi desc, time desc;

6) menggunakan RECURSIVE dengan LATERAL dan mmsi,time DESC INDEX :

WITH RECURSIVE cte AS (
   (
   SELECT *
   FROM   core_message
   ORDER  BY mmsi , time DESC 
   LIMIT  1
   )
   UNION ALL
   SELECT m.*
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT *
      FROM   core_message
      WHERE  mmsi > c.mmsi
      ORDER  BY mmsi , time DESC 
      LIMIT  1
      ) m
   )
TABLE cte;

7) menggunakan RECURSIVE dengan LATERAL dan mundur mmsi,time UNIQUE CONSTRAINT :

WITH RECURSIVE cte AS (

   (

   SELECT *
   FROM   core_message
   ORDER  BY mmsi DESC , time DESC 
   LIMIT  1
   )
   UNION ALL
   SELECT m.*
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT *
      FROM   core_message
      WHERE  mmsi < c.mmsi
      ORDER  BY mmsi DESC , time DESC 
      LIMIT  1
      ) m
   )
TABLE cte;

8) Menggunakan tabel tambahan dengan LATERAL :

SELECT b.*
FROM test_boats a
CROSS JOIN LATERAL(
    SELECT b.*
    FROM core_message b
    WHERE a.mmsi = b.mmsi
    ORDER BY b.time DESC
    LIMIT 1
) b;

Menggunakan tabel khusus untuk pesan terakhir:

9) Inilah solusi awal saya, menggunakan tabel berbeda dengan hanya pesan terakhir. Tabel ini diisi saat pesan baru tiba tetapi juga dapat dibuat seperti ini :

CREATE TABLE core_shipinfos AS (
    WITH RECURSIVE cte AS (
       (
       SELECT *
       FROM   core_message
       ORDER  BY mmsi DESC , time DESC 
       LIMIT  1
       )
       UNION ALL
       SELECT m.*
       FROM   cte c
       CROSS  JOIN LATERAL (
          SELECT *
          FROM   core_message
          WHERE  mmsi < c.mmsi
          ORDER  BY mmsi DESC , time DESC 
          LIMIT  1
          ) m
       )
    TABLE cte);

Maka permintaan untuk mendapatkan pesan terbaru sesederhana itu :

SELECT * FROM core_shipinfos;

Hasil :

Rata-rata beberapa kueri (sekitar 5 untuk kueri cepat):

1) 9146 md
2) 728 md
3) 498 md

4) 51488 md
5) 54764 md
6) 729 md
7) 778 md
8) 516 md

9) 15 md

Kesimpulan:

Saya tidak akan mengomentari solusi tabel khusus, dan akan menyimpannya sampai akhir.

Tabel tambahan (test_boats ) solusi jelas merupakan pemenang di sini tetapi RECURSIVE solusinya juga cukup efisien.

Ada kesenjangan besar dalam kinerja untuk DISTINCT ON menggunakan pemindaian indeks-saja dan yang tidak menggunakannya tetapi, peningkatan kinerjanya agak kecil untuk kueri efisien lainnya.

Ini masuk akal karena peningkatan besar yang dibawa oleh kueri tersebut adalah fakta bahwa mereka tidak perlu mengulang seluruh core_message tabel tetapi hanya pada subset dari mmsi yang unik yang secara signifikan lebih kecil (60K+) dibandingkan dengan core_message ukuran meja (10M+)

Sebagai catatan tambahan, tampaknya tidak ada peningkatan kinerja yang signifikan untuk kueri menggunakan UNIQUE CONSTRAINT jika saya menjatuhkan mmsi,time DESC INDEX . Tetapi menghapus indeks itu tentu saja akan menghemat ruang saya (indeks ini saat ini membutuhkan 328MB)

Tentang solusi tabel khusus:

Setiap pesan disimpan di core_message tabel memuat informasi posisi (posisi, kecepatan, pos, dll.) DAN informasi kapal (nama, tanda panggil, dimensi, dll.), serta pengidentifikasi kapal (mmsi).

Untuk memberikan sedikit lebih banyak latar belakang tentang apa yang sebenarnya saya coba lakukan :Saya menerapkan backend untuk menyimpan pesan yang dipancarkan oleh kapal melalui protokol AIS .

Dengan demikian, setiap mmsi unik yang saya dapatkan, saya mendapatkannya melalui protokol ini. Ini bukan daftar yang telah ditentukan sebelumnya. Itu terus menambahkan MMSI baru sampai saya mendapatkan setiap kapal di dunia menggunakan AIS.

Dalam konteks itu, tabel khusus dengan informasi kapal sebagai pesan terakhir yang diterima masuk akal.

Saya dapat menghindari penggunaan tabel seperti yang telah kita lihat dengan RECURSIVE solusi, tapi... tabel khusus masih 50x lebih cepat dari RECURSIVE solusi.

Tabel khusus itu sebenarnya mirip dengan test_boat tabel, dengan informasi lebih dari sekedar mmsi bidang. Seperti itu, memiliki tabel dengan mmsi hanya bidang atau tabel dengan setiap informasi terakhir dari core_message tabel menambahkan kompleksitas yang sama ke aplikasi saya.

Pada akhirnya, saya pikir saya akan memilih meja khusus ini. Ini akan memberi saya kecepatan yang tidak ada duanya dan saya masih memiliki kemungkinan untuk menggunakan LATERAL trik core_message , yang akan memberi saya lebih banyak fleksibilitas.



  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 SQL untuk menanyakan teks array [] dalam elemen tertentu

  2. Apakah ada cara agar PostgreSQL tidak menciutkan tanda baca dan spasi saat menyusun menggunakan bahasa?

  3. Postgresql - Bagaimana cara mengekstrak kemunculan pertama substring dalam string menggunakan pola ekspresi reguler?

  4. indeks cookie yang tidak ditentukan di beberapa browser

  5. Panggilan untuk makalah untuk PGDay.IT 2011 telah diperpanjang