PostgreSQL Antipatterns: ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° Π½Π°Π±ΠΎΡ€ΠΎΠ² ΠΈ Π²Ρ‹Π±ΠΎΡ€ΠΎΠΊ Π² SQL

ΠŸΠ΅Ρ€ΠΈΠΎΠ΄ΠΈΡ‡Π΅ΡΠΊΠΈ Ρƒ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Π² запрос Π½Π°Π±ΠΎΡ€ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² ΠΈΠ»ΠΈ Π΄Π°ΠΆΠ΅ Ρ†Π΅Π»ΡƒΡŽ Π²Ρ‹Π±ΠΎΡ€ΠΊΡƒ Β«Π½Π° Π²Ρ…ΠΎΠ΄Β». Иногда ΠΏΠΎΠΏΠ°Π΄Π°ΡŽΡ‚ΡΡ ΠΎΡ‡Π΅Π½ΡŒ странныС Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ этой Π·Π°Π΄Π°Ρ‡ΠΈ.
PostgreSQL Antipatterns: ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° Π½Π°Π±ΠΎΡ€ΠΎΠ² ΠΈ Π²Ρ‹Π±ΠΎΡ€ΠΎΠΊ Π² SQL
ПойдСм Β«ΠΎΡ‚ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ³ΠΎΒ» ΠΈ посмотрим, ΠΊΠ°ΠΊ Π΄Π΅Π»Π°Ρ‚ΡŒ Π½Π΅ стоит, ΠΏΠΎΡ‡Π΅ΠΌΡƒ, ΠΈ ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π»ΡƒΡ‡ΡˆΠ΅.

ΠŸΡ€ΡΠΌΠ°Ρ Β«Π²Ρ€Π΅Π·ΠΊΠ°Β» Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π² Ρ‚Π΅Π»ΠΎ запроса

Выглядит ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ‚Π°ΠΊ:

query = "SELECT * FROM tbl WHERE id = " + value

… ΠΈΠ»ΠΈ Ρ‚Π°ΠΊ:

query = "SELECT * FROM tbl WHERE id = :param".format(param=value)

ΠŸΡ€ΠΎ этот способ сказано, написано ΠΈ Π΄Π°ΠΆΠ΅ нарисовано прСдостаточно:

PostgreSQL Antipatterns: ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° Π½Π°Π±ΠΎΡ€ΠΎΠ² ΠΈ Π²Ρ‹Π±ΠΎΡ€ΠΎΠΊ Π² SQL

ΠŸΠΎΡ‡Ρ‚ΠΈ всСгда это β€” прямой ΠΏΡƒΡ‚ΡŒ ΠΊ SQL-ΠΈΠ½ΡŠΠ΅ΠΊΡ†ΠΈΡΠΌ ΠΈ лишнСй Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ Π½Π° бизнСс-Π»ΠΎΠ³ΠΈΠΊΡƒ, которая Π²Ρ‹Π½ΡƒΠΆΠ΄Π΅Π½Π° Β«ΠΊΠ»Π΅ΠΈΡ‚ΡŒΒ» строку вашСго запроса.

Частично ΠΎΠΏΡ€Π°Π²Π΄Π°Π½ Ρ‚Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² случаС нСобходимости использования сСкционирования Π² вСрсиях PostgreSQL 10 ΠΈ Π½ΠΈΠΆΠ΅ для получСния Π±ΠΎΠ»Π΅Π΅ эффСктивного ΠΏΠ»Π°Π½Π°. Π’ этих вСрсиях ΠΏΠ΅Ρ€Π΅Ρ‡Π΅Π½ΡŒ сканируСмых сСкций опрСдСляСтся Π΅Ρ‰Π΅ Π±Π΅Π· ΡƒΡ‡Π΅Ρ‚Π° ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π΅ΠΌΡ‹Ρ… ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ², Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° основании Ρ‚Π΅Π»Π° запроса.

$n-Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹

ИспользованиС плСйсхолдСров ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² β€” это Ρ…ΠΎΡ€ΠΎΡˆΠΎ, ΠΎΠ½ΠΎ позволяСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ PREPARED STATEMENTS, сниТая Π½Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ ΠΊΠ°ΠΊ Π½Π° бизнСс-Π»ΠΎΠ³ΠΈΠΊΡƒ (строка запроса формируСтся ΠΈ пСрСдаСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·), Ρ‚Π°ΠΊ ΠΈ Π½Π° сСрвСр Π‘Π” (Π½Π΅ трСбуСтся ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½Ρ‹ΠΉ Ρ€Π°Π·Π±ΠΎΡ€ ΠΈ ΠΏΠ»Π°Π½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ экзСмпляра запроса).

ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠ΅ количСство Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²

ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ Π±ΡƒΠ΄ΡƒΡ‚ ΠΆΠ΄Π°Ρ‚ΡŒ нас, ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ Π·Π°Ρ…ΠΎΡ‚ΠΈΠΌ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Π·Π°Ρ€Π°Π½Π΅Π΅ нСизвСстноС количСство Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²:

... id IN ($1, $2, $3, ...) -- $1 : 2, $2 : 3, $3 : 5, ...

Если ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ запрос Π² Ρ‚Π°ΠΊΠΎΠΌ Π²ΠΈΠ΄Π΅, Ρ‚ΠΎ это Ρ…ΠΎΡ‚ΡŒ ΠΈ ΡƒΠ±Π΅Ρ€Π΅ΠΆΠ΅Ρ‚ нас ΠΎΡ‚ ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΈΠ½ΡŠΠ΅ΠΊΡ†ΠΈΠΉ, Π½ΠΎ всС Ρ€Π°Π²Π½ΠΎ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Ρ‚ ΠΊ нСобходимости склСйки/Ρ€Π°Π·Π±ΠΎΡ€Π° запроса для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π° ΠΎΡ‚ количСства Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ². Π£ΠΆΠ΅ Π»ΡƒΡ‡ΡˆΠ΅, Ρ‡Π΅ΠΌ Π΄Π΅Π»Π°Ρ‚ΡŒ это ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π·, Π½ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±ΠΎΠΉΡ‚ΠΈΡΡŒ ΠΈ Π±Π΅Π· этого.

Достаточно ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ всСго ΠΎΠ΄ΠΈΠ½ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€, содСрТащий сСриализованноС прСдставлСниС массива:

... id = ANY($1::integer[]) -- $1 : '{2,3,5,8,13}'

ЕдинствСнноС ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ β€” Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ явно ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ Π² Π½ΡƒΠΆΠ½Ρ‹ΠΉ Ρ‚ΠΈΠΏ массива. Но это Π½Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΌΡ‹ ΠΈ Ρ‚Π°ΠΊ Π·Π°Ρ€Π°Π½Π΅Π΅ Π·Π½Π°Π΅ΠΌ, ΠΊΡƒΠ΄Π° адрСсуСмся.

ΠŸΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° Π²Ρ‹Π±ΠΎΡ€ΠΊΠΈ (ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹)

ΠžΠ±Ρ‹Ρ‡Π½ΠΎ это всякиС Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Π½Π°Π±ΠΎΡ€ΠΎΠ² Π΄Π°Π½Π½Ρ‹Ρ… для вставки Π² Π±Π°Π·Ρƒ Β«Π·Π° ΠΎΠ΄ΠΈΠ½ запрос»:

INSERT INTO tbl(k, v) VALUES($1,$2),($3,$4),...

Помимо описанных Π²Ρ‹ΡˆΠ΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ с Β«ΠΏΠ΅Ρ€Π΅ΠΊΠ»Π΅ΠΉΠΊΠΎΠΉΒ» запроса, это нас ΠΌΠΎΠΆΠ΅Ρ‚ привСсти Π΅Ρ‰Π΅ ΠΈ ΠΊ out of memory ΠΈ падСнию сСрвСра. ΠŸΡ€ΠΈΡ‡ΠΈΠ½Π° проста β€” ΠΏΠΎΠ΄ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ PG Ρ€Π΅Π·Π΅Ρ€Π²ΠΈΡ€ΡƒΠ΅Ρ‚ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΏΠ°ΠΌΡΡ‚ΡŒ, Π° количСство записСй Π² Π½Π°Π±ΠΎΡ€Π΅ ограничиваСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΡ€ΠΈΠΊΠ»Π°Π΄Π½Ρ‹ΠΌΠΈ Ρ…ΠΎΡ‚Π΅Π»ΠΊΠ°ΠΌΠΈ бизнСс-Π»ΠΎΠ³ΠΈΠΊΠΈ. Π’ особо клиничСских случаях ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΠ»ΠΎΡΡŒ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ Β«Π½ΠΎΠΌΠ΅Ρ€Π½Ρ‹Π΅Β» Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ большС $9000 β€” Π½Π΅ Π½Π°Π΄ΠΎ Ρ‚Π°ΠΊ.

