PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Hiểu các cột hệ thống trong PostgreSQL

Vì vậy, bạn ngồi đặt tay trên bàn phím và nghĩ “tôi có thể có gì vui để khiến cuộc đời mình trở nên tò mò hơn nữa? ..” Chà - tất nhiên là hãy tạo một bảng!

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

Có gì vui khi một bảng không có dữ liệu? .. Hoàn toàn không có! Nhưng tôi có thể dễ dàng sửa chữa nó:

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

Có vẻ kỳ lạ và khá ngu ngốc khi có một bảng không có cột và một hàng. Chưa kể là không rõ “giá trị mặc định” đã được chèn vào… Chà - đọc vài dòng từ tài liệu cho thấy rằng “ Tất cả các cột sẽ được lấp đầy bằng các giá trị mặc định của chúng . ” Tuy nhiên, tôi không có cột! Chà - tôi chắc chắn có một số:

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)

Vì vậy, sáu cái này chắc chắn không phải là zombie ALTER TABLE DROP COLUMN vì attisdropped là sai. Ngoài ra, tôi thấy rằng tên loại của các cột đó kết thúc bằng "id". Đọc phần dưới cùng của Các loại định danh đối tượng sẽ cung cấp ý tưởng. Một quan sát hài hước khác là - số -2 bị thiếu! Tôi tự hỏi tôi có thể đã làm mất nó ở đâu - Rốt cuộc thì tôi vừa tạo một bảng! Hm, mã định danh đối tượng nào bị thiếu trong bảng của tôi? Theo định nghĩa của tôi. Tôi có tuple, lệnh và id xact. Chà trừ khi một số "toàn cục trên toàn bộ số nhận dạng db", như oid? .. Việc kiểm tra rất dễ dàng - Tôi sẽ tạo bảng với 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)

Thì đấy! Vì vậy, số -2 bị thiếu thực sự là thiếu và chúng tôi thích nó. Dành oids cho các hàng dữ liệu đã sử dụng sẽ là một ý tưởng tồi, vì vậy tôi sẽ tiếp tục chơi với một bảng không có OIDS.

Tôi có gì? Tôi có 6 thuộc tính sau khi tạo "không có bảng cột" với (oids =false). Tôi có nên sử dụng cột hệ thống không? Nếu vậy, tại sao chúng lại bị ẩn đi? Chà - tôi cho rằng chúng không được quảng cáo rộng rãi như vậy, bởi vì cách sử dụng không trực quan và hành vi có thể thay đổi trong tương lai. Ví dụ sau khi nhìn thấy tuple id (ctid), một số có thể nghĩ “à - đây là loại PK nội bộ” (và đại khái là như vậy):

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

Các chữ số đầu tiên (không) đại diện cho số trang và chữ số thứ hai (một) đại diện cho số bộ. Chúng tuần tự:

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

Nhưng trình tự này sẽ không giúp bạn xác định ngay cả hàng nào đến sau đó:

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)

Ở đây tôi đã thêm một cột (để xác định các hàng của tôi) và điền nó bằng số tuple ban đầu (lưu ý rằng cả hai hàng đều được di chuyển về mặt vật lý)

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)

Aha! (nói với ngữ điệu tăng lên) - ở đây tôi đã xóa một trong các hàng của mình, loại bỏ khoảng trống trên bàn kém và chèn một hàng mới. Kết quả - hàng được thêm vào sau này nằm trong bộ đầu tiên của trang đầu tiên, vì Postgres đã quyết định một cách khôn ngoan để tiết kiệm không gian và sử dụng lại không gian đã giải phóng.

Vì vậy, ý tưởng sử dụng ctid để lấy chuỗi các hàng được giới thiệu có vẻ tệ. Lên đến một mức độ nào đó - nếu bạn làm việc trong một giao dịch, trình tự vẫn còn - các hàng mới bị ảnh hưởng trên cùng một bảng sẽ có ctid “lớn hơn”. Tất nhiên sau khi hút chân không (autovacuum) hoặc nếu bạn đủ may mắn để có các bản cập nhật HOT sớm hơn hoặc những khoảng trống vừa được phát hành sẽ được sử dụng lại - phá vỡ thứ tự tuần tự. Nhưng đừng sợ - có sáu thuộc tính ẩn, không phải một!

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

