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

PostgreSQL:Peningkatan otomatis berdasarkan batasan unik multi-kolom

Akan lebih baik jika PostgreSQL mendukung penambahan "pada kolom sekunder dalam indeks multi-kolom" seperti tabel MyISAM MySQL

Ya, tetapi perhatikan bahwa dalam melakukannya, MyISAM mengunci seluruh tabel Anda. Yang kemudian membuatnya aman untuk menemukan +1 terbesar tanpa mengkhawatirkan transaksi bersamaan.

Di Postgres, Anda juga dapat melakukan ini, dan tanpa mengunci seluruh tabel. Kunci penasehat dan pemicu akan cukup baik:

CREATE TYPE animal_grp AS ENUM ('fish','mammal','bird');

CREATE TABLE animals (
    grp animal_grp NOT NULL,
    id INT NOT NULL DEFAULT 0,
    name varchar NOT NULL,
    PRIMARY KEY (grp,id)
);

CREATE OR REPLACE FUNCTION animals_id_auto()
    RETURNS trigger AS $$
DECLARE
    _rel_id constant int := 'animals'::regclass::int;
    _grp_id int;
BEGIN
    _grp_id = array_length(enum_range(NULL, NEW.grp), 1);

    -- Obtain an advisory lock on this table/group.
    PERFORM pg_advisory_lock(_rel_id, _grp_id);

    SELECT  COALESCE(MAX(id) + 1, 1)
    INTO    NEW.id
    FROM    animals
    WHERE   grp = NEW.grp;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql STRICT;

CREATE TRIGGER animals_id_auto
    BEFORE INSERT ON animals
    FOR EACH ROW WHEN (NEW.id = 0)
    EXECUTE PROCEDURE animals_id_auto();

CREATE OR REPLACE FUNCTION animals_id_auto_unlock()
    RETURNS trigger AS $$
DECLARE
    _rel_id constant int := 'animals'::regclass::int;
    _grp_id int;
BEGIN
    _grp_id = array_length(enum_range(NULL, NEW.grp), 1);

    -- Release the lock.
    PERFORM pg_advisory_unlock(_rel_id, _grp_id);

    RETURN NEW;
END;
$$ LANGUAGE plpgsql STRICT;

CREATE TRIGGER animals_id_auto_unlock
    AFTER INSERT ON animals
    FOR EACH ROW
    EXECUTE PROCEDURE animals_id_auto_unlock();

INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;

Ini menghasilkan:

  grp   | id |  name   
--------+----+---------
 fish   |  1 | lax
 mammal |  1 | dog
 mammal |  2 | cat
 mammal |  3 | whale
 bird   |  1 | penguin
 bird   |  2 | ostrich
(6 rows)

Ada satu peringatan. Kunci penasehat diadakan sampai dirilis atau sampai sesi berakhir. Jika terjadi kesalahan selama transaksi, kunci akan tetap ada dan Anda harus melepaskannya secara manual.

SELECT pg_advisory_unlock('animals'::regclass::int, i)
FROM generate_series(1, array_length(enum_range(NULL::animal_grp),1)) i;

Di Postgres 9.1, Anda dapat membuang pemicu buka kunci, dan mengganti panggilan pg_advisory_lock() dengan pg_advisory_xact_lock(). Yang itu secara otomatis ditahan hingga dan dilepaskan pada akhir transaksi.

Pada catatan terpisah, saya akan tetap menggunakan urutan lama yang bagus. Itu akan membuat segalanya lebih cepat -- meskipun tampilannya tidak secantik saat Anda melihat datanya.

Terakhir, urutan unik kombo per (tahun, bulan) juga dapat diperoleh dengan menambahkan tabel tambahan, yang kunci utamanya adalah serial, dan yang nilainya (tahun, bulan) memiliki batasan unik.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Memesan hasil model bersarang yang penuh semangat di Node Sequelize

  2. Bagaimana cara memilih lebih dari 1 catatan per hari?

  3. Pemeran tipe data Postgres

  4. kesalahan menginstal psycopg2, perpustakaan tidak ditemukan untuk -lssl

  5. Memilih baris yang diurutkan oleh beberapa kolom dan berbeda di kolom lainnya