PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Ново в PostgreSQL 12:Генерирани колони

PostgreSQL 12 идва с нова функция, наречена генерирани колони . Други популярни RDBMS вече поддържат генерирани колони като „изчислени колони“ или „виртуални колони“. С Postgres 12 вече можете да го използвате и в PostgreSQL. Прочетете, за да научите повече.

Какво е генерирана колона?

Генерираната колона е нещо като изглед, но за колони. Ето един основен пример:

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=#

Създадохме таблицаt с две редовни колони, наречени w из , и генерирана колона, наречена област . Стойността на площа се изчислява по време на създаване на ред и се запазва на диска.

Стойността на генерираните колони се преизчислява, когато редът се актуализира:

db=# UPDATE t SET w=40;
UPDATE 1
db=# SELECT * FROM t;
 w  | h  | area
----+----+------
 40 | 20 |  800
(1 row)

db=#

По-рано такава функционалност обикновено се постигаше с тригери, но с генерирани колони това става много по-елегантно и по-чисто.

Няколко точки, които трябва да знаете за генерираните колони:

  • Постоянство :В момента стойността на генерираните колони трябва да бъде запазена и не може да бъде изчислена в движение по време на заявка. Ключовата дума „STORED“ трябва да присъства в дефиницията на колоната.
  • Изразът :Изразът, използван за изчисляване на стойността, трябва да енеизменяем , тоест трябва да е детерминистично. Може да зависи от други колони, но не и от други генерирани колони на таблицата.
  • Индекси :Генерираните колони могат да се използват в индекси, но не могат да се използват като ключ на дял за разделени таблици.
  • Копиране и pg_dump :Стойностите на генерираните колони се пропускат в изхода на командите “pg_dump” и “COPY table”, тъй като не е необходимо. Можете изрично да ги включите в COPY, като използвате COPY (SELECT * FROM t) TO STDOUT вместо COPY t TO STDOUT .

Практически пример

Нека добавим поддръжка за пълно текстово търсене към таблица, използвайки генерирани колони. Ето таблица, която съхранява целия текст на всички пиеси на Шекспир:

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
);

Ето как изглеждат данните:

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)

Ще добавим колона, която ще съдържа лексемите в стойността на “body”. Функцията to_tsvector връща лексемите, от които се нуждаем:

shakespeare=# SELECT to_tsvector('english', 'move moving moved movable mover movability');
             to_tsvector
-------------------------------------
 'movabl':4,6 'move':1,2,3 'mover':5
(1 row)

Типът на стойността, върната от to_tsvector е цветен.

Нека променим таблицата, за да добавим генерирана колона:

ALTER TABLE scenes
  ADD tsv tsvector
    GENERATED ALWAYS AS (to_tsvector('english', body)) STORED;

Можете да видите промяната с \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)

И точно така, вече можете да извършвате пълнотекстови търсения:

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=#

Прочетете повече

Ако имате нужда от предварително изчислени / „кеширани“ данни, особено при натоварване от няколко записвания и много четения, генерираните колони трябва да помогнат за опростяване на кода на приложението/сървъра много.

Можете да прочетете документацията v12 на CREATE TABLE и ALTER TABLE, за да видите актуализирания синтаксис.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. sql ПОРЪЧАЙТЕ ПО множество стойности в определен ред?

  2. Как да получа броя на неделята на текущия месец в psql?

  3. Връщане на списък с часови зони, поддържани от PostgreSQL

  4. Oracle към PostgreSQL — Курсори и ltrees

  5. PostgreSQL управление и автоматизация с ClusterControl