ΠŸΠ΅Ρ€Π΅ΠΏΠΈΡˆΠ΅ΠΌ запрос, ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠ² ΡƒΠΆΠ΅ Β«Π΄Π²ΡƒΡ…ΡƒΡ€ΠΎΠ²Π½Π΅Π²ΡƒΡŽΒ» ΡΠ΅Ρ€ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ:

INSERT INTO tbl
SELECT
  unnest[1]::text k
, unnest[2]::integer v
FROM (
  SELECT
    unnest($1::text[])::text[] -- $1 : '{"{a,1}","{b,2}","{c,3}","{d,4}"}'
) T;

Π”Π°, Π² случаС «слоТных» Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π²Π½ΡƒΡ‚Ρ€ΠΈ массива, ΠΈΡ… трСбуСтся ΠΎΠ±Ρ€Π°ΠΌΠ»ΡΡ‚ΡŒ ΠΊΠ°Π²Ρ‹Ρ‡ΠΊΠ°ΠΌΠΈ.
ΠŸΠΎΠ½ΡΡ‚Π½ΠΎ, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΈΠΌ способом ΠΌΠΎΠΆΠ½ΠΎ Β«Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒΒ» Π²Ρ‹Π±ΠΎΡ€ΠΊΡƒ с ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹ΠΌ количСством ΠΏΠΎΠ»Π΅ΠΉ.

unnest, unnest, …

ΠŸΠ΅Ρ€ΠΈΠΎΠ΄ΠΈΡ‡Π΅ΡΠΊΠΈ Π²ΡΡ‚Ρ€Π΅Ρ‡Π°ΡŽΡ‚ΡΡ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ вмСсто «массива массивов» Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… «массивов столбцов», ΠΏΡ€ΠΎ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ я ΡƒΠΏΠΎΠΌΠΈΠ½Π°Π» Π² ΠΏΡ€ΠΎΡˆΠ»ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠ΅:

SELECT
  unnest($1::text[]) k
, unnest($2::integer[]) v;

ΠŸΡ€ΠΈ Ρ‚Π°ΠΊΠΎΠΌ способС, ошибившись ΠΏΡ€ΠΈ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ списков Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ для Ρ€Π°Π·Π½Ρ‹Ρ… столбцов, ΠΎΡ‡Π΅Π½ΡŒ просто ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ совсСм Π½Π΅ΠΎΠΆΠΈΠ΄Π°Π½Π½Ρ‹Π΅ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹, зависящиС Π΅Ρ‰Π΅ ΠΈ ΠΎΡ‚ вСрсии сСрвСра:

-- $1 : '{a,b,c}', $2 : '{1,2}'
-- PostgreSQL 9.4
k | v
-----
a | 1
b | 2
c | 1
a | 2
b | 1
c | 2
-- PostgreSQL 11
k | v
-----
a | 1
b | 2
c |

JSON

Начиная Π΅Ρ‰Π΅ с вСрсии 9.3 Π² PostgreSQL появились ΠΏΠΎΠ»Π½ΠΎΡ†Π΅Π½Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Ρ‚ΠΈΠΏΠΎΠΌ json. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ, Ссли ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² Ρƒ вас происходит Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ прямо Ρ‚Π°ΠΌ ΠΈ Ρ„ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ json-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ для SQL-запроса:

SELECT
  key k
, value v
FROM
  json_each($1::json); -- '{"a":1,"b":2,"c":3,"d":4}'

Для ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΡ… вСрсий Ρ‚Π°ΠΊΠΎΠΉ ΠΆΠ΅ способ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для each(hstore), Π½ΠΎ коррСктная «свСртка» с экранированиСм слоТных ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π² hstore ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹.

json_populate_recordset

