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

Memahami Kolom Sistem di PostgreSQL

Jadi, Anda duduk dengan tangan di atas keyboard dan berpikir “kesenangan apa yang bisa saya miliki untuk membuat hidup saya lebih penasaran?..” Yah - buat tabel tentu saja!

vao=# create table nocol();
CREATE TABLE
vao=# select * from nocol;
--
(0 rows)

Apa yang menyenangkan tentang tabel tanpa data?.. Sama sekali tidak ada! Tapi saya bisa dengan mudah memperbaikinya:

vao=# insert into nocol default values;
INSERT 0 1

Kelihatannya aneh dan cukup bodoh memiliki tabel tanpa kolom dan satu baris. Belum lagi tidak jelas “nilai default” apa yang dimasukkan… Nah - membaca beberapa baris dari dokumen mengungkapkan bahwa “Semua kolom akan diisi dengan nilai defaultnya .” Namun saya tidak punya kolom! Yah - saya pasti punya beberapa:

vao=# select attname, attnum, atttypid::regtype, attisdropped::text from pg_attribute where attrelid = 'nocol'::regclass;
 attname  | attnum | atttypid | attisdropped 
----------+--------+----------+--------------
 tableoid |     -7 | oid      | false
 cmax     |     -6 | cid      | false
 xmax     |     -5 | xid      | false
 cmin     |     -4 | cid      | false
 xmin     |     -3 | xid      | false
 ctid     |     -1 | tid      | false
(6 rows)

Jadi keenam ini jelas bukan zombie ALTER TABLE DROP COLUMN karena attisdropped salah. Saya juga melihat bahwa nama tipe kolom tersebut diakhiri dengan "id". Membaca bagian bawah Object Identifier Types akan memberikan ide. Pengamatan lucu lainnya adalah - -2 hilang! Saya bertanya-tanya di mana saya bisa kehilangannya - saya baru saja membuat tabel! Hm, pengenal objek apa yang hilang di tabel saya? Secara definisi maksud saya. Saya memiliki Tuple, perintah dan id xact. Yah kecuali beberapa "pengidentifikasi db seluruh dunia", seperti oid?.. Memeriksanya mudah - saya akan membuat tabel dengan OIDS:

vao=# create table nocol_withoid() with oids;
CREATE TABLE
vao=# select attname, attnum, atttypid::regtype, attisdropped::text from pg_attribute where attrelid = 'nocol_withoid'::regclass;
 attname  | attnum | atttypid | attisdropped 
----------+--------+----------+--------------
 tableoid |     -7 | oid      | false
 cmax     |     -6 | cid      | false
 xmax     |     -5 | xid      | false
 cmin     |     -4 | cid      | false
 xmin     |     -3 | xid      | false
 oid      |     -2 | oid      | false
 ctid     |     -1 | tid      | false
(7 rows)

Voila! Jadi -2 yang hilang memang hilang dan kami menyukainya. Menghabiskan oid untuk baris data bekas akan menjadi ide yang buruk, jadi saya akan terus bermain dengan tabel tanpa OIDS.

Apa yang saya punya? Saya memiliki 6 atribut setelah membuat "tidak ada tabel kolom" dengan (oids=false). Haruskah saya menggunakan kolom sistem? Jika demikian, mengapa mereka agak tersembunyi? Yah - saya berasumsi mereka tidak diiklankan secara luas, karena penggunaannya tidak intuitif dan perilaku dapat berubah di masa depan. Misalnya setelah melihat tuple id (ctid) beberapa orang mungkin berpikir “ah - ini semacam PK internal” (dan memang begitu):

vao=# select ctid from nocol;
 ctid  
-------
 (0,1)
(1 row)

Digit pertama (nol) menunjukkan nomor halaman dan angka kedua (satu) menunjukkan nomor tuple. Mereka berurutan:

vao=# insert into nocol default values;
INSERT 0 1
vao=# select ctid from nocol;
 ctid  
-------
 (0,1)
 (0,2)
