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

Tambahkan batasan datetime ke indeks parsial multi-kolom PostgreSQL

Anda mendapatkan pengecualian menggunakan now() karena fungsinya bukan IMMUTABLE (jelas) dan, dengan mengutip manual :

Saya melihat dua cara untuk menggunakan indeks parsial (jauh lebih efisien):

1. Indeks parsial dengan kondisi menggunakan konstan tanggal:

CREATE INDEX queries_recent_idx ON queries_query (user_sid, created)
WHERE created > '2013-01-07 00:00'::timestamp;

Dengan asumsi created sebenarnya didefinisikan sebagai timestamp . Tidak akan berfungsi untuk memberikan timestamp konstan untuk timestamptz kolom (timestamp with time zone ). Pemeran dari timestamp ke timestamptz (atau sebaliknya) bergantung pada setelan zona waktu saat ini dan tidak dapat diubah . Gunakan konstanta tipe data yang cocok. Memahami dasar-dasar stempel waktu dengan / tanpa zona waktu:

Lepaskan dan buat ulang indeks itu pada jam-jam dengan lalu lintas rendah, mungkin dengan pekerjaan cron setiap hari atau setiap minggu (atau apa pun yang cukup baik untuk Anda). Membuat indeks cukup cepat, terutama indeks parsial yang relatif kecil. Solusi ini juga tidak perlu menambahkan apa pun ke tabel.

Dengan asumsi tidak ada akses bersamaan ke tabel, rekreasi indeks otomatis dapat dilakukan dengan fungsi seperti ini:

CREATE OR REPLACE FUNCTION f_index_recreate()
  RETURNS void
  LANGUAGE plpgsql AS
$func$
BEGIN
   DROP INDEX IF EXISTS queries_recent_idx;
   EXECUTE format('
      CREATE INDEX queries_recent_idx
      ON queries_query (user_sid, created)
      WHERE created > %L::timestamp'
    , LOCALTIMESTAMP - interval '30 days');  -- timestamp constant
--  , now() - interval '30 days');           -- alternative for timestamptz
END
$func$;

Telepon:

SELECT f_index_recreate();

now() (seperti yang Anda miliki) setara dengan CURRENT_TIMESTAMP dan mengembalikan timestamptz . Transmisikan ke timestamp dengan now()::timestamp atau gunakan LOCALTIMESTAMP sebagai gantinya.

db<>fiddle di sini
Lama sqlfiddle

Jika Anda harus berurusan dengan akses bersamaan ke tabel, gunakan DROP INDEX CONCURRENTLY dan CREATE INDEX CONCURRENTLY . Tetapi Anda tidak dapat menggabungkan perintah ini menjadi suatu fungsi karena, per dokumentasi :

Jadi, dengan dua transaksi terpisah :

CREATE INDEX CONCURRENTLY queries_recent_idx2 ON queries_query (user_sid, created)
WHERE  created > '2013-01-07 00:00'::timestamp;  -- your new condition

Kemudian:

DROP INDEX CONCURRENTLY IF EXISTS queries_recent_idx;

Secara opsional, ganti nama menjadi nama lama:

ALTER INDEX queries_recent_idx2 RENAME TO queries_recent_idx;

2. Indeks parsial dengan kondisi pada tag "diarsipkan"

Tambahkan archived tag ke meja Anda:

ALTER queries_query ADD COLUMN archived boolean NOT NULL DEFAULT FALSE;

UPDATE kolom pada interval yang Anda pilih untuk "menghentikan" baris lama dan membuat indeks seperti:

CREATE INDEX some_index_name ON queries_query (user_sid, created)
WHERE NOT archived;

Tambahkan kondisi yang cocok ke kueri Anda (meskipun tampaknya berlebihan) untuk mengizinkannya menggunakan indeks. Periksa dengan EXPLAIN ANALYZE apakah perencana kueri mengetahui - ia harus dapat menggunakan indeks untuk kueri pada tanggal yang lebih baru. Tapi itu tidak akan memahami kondisi yang lebih kompleks yang tidak sama persis.

Anda tidak perlu menghapus dan membuat ulang indeks, tetapi UPDATE di atas meja mungkin lebih mahal daripada rekreasi indeks dan meja menjadi sedikit lebih besar.

Saya akan memilih yang pertama pilihan (rekreasi indeks). Sebenarnya, saya menggunakan solusi ini di beberapa database. Yang kedua menimbulkan pembaruan yang lebih mahal.

Kedua solusi mempertahankan kegunaannya dari waktu ke waktu, kinerja perlahan-lahan menurun karena lebih banyak baris usang dimasukkan dalam indeks.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nyalakan Pemicu SQL hanya ketika pengguna tertentu memperbarui baris

  2. Apakah desain PHP, Python, PostgreSQL cocok untuk aplikasi bisnis?

  3. BERBEDA dengan dua array_agg (atau satu array_agg dengan Tuple di dalamnya)?

  4. PostgreSQL - pengelompokan berdasarkan kolom jsonb

  5. Postgres TIDAK dalam array