Nếu tôi kiểm tra xmin, tôi sẽ thấy rằng id giao dịch đã giới thiệu hàng được chèn cuối cùng cao hơn (+2) (+1 là hàng đã xóa). Vì vậy, đối với mã định danh hàng tuần tự, tôi có thể sử dụng thuộc tính hoàn toàn khác! Tất nhiên nó không đơn giản như vậy, nếu không thì việc sử dụng như vậy sẽ được khuyến khích. Cột xmin trước 9.4 thực sự đã được ghi đè để bảo vệ khỏi sự bao bọc xid. Tại sao lại phức tạp như vậy? MVCC trong Postgres rất thông minh và các phương pháp xung quanh nó ngày càng tốt hơn theo thời gian. Tất nhiên nó mang lại sự phức tạp. Chao ôi. Một số người thậm chí muốn tránh các cột hệ thống. Chà đôi. Bởi vì các cột hệ thống mát mẻ và được ghi chép đầy đủ. Thuộc tính rất trên cùng (hãy nhớ rằng tôi bỏ qua oids) là dạng bảng:

vao=# select i, tableoid from nocol;
 i | tableoid 
---+----------
   |   253952
 2 |   253952
(2 rows)
Tải xuống Báo cáo chính thức hôm nay Quản lý &Tự động hóa PostgreSQL với ClusterControlTìm hiểu về những điều bạn cần biết để triển khai, giám sát, quản lý và mở rộng PostgreSQLTải xuống Báo cáo chính thức

Có vẻ như vô ích khi có cùng giá trị trong mỗi hàng - phải không? Và cách đây không lâu, nó là thuộc tính rất phổ biến - khi tất cả chúng ta đang xây dựng phân vùng bằng cách sử dụng các quy tắc và bảng kế thừa. Bạn sẽ gỡ lỗi bảng nào mà hàng đến từ nếu không có tableoid? Vì vậy, khi bạn sử dụng các quy tắc, chế độ xem (cùng một quy tắc) hoặc UNION, thuộc tính tableoid sẽ giúp bạn xác định nguồn:

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 đó là gì? Tôi đã sử dụng rất nhiều để thấy INSERT 0 1 đến nỗi đầu ra psql của tôi trông kỳ lạ! À - đúng - Tôi đã tạo một bảng với oids và chỉ sử dụng một cách vô ích một cách tuyệt vọng (253967) một mã định danh! Chà - không hoàn toàn vô nghĩa (mặc dù tuyệt vọng) - lựa chọn trả về hai hàng có cùng ctid (0,1) - không có gì đáng ngạc nhiên - tôi đang chọn từ hai bảng và sau đó thêm kết quả lần lượt vào, vì vậy cơ hội có cùng một ctid không phải là thấp. Điều cuối cùng cần đề cập là tôi có thể sử dụng lại các loại mã định danh đối tượng để hiển thị nó khá đẹp:

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)

Aha! (nói với ngữ điệu tăng lên) - Vì vậy, đó là cách để ghi rõ nguồn dữ liệu ở đây!

Cuối cùng là một cách sử dụng rất phổ biến và thú vị khác - xác định hàng nào đã được chèn và hàng nào được nâng cấp:

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

Bây giờ chúng ta đã có PK, tôi có thể sử dụng lệnh 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)
Các tài nguyên liên quan ClusterControl for PostgreSQL Hiểu và Đọc Danh mục Hệ thống PostgreSQL Tổng quan về Lập chỉ mục Cơ sở dữ liệu trong PostgreSQL

Tại sao rất hạnh phúc? Bởi vì tôi có thể nói (với một số bí mật) rằng hàng với xmax không bằng 0 rằng nó đã được cập nhật. Và đừng nghĩ đó là điều hiển nhiên - có vẻ như vậy chỉ vì tôi đã sử dụng unixtime cho PK, vì vậy nó trông thực sự khác với các giá trị một chữ số. Hãy tưởng tượng bạn thực hiện như vậy TRÊN MẶT TRẬN xoắn trên tập hợp lớn và không có cách hợp lý nào để xác định giá trị nào có xung đột và giá trị nào - không. xmax đã giúp hàng tấn DBA trong thời kỳ khó khăn. Và mô tả tốt nhất về cách nó hoạt động mà tôi muốn giới thiệu ở đây - cũng như tôi muốn giới thiệu cả ba người tham gia thảo luận (Abelisto, Erwin và Laurenz) để đọc trên các câu hỏi và câu trả lời về thẻ postgres khác trên SO.

Thế là xong.

tableoid, xmax, xmin và ctid là những người bạn tốt của bất kỳ DBA nào. Không xúc phạm cmax, cmin và oid - họ cũng là những người bạn tốt của nhau! Nhưng điều này là đủ cho một đánh giá nhỏ và tôi muốn rời khỏi bàn phím ngay bây giờ.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mẫu bảng và các phương pháp khác để lấy các bộ số ngẫu nhiên

  2. Nhật ký lưu trữ được nén PostgreSQL trong Windows

  3. Rails Console tìm người dùng theo mảng id

  4. Cách tạo người dùng chỉ đọc trong PostgreSQL

  5. Làm cách nào để đặt tham số String [] cho một truy vấn gốc?