(2 rows)

Tetapi urutan ini tidak akan membantu Anda menentukan bahkan baris mana yang muncul setelahnya:

vao=# alter table nocol add column i int;
ALTER TABLE
vao=# update nocol set i = substring(ctid::text from 4 for 1)::int;
UPDATE 2
vao=# select i, ctid from nocol;
 i | ctid  
---+-------
 1 | (0,3)
 2 | (0,4)
(2 rows)

Di sini saya menambahkan kolom (untuk mengidentifikasi baris saya) dan mengisinya dengan nomor tupel awal (ingat kedua baris dipindahkan secara fisik)

vao=# delete from nocol where ctid = '(0,3)';
DELETE 1
vao=# vacuum nocol;
VACUUM
vao=# insert into nocol default values;
INSERT 0 1
vao=# select i, ctid from nocol;
 i | ctid  
---+-------
   | (0,1)
 2 | (0,4)
(2 rows)

Ah! (diucapkan dengan intonasi naik) - di sini saya menghapus salah satu baris saya, mengeluarkan ruang hampa di meja yang buruk dan memasukkan baris baru. Hasilnya - baris yang ditambahkan kemudian ada di halaman pertama tupel pertama, karena Postgres dengan bijak memutuskan untuk menghemat ruang dan menggunakan kembali ruang yang kosong.

Jadi ide untuk menggunakan ctid untuk mendapatkan urutan baris yang diperkenalkan terlihat buruk. Sampai tingkat tertentu - jika Anda bekerja dalam satu transaksi, urutannya tetap - baris yang baru terpengaruh pada tabel yang sama akan memiliki ctid "lebih besar". Tentu saja setelah vakum (autovacuum) atau jika Anda cukup beruntung untuk memiliki pembaruan PANAS sebelumnya atau baru saja dirilis, celah akan digunakan kembali - melanggar urutan berurutan. Tapi jangan takut - ada enam atribut tersembunyi, bukan satu!

vao=# select i, ctid, xmin from nocol;
 i | ctid  | xmin  
---+-------+-------
   | (0,1) | 26211
 2 | (0,4) | 26209
(2 rows)

Jika saya memeriksa xmin, saya akan melihat bahwa id transaksi yang memperkenalkan baris yang dimasukkan terakhir adalah (+2) lebih tinggi (+1 adalah baris yang dihapus). Jadi untuk pengidentifikasi baris berurutan, saya mungkin menggunakan atribut yang sama sekali berbeda! Tentu saja tidak sesederhana ini, jika tidak, penggunaan seperti itu akan dianjurkan. Kolom xmin sebelum 9.4 sebenarnya ditimpa untuk melindungi dari sampul xid. Mengapa begitu rumit? MVCC di Postgres sangat cerdas dan metode di sekitarnya menjadi lebih baik dari waktu ke waktu. Tentu saja itu membawa kompleksitas. Sayang. Beberapa orang bahkan ingin menghindari kolom sistem. Dua kali lipat. Karena kolom sistem keren dan didokumentasikan dengan baik. Atribut paling atas (ingat saya melewatkan oids) adalah tableoid:

vao=# select i, tableoid from nocol;
 i | tableoid 
---+----------
   |   253952
 2 |   253952
(2 rows)
Unduh Whitepaper Hari Ini Pengelolaan &Otomatisasi PostgreSQL dengan ClusterControlPelajari tentang apa yang perlu Anda ketahui untuk menerapkan, memantau, mengelola, dan menskalakan PostgreSQLUnduh Whitepaper

Tampaknya tidak berguna memiliki nilai SAMA di setiap baris - bukan? Namun beberapa waktu yang lalu itu adalah atribut yang sangat populer - ketika kita semua membangun partisi menggunakan aturan dan tabel yang diwarisi. Bagaimana Anda men-debug tabel dari mana baris itu berasal jika tidak dengan tableoid? Jadi saat Anda menggunakan aturan, tampilan (aturan yang sama) atau UNION, atribut tableoid membantu Anda mengidentifikasi sumbernya:

vao=# insert into nocol_withoid default values;
INSERT 253967 1
vao=# select ctid, tableoid from nocol union select ctid, tableoid from nocol_withoid ;
 ctid  | tableoid 
-------+----------
 (0,1) |   253952
 (0,1) |   253961
 (0,4) |   253952
(3 rows)

Wow apa itu? Saya sudah terbiasa melihat INSERT 0 1 sehingga output psql saya terlihat aneh! Ah - benar - saya membuat tabel dengan oids dan hanya menggunakan satu (253967) pengidentifikasi dengan sia-sia! Yah - tidak sepenuhnya sia-sia (meskipun putus asa) - pilih mengembalikan dua baris dengan ctid yang sama (0,1) - tidak mengherankan - Saya memilih dari dua tabel dan kemudian menambahkan hasil satu ke yang lain, sehingga peluang untuk memiliki ctid yang sama tidak begitu rendah. Hal terakhir yang perlu disebutkan adalah saya dapat kembali menggunakan tipe pengenal objek untuk menunjukkannya dengan cantik:

vao=# select ctid, tableoid::regclass from nocol union select ctid, tableoid from nocol_withoid ;
 ctid  |   tableoid    
-------+---------------
 (0,1) | nocol
 (0,1) | nocol_withoid
 (0,4) | nocol
(3 rows)

Ah! (diucapkan dengan intonasi naik) - Jadi begitulah cara menyematkan sumber data dengan jelas di sini!

Akhirnya penggunaan lain yang sangat populer dan menarik - menentukan baris mana yang disisipkan dan mana yang disisipkan:

vao=# update nocol set i = 0 where i is null;
UPDATE 1
vao=# alter table nocol alter COLUMN i set not null;
ALTER TABLE
vao=# alter table nocol add constraint pk primary key (i);
ALTER TABLE

Sekarang kita memiliki PK, saya dapat menggunakan direktif ON CONFLICT:

vao=# insert into nocol values(0),(-1) on conflict(i) do update set i = extract(epoch from now()) returning i, xmax;
     i      |   xmax    
------------+-----------
 1534433974 |     26281
         -1 |         0
(2 rows)
Referensi terkait ClusterControl untuk PostgreSQL Memahami Dan Membaca Katalog Sistem PostgreSQL Ikhtisar Pengindeksan Database di PostgreSQL

Mengapa begitu bahagia? Karena saya tahu (dengan sedikit kerahasiaan) bahwa baris dengan xmax tidak sama dengan nol itu diperbarui. Dan jangan berpikir itu sudah jelas - terlihat begitu hanya karena saya menggunakan unixtime untuk PK, jadi terlihat sangat berbeda dari nilai satu digit. Bayangkan Anda melakukan twist ON CONFLICT di set besar dan tidak ada cara logis untuk mengidentifikasi nilai mana yang memiliki konflik dan mana - tidak. xmax membantu banyak DBA di masa-masa sulit. Dan deskripsi terbaik tentang cara kerjanya akan saya rekomendasikan di sini - sama seperti saya akan merekomendasikan ketiga peserta diskusi (Abelisto, Erwin dan Laurenz) untuk dibaca di pertanyaan dan jawaban tag postgres lainnya di SO.

Itu dia.

tableoid, xmax, xmin, dan ctid adalah teman baik DBA mana pun. Bukan untuk menghina cmax, cmin dan oid - mereka juga berteman baik! Tapi ini cukup untuk ulasan kecil dan saya ingin melepaskan tangan saya dari keyboard sekarang.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. lastInsertId tidak berfungsi di Postgresql

  2. Deteksi jika baris telah diperbarui atau dimasukkan

  3. Bagaimana Pi() Bekerja di PostgreSQL

  4. Fitur Metode Pencadangan PostgreSQL di AWS S3

  5. Salin tabel dari satu database ke database lain di Postgres