Если Π²Ρ‹ Π·Π°Ρ€Π°Π½Π΅Π΅ Π·Π½Π°Π΅Ρ‚Π΅, Ρ‡Ρ‚ΠΎ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· Β«Π²Ρ…ΠΎΠ΄Π½ΠΎΠ³ΠΎΒ» json-массива ΠΏΠΎΠΉΠ΄ΡƒΡ‚ для заполнСния ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, ΠΌΠΎΠΆΠ½ΠΎ сильно ΡΡΠΊΠΎΠ½ΠΎΠΌΠΈΡ‚ΡŒ Π² Β«Ρ€Π°Π·Ρ‹ΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠΈΒ» ΠΏΠΎΠ»Π΅ΠΉ ΠΈ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ΠΈΠΈ ΠΊ Π½ΡƒΠΆΠ½Ρ‹ΠΌ Ρ‚ΠΈΠΏΠ°ΠΌ, воспользовавшись Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ json_populate_recordset:

SELECT
  *
FROM
  json_populate_recordset(
    NULL::pg_class
  , $1::json -- $1 : '[{"relname":"pg_class","oid":1262},{"relname":"pg_namespace","oid":2615}]'
  );

json_to_recordset

А эта функция просто Β«Ρ€Π°Π·Π²Π΅Ρ€Π½Π΅Ρ‚Β» ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹ΠΉ массив ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π² Π²Ρ‹Π±ΠΎΡ€ΠΊΡƒ, Π½Π΅ ΠΎΠΏΠΈΡ€Π°ΡΡΡŒ Π½Π° Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹:

SELECT
  *
FROM
  json_to_recordset($1::json) T(k text, v integer);
-- $1 : '[{"k":"a","v":1},{"k":"b","v":2}]'
k | v
-----
a | 1
b | 2

TEMPORARY TABLE

Но Ссли объСм Π΄Π°Π½Π½Ρ‹Ρ… Π² ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π΅ΠΌΠΎΠΉ Π²Ρ‹Π±ΠΎΡ€ΠΊΠ΅ ΠΎΡ‡Π΅Π½ΡŒ Π²Π΅Π»ΠΈΠΊ, Ρ‚ΠΎ Π·Π°ΠΊΠΈΠ½ΡƒΡ‚ΡŒ Π΅Π³ΠΎ Π² ΠΎΠ΄ΠΈΠ½ сСриализованный ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ β€” тяТСло, Π° ΠΈΠ½ΠΎΠ³Π΄Π° ΠΈ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Ρ€Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ выдСлСния большого объСма памяти. НапримСр, Π²Π°ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π΄ΠΎΠ»Π³ΠΎ-Π΄ΠΎΠ»Π³ΠΎ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ большой ΠΏΠ°ΠΊΠ΅Ρ‚ Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎ событиям ΠΈΠ· внСшнСй систСмы, Π° ΠΏΠΎΡ‚ΠΎΠΌ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ Ρ€Π°Π·ΠΎΠ²ΠΎ Π΅Π³ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π½Π° сторонС Π‘Π”.

Π’ этом случаС Π»ΡƒΡ‡ΡˆΠΈΠΌ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ΠΌ станСт использованиС Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… Ρ‚Π°Π±Π»ΠΈΡ†:

CREATE TEMPORARY TABLE tbl(k text, v integer);
...
INSERT INTO tbl(k, v) VALUES($1, $2); -- ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚ΡŒ ΠΌΠ½ΠΎΠ³ΠΎ-ΠΌΠ½ΠΎΠ³ΠΎ Ρ€Π°Π·
...
-- Ρ‚ΡƒΡ‚ Π΄Π΅Π»Π°Π΅ΠΌ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠ΅ со всСй этой Ρ‚Π°Π±Π»ΠΈΡ†Π΅ΠΉ Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ

