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

Fungsi jendela PostgreSQL:partisi dengan perbandingan

Menggunakan beberapa fungsi jendela yang berbeda dan dua subkueri, ini akan bekerja dengan cepat:

WITH events(id, event, ts) AS (
  VALUES
   (1, 12, '2014-03-19 08:00:00'::timestamp)
  ,(2, 12, '2014-03-19 08:30:00')
  ,(3, 13, '2014-03-19 09:00:00')
  ,(4, 13, '2014-03-19 09:30:00')
  ,(5, 12, '2014-03-19 10:00:00')
   )
SELECT first_value(pre_id)  OVER (PARTITION BY grp ORDER BY ts)      AS pre_id
     , id, ts
     , first_value(post_id) OVER (PARTITION BY grp ORDER BY ts DESC) AS post_id
FROM  (
   SELECT *, count(step) OVER w AS grp
   FROM  (
      SELECT id, ts
           , NULLIF(lag(event) OVER w, event) AS step
           , lag(id)  OVER w AS pre_id
           , lead(id) OVER w AS post_id
      FROM   events
      WINDOW w AS (ORDER BY ts)
      ) sub1
   WINDOW w AS (ORDER BY ts)
   ) sub2
ORDER  BY ts;

Menggunakan ts sebagai nama untuk kolom stempel waktu.
Dengan asumsi ts menjadi unik - dan diindeks (batasan unik melakukannya secara otomatis).

Dalam pengujian dengan tabel kehidupan nyata dengan 50 ribu baris, hanya diperlukan pemindaian indeks tunggal . Jadi, harus cukup cepat bahkan dengan meja besar. Sebagai perbandingan, kueri Anda dengan bergabung / berbeda tidak selesai setelah satu menit (seperti yang diharapkan).
Bahkan versi yang dioptimalkan, menangani satu gabungan silang pada satu waktu (penggabungan kiri dengan kondisi yang hampir tidak membatasi secara efektif terbatas cross join) tidak selesai setelah satu menit.

Untuk performa terbaik dengan meja besar, sesuaikan setelan memori Anda, khususnya untuk work_mem (untuk operasi sortir besar). Pertimbangkan untuk mengaturnya (jauh) lebih tinggi untuk sesi Anda sementara jika Anda dapat menghemat RAM. Baca selengkapnya di sini dan di sini.

Bagaimana?

  1. Dalam subkueri sub1 lihat acara dari baris sebelumnya dan simpan hanya jika itu telah berubah, dengan demikian menandai elemen pertama dari grup baru. Pada saat yang sama, dapatkan id dari baris sebelumnya dan berikutnya (pre_id , post_id ).

  2. Dalam subkueri sub2 , count() hanya menghitung nilai bukan nol. grp . yang dihasilkan menandai rekan-rekan di blok peristiwa yang sama berturut-turut.

  3. Di bagian terakhir SELECT , ambil pre_id pertama dan post_id terakhir per grup untuk setiap baris untuk mencapai hasil yang diinginkan.
    Sebenarnya, ini harus lebih cepat di SELECT luar :

     last_value(post_id) OVER (PARTITION BY grp ORDER BY ts
                               RANGE BETWEEN UNBOUNDED PRECEDING
                                     AND     UNBOUNDED FOLLOWING) AS post_id
    

    ... karena urutan jendela sesuai dengan jendela untuk pre_id , jadi hanya satu jenis yang diperlukan. Tes cepat tampaknya mengkonfirmasinya. Selengkapnya tentang definisi bingkai ini.

SQL 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. Pengujian Otomatis dari Proses Peningkatan untuk PostgreSQL

  2. Tren PostgreSQL:Penyedia Cloud Paling Populer, Bahasa, VAKUM, Strategi Manajemen Kueri &Jenis Penerapan di Perusahaan

  3. Membuat Cold Standby untuk PostgreSQL Menggunakan Amazon AWS

  4. masalah dengan python manage.py migrasi -> Tidak ada modul bernama psycopg2

  5. CASCADE DELETE sekali saja