PostgreSQL 12 wordt geleverd met een nieuwe functie genaamd gegenereerde kolommen . Andere populaire RDBMS-en ondersteunen al gegenereerde kolommen als "berekende kolommen" of "virtuele kolommen". Met Postgres 12 kunt u het nu ook in PostgreSQL gebruiken. Lees verder voor meer informatie.
Wat is een gegenereerde kolom?
Een gegenereerde kolom is een soort weergave, maar dan voor kolommen. Hier is een basisvoorbeeld:
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=#
We hebben een tabel gemaakt t met twee gewone kolommen genaamd w en h ,en een gegenereerde kolom met de naam gebied . De waarde van gebied wordt berekend op de aanmaaktijd van de rij en wordt bewaard op de schijf.
De waarde van gegenereerde kolommen wordt opnieuw berekend wanneer de rij wordt bijgewerkt:
db=# UPDATE t SET w=40;
UPDATE 1
db=# SELECT * FROM t;
w | h | area
----+----+------
40 | 20 | 800
(1 row)
db=#
Dergelijke functionaliteit werd vroeger meestal bereikt met triggers, maar met gegenereerde kolommen wordt dit veel eleganter en schoner.
Een paar punten die u moet weten over gegenereerde kolommen:
- Persistentie :Momenteel moet de waarde van gegenereerde kolommen worden aangehouden en kan deze niet direct worden berekend tijdens het opvragen. Het trefwoord “OPGESLAGEN” moet aanwezig zijn in de kolomdefinitie.
- De uitdrukking :De uitdrukking die wordt gebruikt om de waarde te berekenen, moetonveranderlijk . zijn , dat wil zeggen, het moet deterministisch zijn. Het kan afhangen van andere kolommen, maar niet van andere gegenereerde kolommen, van de tabel.
- Indexen :Gegenereerde kolommen kunnen worden gebruikt in indexen, maar kunnen niet worden gebruikt als partitiesleutel voor gepartitioneerde tabellen.
- Kopieer en pg_dump :De waarden van gegenereerde kolommen worden weggelaten in de uitvoer van de opdrachten "pg_dump" en "COPY table", omdat dit niet nodig is. U kunt ze expliciet opnemen in COPY met
COPY (SELECT * FROM t) TO STDOUT
in plaats vanCOPY t TO STDOUT
.
Een praktisch voorbeeld
Laten we ondersteuning voor zoeken in volledige tekst toevoegen aan een tabel met behulp van gegenereerde kolommen. Hier is een tabel met de volledige tekst van alle toneelstukken van 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
);
Zo zien de gegevens eruit:
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)
We zullen een kolom toevoegen die de lexemen zal bevatten in de waarde van "body". De functie to_tsvector retourneert de lexemen die we nodig hebben:
shakespeare=# SELECT to_tsvector('english', 'move moving moved movable mover movability');
to_tsvector
-------------------------------------
'movabl':4,6 'move':1,2,3 'mover':5
(1 row)
Het type van de waarde die wordt geretourneerd door to_tsvector
is tsvector.
Laten we de tabel wijzigen om een gegenereerde kolom toe te voegen:
ALTER TABLE scenes
ADD tsv tsvector
GENERATED ALWAYS AS (to_tsvector('english', body)) STORED;
U kunt de wijziging zien met \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)
En zo kunt u nu zoeken in volledige tekst:
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=#
Meer lezen
Als u vooraf berekende / "gecachete" gegevens nodig hebt, vooral met een werkbelasting van weinig schrijfbewerkingen en veel leesbewerkingen, zouden gegenereerde kolommen uw applicatie / servercode aanzienlijk moeten vereenvoudigen.
U kunt de v12-documentatie van CREATE TABLE en ALTER TABLE lezen om de bijgewerkte syntaxis te zien.