Бпособ Ρ…ΠΎΡ€ΠΎΡˆ ΠΈΠΌΠ΅Π½Π½ΠΎ для Ρ€Π΅Π΄ΠΊΠΎΠΉ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Π±ΠΎΠ»ΡŒΡˆΠΈΡ… объСмов Π΄Π°Π½Π½Ρ‹Ρ….
Π‘ Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния описания структуры своих Π΄Π°Π½Π½Ρ‹Ρ… врСмСнная Ρ‚Π°Π±Π»ΠΈΡ†Π° отличаСтся ΠΎΡ‚ Β«ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΉΒ» Ρ‚ΠΎΠ»ΡŒΠΊΠΎ лишь ΠΎΠ΄Π½ΠΈΠΌ ΠΏΡ€ΠΈΠ·Π½Π°ΠΊΠΎΠΌ Π² систСмной Ρ‚Π°Π±Π»ΠΈΡ†Π΅ pg_class, Π° Π² pg_type, pg_depend, pg_attribute, pg_attrdef, … β€” Ρ‚Π°ΠΊ ΠΈ вовсС Π½ΠΈΡ‡Π΅ΠΌ.

ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Π² web-систСмах с большим количСством ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΎΠΆΠΈΠ²ΡƒΡ‰ΠΈΡ… ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΈΠ· Π½ΠΈΡ… такая Ρ‚Π°Π±Π»ΠΈΡ†Π° Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΡ€ΠΎΠΆΠ΄Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹Π΅ систСмныС записи ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π·, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡƒΠ΄Π°Π»ΡΡŽΡ‚ΡΡ с Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ΠΌ соСдинСния с Π‘Π”. Π’ ΠΈΡ‚ΠΎΠ³Π΅, Π½Π΅ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΡƒΠ΅ΠΌΠΎΠ΅ использованиС TEMP TABLE ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ Β«Ρ€Π°ΡΠΏΡƒΡ…Π°Π½ΠΈΡŽΒ» Ρ‚Π°Π±Π»ΠΈΡ† Π² pg_catalog ΠΈ замСдлСнию ΠΌΠ½ΠΎΠ³ΠΈΡ… ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΡ… ΠΈΡ….
ΠšΠΎΠ½Π΅Ρ‡Π½ΠΎ, с этим ΠΌΠΎΠΆΠ½ΠΎ Π±ΠΎΡ€ΠΎΡ‚ΡŒΡΡ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ пСриодичСского ΠΏΡ€ΠΎΡ…ΠΎΠ΄Π° VACUUM FULL ΠΏΠΎ Ρ‚Π°Π±Π»ΠΈΡ†Π°ΠΌ систСмного ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π°.

ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ сСссии

ΠŸΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ· ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π³ΠΎ случая достаточно слоТна для ΠΎΠ΄Π½ΠΎΠ³ΠΎ SQL-запроса, Π½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ Π΅Π΅ хочСтся достаточно часто. Π’ΠΎ Π΅ΡΡ‚ΡŒ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΡ†Π΅Π΄ΡƒΡ€Π½ΡƒΡŽ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ Π² DO-Π±Π»ΠΎΠΊΠ΅, Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… Ρ‡Π΅Ρ€Π΅Π· Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π±ΡƒΠ΄Π΅Ρ‚ слишком Π½Π°ΠΊΠ»Π°Π΄Π½ΠΎ.

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ $n-ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Π² Π°Π½ΠΎΠ½ΠΈΠΌΠ½Ρ‹ΠΉ Π±Π»ΠΎΠΊ ΠΌΡ‹ Ρ‚ΠΎΠΆΠ΅ Π½Π΅ смоТСм. Π’Ρ‹ΠΉΡ‚ΠΈ ΠΈΠ· полоТСния Π½Π°ΠΌ ΠΏΠΎΠΌΠΎΠ³ΡƒΡ‚ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ сСссии ΠΈ функция current_setting.

Π”ΠΎ вСрсии 9.2 Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π±Ρ‹Π»ΠΎ ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΡΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ΅ пространство ΠΈΠΌΠ΅Π½ custom_variable_classes для «своих» ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… сСссии. На Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΆΠ΅ вСрсиях ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ‚Π°ΠΊ:

SET my.val = '{1,2,3}';
DO $$
DECLARE
  id integer;
BEGIN
  FOR id IN (SELECT unnest(current_setting('my.val')::integer[])) LOOP
    RAISE NOTICE 'id : %', id;
  END LOOP;
END;
$$ LANGUAGE plpgsql;
-- NOTICE:  id : 1
-- NOTICE:  id : 2
-- NOTICE:  id : 3

На Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅ΠΌΡ‹Ρ… ΠΏΡ€ΠΎΡ†Π΅Π΄ΡƒΡ€Π½Ρ‹Ρ… языках ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ.

Π—Π½Π°Π΅Ρ‚Π΅ Π΅Ρ‰Π΅ способы? ΠŸΠΎΠ΄Π΅Π»ΠΈΡ‚Π΅ΡΡŒ Π² коммСнтариях!

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com