PostgreSQL 12 đi kèm với một tính năng mới được gọi là cột được tạo . Các RDBMS phổ biến khác đã hỗ trợ các cột được tạo dưới dạng “cột được tính toán” hoặc “cột ảo”. Với Postgres 12, bây giờ bạn cũng có thể sử dụng nó trong PostgreSQL. Đọc để tìm hiểu thêm.
Cột được tạo là gì?
Một cột được tạo giống như một dạng xem, nhưng đối với các cột. Đây là một ví dụ cơ bản:
db=# CREATE TABLE t (w real, h real, area real GENERATED ALWAYS AS (w*h) STORED);
CREATE TABLE
db=# INSERT INTO t (w, h) VALUES (10, 20);
INSERT 0 1
db=# SELECT * FROM t;
w | h | area
----+----+------
10 | 20 | 200
(1 row)
db=#
Chúng tôi đã tạo bảng t với hai cột thông thường được gọi là w và h và một cột được tạo có tên là khu vực . Giá trị của khu vực là thời gian tạo không đổi được tính toán và được lưu giữ trên đĩa.
Giá trị của các cột đã tạo được tính toán lại khi hàng được cập nhật:
db=# UPDATE t SET w=40;
UPDATE 1
db=# SELECT * FROM t;
w | h | area
----+----+------
40 | 20 | 800
(1 row)
db=#
Chức năng như vậy trước đó thường đạt được với trình kích hoạt, nhưng với các cột được tạo, điều này sẽ trở nên thanh lịch và sạch sẽ hơn nhiều.
Một số điểm bạn nên biết về các cột đã tạo:
- Tính bền bỉ :Hiện tại, giá trị của các cột đã tạo phải được bổ sung và không thể được tính toán nhanh tại thời điểm truy vấn. Từ khóa "ĐƯỢC LƯU TRỮ" phải có trong định nghĩa cột.
- Biểu thức :Biểu thức được sử dụng để tính giá trị phải là không thay đổi , nghĩa là, nó phải có tính xác định. Nó có thể phụ thuộc vào các cột khác chứ không phụ thuộc vào các cột được tạo khác của bảng.
- Chỉ mục :Các cột đã tạo có thể được sử dụng trong chỉ mục, nhưng không thể được sử dụng làm khóa phân vùng cho các bảng được phân vùng.
- Sao chép và pg_dump :Giá trị của các cột đã tạo bị bỏ qua trong đầu ra của lệnh “pg_dump” và “COPY table”, vì nó là không cần thiết. Bạn không bao gồm chúng trong SAO CHÉP một cách rõ ràng bằng cách sử dụng
COPY (SELECT * FROM t) TO STDOUT
chứ không phải làCOPY t TO STDOUT
.
Ví dụ thực tế
Hãy thêm hỗ trợ tìm kiếm văn bản đầy đủ vào bảng bằng cách sử dụng các cột đã tạo. Đây là bảng lưu trữ toàn bộ nội dung của tất cả các vở kịch của Shakespeare:
CREATE TABLE scenes (
workid text, -- denotes the name of the play (like "macbeth")
act integer, -- the act (like 1)
scene integer, -- the scene within the act (like 7)
description text, -- short desc of the scene (like "Macbeth's castle.")
body text -- full text of the scene
);
Đây là giao diện của dữ liệu:
shakespeare=# SELECT workid, act, scene, description, left(body, 200) AS body_start
shakespeare-# FROM scenes WHERE workid='macbeth' AND act=1 AND scene=1;
workid | act | scene | description | body_start
---------+-----+-------+-----------------+----------------------------------------------
macbeth | 1 | 1 | A desert place. | [Thunder and lightning. Enter three Witches]+
| | | | +
| | | | First Witch: When shall we three meet again +
| | | | In thunder, lightning, or in rain? +
| | | | +
| | | | Second Witch: When the hurlyburly's done, +
| | | | When the battle's lost and won. +
| | | |
(1 row)
Chúng tôi sẽ thêm một cột sẽ chứa các lexemes trong giá trị "body". Hàm to_tsvector trả về các lexem mà chúng tôi cần:
shakespeare=# SELECT to_tsvector('english', 'move moving moved movable mover movability');
to_tsvector
-------------------------------------
'movabl':4,6 'move':1,2,3 'mover':5
(1 row)
Loại giá trị được trả về bởi to_tsvector
là tsvector.
Hãy thay đổi bảng để thêm một cột đã tạo:
ALTER TABLE scenes
ADD tsv tsvector
GENERATED ALWAYS AS (to_tsvector('english', body)) STORED;
Bạn có thể thấy sự thay đổi với \d
:
shakespeare=# \d scenes
Table "public.scenes"
Column | Type | Collation | Nullable | Default
-------------+----------+-----------+----------+----------------------------------------------------------------------
workid | text | | not null |
act | integer | | not null |
scene | integer | | not null |
description | text | | |
body | text | | |
tsv | tsvector | | | generated always as (to_tsvector('english'::regconfig, body)) stored
Indexes:
"scenes_pkey" PRIMARY KEY, btree (workid, act, scene)
Và giống như vậy, bây giờ bạn có thể thực hiện tìm kiếm toàn văn:
shakespeare=# SELECT
workid, act, scene, ts_headline(body, q)
FROM (
SELECT
workid, act, scene, body, ts_rank(tsv, q) as rank, q
FROM
scenes, plainto_tsquery('uneasy head') q
WHERE
tsv @@ q
ORDER BY
rank DESC
LIMIT
5
) p
ORDER BY
rank DESC;
workid | act | scene | ts_headline
----------+-----+-------+-----------------------------------------------------------
henry4p2 | 3 | 1 | <b>Uneasy</b> lies the <b>head</b> that wears a crown. +
| | | +
| | | Enter WARWICK and Surrey +
| | | +
| | | Earl of Warwick
henry5 | 2 | 2 | <b>head</b> assembled them? +
| | | +
| | | Lord Scroop: No doubt, my liege, if each man do his best.+
| | | +
| | | Henry V: I doubt not that; since we are well persuaded +
| | | We carry not a heart with us from hence
(2 rows)
shakespeare=#
Đọc thêm
Nếu bạn có nhu cầu về dữ liệu được tính toán trước / “đã lưu trong bộ nhớ cache”, đặc biệt là với khối lượng công việc ít lần ghi và nhiều lần đọc, các cột được tạo sẽ giúp đơn giản hóa mã ứng dụng / phía máy chủ của bạn rất nhiều.
Bạn có thể đọc tài liệu v12 về CREATE TABLE và ALTER TABLE để xem cú pháp được cập nhật.