ΠΡΠΎΠ΄ΠΎΠ»ΠΆΠ°Π΅ΠΌ ΡΠ΅ΡΠΈΡ ΡΡΠ°ΡΠ΅ΠΉ, ΠΏΠΎΡΠ²ΡΡΠ΅Π½Π½ΡΡ ΠΈΡΡΠ»Π΅Π΄ΠΎΠ²Π°Π½ΠΈΡ ΠΌΠ°Π»ΠΎΠΈΠ·Π²Π΅ΡΡΠ½ΡΡ ΡΠΏΠΎΡΠΎΠ±ΠΎΠ² ΡΠ»ΡΡΡΠ΅Π½ΠΈΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ Β«Π²ΡΠΎΠ΄Π΅ Π±Ρ ΠΏΡΠΎΡΡΡΡ Β» Π·Π°ΠΏΡΠΎΡΠΎΠ² Π½Π° PostgreSQL:
ΡΠ΅Π΄ΠΊΠ°Ρ Π·Π°ΠΏΠΈΡΡ Π΄ΠΎΠ»Π΅ΡΠΈΡ Π΄ΠΎ ΡΠ΅ΡΠ΅Π΄ΠΈΠ½Ρ JOIN ΡΠΈΠ·ΠΈΡΠΎΠ² JOIN ΠΌΠ°ΡΡΠΈΠ²ΠΎΠ² Π²ΡΠ΅Π΄Π½ΡΠ΅ JOIN ΠΈ OR CTE JOIN CTE
ΠΠ΅ ΠΏΠΎΠ΄ΡΠΌΠ°ΠΉΡΠ΅, ΡΡΠΎ Ρ ΡΠ°ΠΊ ΡΠΈΠ»ΡΠ½ΠΎ Π½Π΅ Π»ΡΠ±Π»Ρ JOINβ¦ π
ΠΠΎ Π·Π°ΡΠ°ΡΡΡΡ Π±Π΅Π· Π½Π΅Π³ΠΎ Π·Π°ΠΏΡΠΎΡ ΠΏΠΎΠ»ΡΡΠ°Π΅ΡΡΡ ΠΎΡΡΡΠΈΠΌΠΎ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½Π΅Π΅, ΡΠ΅ΠΌ Ρ Π½ΠΈΠΌ. ΠΠΎΡΡΠΎΠΌΡ ΡΠ΅Π³ΠΎΠ΄Π½Ρ ΠΏΠΎΠΏΡΠΎΠ±ΡΠ΅ΠΌ Π²ΠΎΠΎΠ±ΡΠ΅ ΠΈΠ·Π±Π°Π²ΠΈΡΡΡΡ ΠΎΡ ΡΠ΅ΡΡΡΡΠΎΠ΅ΠΌΠΊΠΎΠ³ΠΎ JOIN β Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΡΠ»ΠΎΠ²Π°ΡΡ.
ΠΠ°ΡΠΈΠ½Π°Ρ Ρ PostgreSQL 12 ΡΠ°ΡΡΡ ΠΎΠΏΠΈΡΠ°Π½Π½ΡΡ Π½ΠΈΠΆΠ΅ ΡΠΈΡΡΠ°ΡΠΈΠΉ ΠΌΠΎΠΆΠ΅Ρ Π²ΠΎΡΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΡΡΡ ΡΡΡΡ ΠΈΠ½Π°ΡΠ΅ ΠΈΠ·-Π·Π°
Π½Π΅-ΠΌΠ°ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ CTE ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ . ΠΡΠΎ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ Π²ΠΎΠ·Π²ΡΠ°ΡΠ΅Π½ΠΎ ΠΊ ΠΏΡΠ΅ΠΆΠ½Π΅ΠΌΡ Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΡΠΊΠ°Π·Π°Π½ΠΈΡ ΠΊΠ»ΡΡΠ°MATERIALIZED
.
ΠΠ½ΠΎΠ³ΠΎ Β«ΡΠ°ΠΊΡΠΎΠ²Β» ΠΏΠΎ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½Π½ΠΎΠΌΡ ΡΠ»ΠΎΠ²Π°ΡΡ
ΠΠ°Π²Π°ΠΉΡΠ΅ Π²ΠΎΠ·ΡΠΌΠ΅ΠΌ Π²ΠΏΠΎΠ»Π½Π΅ ΡΠ΅Π°Π»ΡΠ½ΡΡ ΠΏΡΠΈΠΊΠ»Π°Π΄Π½ΡΡ Π·Π°Π΄Π°ΡΡ β Π½Π°Π΄ΠΎ Π²ΡΠ²Π΅ΡΡΠΈ ΡΠΏΠΈΡΠΎΠΊ
25.01 | ΠΠ²Π°Π½ΠΎΠ² Π.Π. | ΠΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΈΡΡ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ Π°Π»Π³ΠΎΡΠΈΡΠΌΠ°.
22.01 | ΠΠ²Π°Π½ΠΎΠ² Π.Π. | ΠΠ°ΠΏΠΈΡΠ°ΡΡ ΡΡΠ°ΡΡΡ Π½Π° Π₯Π°Π±Ρ: ΠΆΠΈΠ·Π½Ρ Π±Π΅Π· JOIN.
20.01 | ΠΠ΅ΡΡΠΎΠ² Π.Π. | ΠΠΎΠΌΠΎΡΡ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ Π·Π°ΠΏΡΠΎΡ.
18.01 | ΠΠ²Π°Π½ΠΎΠ² Π.Π. | ΠΠ°ΠΏΠΈΡΠ°ΡΡ ΡΡΠ°ΡΡΡ Π½Π° Π₯Π°Π±Ρ: JOIN Ρ ΡΡΠ΅ΡΠΎΠΌ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ Π΄Π°Π½Π½ΡΡ
.
16.01 | ΠΠ΅ΡΡΠΎΠ² Π.Π. | ΠΠΎΠΌΠΎΡΡ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ Π·Π°ΠΏΡΠΎΡ.
Π Π°Π±ΡΡΡΠ°ΠΊΡΠ½ΠΎΠΌ ΠΌΠΈΡΠ΅ Π°Π²ΡΠΎΡΡ Π·Π°Π΄Π°Ρ Π΄ΠΎΠ»ΠΆΠ½Ρ Π±ΡΠ»ΠΈ Π±Ρ ΡΠ°Π²Π½ΠΎΠΌΠ΅ΡΠ½ΠΎ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»ΡΡΡΡΡ ΡΡΠ΅Π΄ΠΈ Π²ΡΠ΅Ρ ΡΠΎΡΡΡΠ΄Π½ΠΈΠΊΠΎΠ² Π½Π°ΡΠ΅ΠΉ ΠΎΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΠΈ, Π½ΠΎ Π² ΡΠ΅Π°Π»ΡΠ½ΠΎΡΡΠΈ Π·Π°Π΄Π°ΡΠΈ ΠΏΡΠΈΡ ΠΎΠ΄ΡΡ, ΠΊΠ°ΠΊ ΠΏΡΠ°Π²ΠΈΠ»ΠΎ, ΠΎΡ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π° Π»ΡΠ΄Π΅ΠΉ β Β«ΠΎΡ Π½Π°ΡΠ°Π»ΡΡΡΠ²Π°Β» Π²Π²Π΅ΡΡ ΠΏΠΎ ΠΈΠ΅ΡΠ°ΡΡ ΠΈΠΈ ΠΈΠ»ΠΈ Β«ΠΎΡ ΡΠΌΠ΅ΠΆΠ½ΠΈΠΊΠΎΠ²Β» ΠΈΠ· ΡΠΎΡΠ΅Π΄Π½ΠΈΡ ΠΎΡΠ΄Π΅Π»ΠΎΠ² (Π°Π½Π°Π»ΠΈΡΠΈΠΊΠΈ, Π΄ΠΈΠ·Π°ΠΉΠ½Π΅ΡΡ, ΠΌΠ°ΡΠΊΠ΅ΡΠΈΠ½Π³, …).
ΠΠ°Π²Π°ΠΉΡΠ΅ ΠΏΡΠΈΠΌΠ΅ΠΌ, ΡΡΠΎ Π² Π½Π°ΡΠ΅ΠΉ ΠΎΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΠΈ ΠΈΠ· 1000 ΡΠ΅Π»ΠΎΠ²Π΅ΠΊ ΡΠΎΠ»ΡΠΊΠΎ 20 Π°Π²ΡΠΎΡΠΎΠ² (ΠΎΠ±ΡΡΠ½ΠΎ Π΄Π°ΠΆΠ΅ ΠΌΠ΅Π½ΡΡΠ΅) ΡΡΠ°Π²ΡΡ Π·Π°Π΄Π°ΡΠΈ Π² Π°Π΄ΡΠ΅Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΈΡΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»Ρ ΠΈ
Π‘ΠΊΡΠΈΠΏΡ-Π³Π΅Π½Π΅ΡΠ°ΡΠΎΡ
-- ΡΠΎΡΡΡΠ΄Π½ΠΈΠΊΠΈ
CREATE TABLE person AS
SELECT
id
, repeat(chr(ascii('a') + (id % 26)), (id % 32) + 1) "name"
, '2000-01-01'::date - (random() * 1e4)::integer birth_date
FROM
generate_series(1, 1000) id;
ALTER TABLE person ADD PRIMARY KEY(id);
-- Π·Π°Π΄Π°ΡΠΈ Ρ ΡΠΊΠ°Π·Π°Π½Π½ΡΠΌ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ΠΌ
CREATE TABLE task AS
WITH aid AS (
SELECT
id
, array_agg((random() * 999)::integer + 1) aids
FROM
generate_series(1, 1000) id
, generate_series(1, 20)
GROUP BY
1
)
SELECT
*
FROM
(
SELECT
id
, '2020-01-01'::date - (random() * 1e3)::integer task_date
, (random() * 999)::integer + 1 owner_id
FROM
generate_series(1, 100000) id
) T
, LATERAL(
SELECT
aids[(random() * (array_length(aids, 1) - 1))::integer + 1] author_id
FROM
aid
WHERE
id = T.owner_id
LIMIT 1
) a;
ALTER TABLE task ADD PRIMARY KEY(id);
CREATE INDEX ON task(owner_id, task_date);
CREATE INDEX ON task(author_id);
ΠΠΎΠΊΠ°ΠΆΠ΅ΠΌ ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΠ΅ 100 Π·Π°Π΄Π°Ρ Π΄Π»Ρ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΈΡΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»Ρ:
SELECT
task.*
, person.name
FROM
task
LEFT JOIN
person
ON person.id = task.author_id
WHERE
owner_id = 777
ORDER BY
task_date DESC
LIMIT 100;
ΠΠΎΠ»ΡΡΠ°Π΅ΡΡΡ, ΡΡΠΎ 1/3 Π²ΡΠ΅Π³ΠΎ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ ΠΈ 3/4 ΡΡΠ΅Π½ΠΈΠΉ ΡΡΡΠ°Π½ΠΈΡ Π΄Π°Π½Π½ΡΡ Π±ΡΠ»ΠΈ ΡΠ΄Π΅Π»Π°Π½Ρ ΡΠΎΠ»ΡΠΊΠΎ Π΄Π»Ρ ΡΠΎΠ³ΠΎ, ΡΡΠΎΠ±Ρ 100 ΡΠ°Π· ΠΏΠΎΠΈΡΠΊΠ°ΡΡ Π°Π²ΡΠΎΡΠ° β Π΄Π»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ Π²ΡΠ²ΠΎΠ΄ΠΈΠΌΠΎΠΉ Π·Π°Π΄Π°ΡΠΈ. ΠΠΎ ΠΌΡ ΠΆΠ΅ Π·Π½Π°Π΅ΠΌ, ΡΡΠΎ ΡΡΠ΅Π΄ΠΈ ΡΡΠΎΠΉ ΡΠΎΡΠ½ΠΈ Π²ΡΠ΅Π³ΠΎ 20 ΡΠ°Π·Π½ΡΡ β Π½Π΅Π»ΡΠ·Ρ Π»ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΡΠΎ Π·Π½Π°Π½ΠΈΠ΅?
hstore-ΡΠ»ΠΎΠ²Π°ΡΡ
ΠΠΎΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΡ
CREATE EXTENSION hstore
Π ΡΠ»ΠΎΠ²Π°ΡΡ Π½Π°ΠΌ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ ΠΏΠΎΠΌΠ΅ΡΡΠΈΡΡ ID Π°Π²ΡΠΎΡΠ° ΠΈ Π΅Π³ΠΎ ΠΈΠΌΡ, ΡΡΠΎΠ±Ρ ΠΏΠΎΡΠΎΠΌ ΠΈΠΌΠ΅ΡΡ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ ΠΈΠ·Π²Π»Π΅ΡΡ ΠΏΠΎ ΡΡΠΎΠΌΡ ΠΊΠ»ΡΡΡ:
-- ΡΠΎΡΠΌΠΈΡΡΠ΅ΠΌ ΡΠ΅Π»Π΅Π²ΡΡ Π²ΡΠ±ΠΎΡΠΊΡ
WITH T AS (
SELECT
*
FROM
task
WHERE
owner_id = 777
ORDER BY
task_date DESC
LIMIT 100
)
-- ΡΠΎΡΠΌΠΈΡΡΠ΅ΠΌ ΡΠ»ΠΎΠ²Π°ΡΡ Π΄Π»Ρ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΡ
Π·Π½Π°ΡΠ΅Π½ΠΈΠΉ
, dict AS (
SELECT
hstore( -- hstore(keys::text[], values::text[])
array_agg(id)::text[]
, array_agg(name)::text[]
)
FROM
person
WHERE
id = ANY(ARRAY(
SELECT DISTINCT
author_id
FROM
T
))
)
-- ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌ ΡΠ²ΡΠ·Π°Π½Π½ΡΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΡ ΡΠ»ΠΎΠ²Π°ΡΡ
SELECT
*
, (TABLE dict) -> author_id::text -- hstore -> key
FROM
T;
ΠΠ° ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ ΠΎ ΠΏΠ΅ΡΡΠΎΠ½Π°Ρ
Π·Π°ΡΡΠ°ΡΠ΅Π½ΠΎ Π² 2 ΡΠ°Π·Π° ΠΌΠ΅Π½ΡΡΠ΅ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ ΠΈ Π² 7 ΡΠ°Π· ΠΌΠ΅Π½ΡΡΠ΅ ΠΏΡΠΎΡΠΈΡΠ°Π½ΠΎ Π΄Π°Π½Π½ΡΡ
! ΠΠΎΠΌΠΈΠΌΠΎ Β«ΠΎΡΠ»ΠΎΠ²Π°ΡΠΈΠ²Π°Π½ΠΈΡΒ», ΡΡΠΈΡ
ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ² Π½Π°ΠΌ ΠΏΠΎΠΌΠΎΠ³Π»ΠΎ Π΄ΠΎΡΡΠΈΡΡ Π΅ΡΠ΅ ΠΈ ΠΌΠ°ΡΡΠΎΠ²ΠΎΠ΅ ΠΈΠ·Π²Π»Π΅ΡΠ΅Π½ΠΈΠ΅ Π·Π°ΠΏΠΈΡΠ΅ΠΉ ΠΈΠ· ΡΠ°Π±Π»ΠΈΡΡ Π·Π° Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½Π½ΡΠΉ ΠΏΡΠΎΡ
ΠΎΠ΄ Ρ ΠΏΠΎΠΌΠΎΡΡΡ = ANY(ARRAY(...))
.
ΠΠ°ΠΏΠΈΡΠΈ ΡΠ°Π±Π»ΠΈΡΡ: ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΈ Π΄Π΅ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ
ΠΠΎ ΡΡΠΎ Π΄Π΅Π»Π°ΡΡ, Π΅ΡΠ»ΠΈ Π½Π°ΠΌ Π½ΡΠΆΠ½ΠΎ ΡΠΎΡ ΡΠ°Π½ΠΈΡΡ Π² ΡΠ»ΠΎΠ²Π°ΡΠ΅ Π½Π΅ ΠΎΠ΄Π½ΠΎ ΡΠ΅ΠΊΡΡΠΎΠ²ΠΎΠ΅ ΠΏΠΎΠ»Π΅, Π° ΡΠ΅Π»ΡΡ Π·Π°ΠΏΠΈΡΡ? Π ΡΡΠΎΠΌ ΡΠ»ΡΡΠ°Π΅ Π½Π°ΠΌ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ ΡΠΏΠΎΡΠΎΠ±Π½ΠΎΡΡΡ PostgreSQL ΡΠ°Π±ΠΎΡΠ°ΡΡ Ρ Π·Π°ΠΏΠΈΡΡΡ ΡΠ°Π±Π»ΠΈΡΡ ΠΊΠ°ΠΊ Ρ Π΅Π΄ΠΈΠ½ΡΠΌ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ΠΌ:
...
, dict AS (
SELECT
hstore(
array_agg(id)::text[]
, array_agg(p)::text[] -- ΠΌΠ°Π³ΠΈΡ #1
)
FROM
person p
WHERE
...
)
SELECT
*
, (((TABLE dict) -> author_id::text)::person).* -- ΠΌΠ°Π³ΠΈΡ #2
FROM
T;
ΠΠ°Π²Π°ΠΉΡΠ΅ ΡΠ°Π·Π±Π΅ΡΠ΅ΠΌ, ΡΡΠΎ ΡΡΡ Π²ΠΎΠΎΠ±ΡΠ΅ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΠ»ΠΎ:
- ΠΡ Π²Π·ΡΠ»ΠΈ p ΠΊΠ°ΠΊ Π°Π»ΠΈΠ°Ρ ΠΊ ΠΏΠΎΠ»Π½ΠΎΠΉ Π·Π°ΠΏΠΈΡΠΈ ΡΠ°Π±Π»ΠΈΡΡ person ΠΈ ΡΠΎΠ±ΡΠ°Π»ΠΈ ΠΈΠ· Π½ΠΈΡ ΠΌΠ°ΡΡΠΈΠ².
- ΠΡΠΎΡ ΠΌΠ°ΡΡΠΈΠ² Π·Π°ΠΏΠΈΡΠ΅ΠΉ ΠΏΠ΅ΡΠ΅ΠΊΠ°ΡΡΠΎΠ²Π°Π»ΠΈ Π² ΠΌΠ°ΡΡΠΈΠ² ΡΠ΅ΠΊΡΡΠΎΠ²ΡΡ ΡΡΡΠΎΠΊ (person[]::text[]), ΡΡΠΎΠ±Ρ ΠΏΠΎΠΌΠ΅ΡΡΠΈΡΡ Π΅Π³ΠΎ Π² hstore-ΡΠ»ΠΎΠ²Π°ΡΡ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΠΌΠ°ΡΡΠΈΠ²Π° Π·Π½Π°ΡΠ΅Π½ΠΈΠΉ.
- ΠΡΠΈ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠΈ ΡΠ²ΡΠ·Π°Π½Π½ΠΎΠΉ Π·Π°ΠΏΠΈΡΠΈ ΠΌΡ Π΅Π΅ Π²ΡΡΠ°ΡΠΈΠ»ΠΈ ΠΈΠ· ΡΠ»ΠΎΠ²Π°ΡΡ ΠΏΠΎ ΠΊΠ»ΡΡΡ ΠΊΠ°ΠΊ ΡΠ΅ΠΊΡΡΠΎΠ²ΡΡ ΡΡΡΠΎΠΊΡ.
- Π’Π΅ΠΊΡΡ Π½Π°ΠΌ Π½ΡΠΆΠ½ΠΎ ΠΏΡΠ΅Π²ΡΠ°ΡΠΈΡΡ Π² Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΡΠΈΠΏΠ° ΡΠ°Π±Π»ΠΈΡΡ person (Π΄Π»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΠ°Π±Π»ΠΈΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΠΎΠ·Π΄Π°Π΅ΡΡΡ ΠΎΠ΄Π½ΠΎΠΈΠΌΠ΅Π½Π½ΡΠΉ Π΅ΠΉ ΡΠΈΠΏ).
- Β«Π Π°Π·Π²Π΅ΡΠ½ΡΠ»ΠΈΒ» ΡΠΈΠΏΠΈΠ·ΠΎΠ²Π°Π½Π½ΡΡ Π·Π°ΠΏΠΈΡΡ Π² ΡΡΠΎΠ»Π±ΡΡ Ρ ΠΏΠΎΠΌΠΎΡΡΡ
(...).*
.
json-ΡΠ»ΠΎΠ²Π°ΡΡ
ΠΠΎ ΡΠ°ΠΊΠΎΠΉ ΡΠΎΠΊΡΡ, ΠΊΠ°ΠΊ ΠΌΡ ΠΏΡΠΈΠΌΠ΅Π½ΠΈΠ»ΠΈ Π²ΡΡΠ΅, Π½Π΅ ΠΏΡΠΎΠΉΠ΄Π΅Ρ, Π΅ΡΠ»ΠΈ Π½Π΅Ρ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠ΅Π³ΠΎ ΡΠ°Π±Π»ΠΈΡΠ½ΠΎΠ³ΠΎ ΡΠΈΠΏΠ°, ΡΡΠΎΠ±Ρ ΡΠ΄Π΅Π»Π°ΡΡ Β«ΡΠ°ΡΠΊΠ°ΡΡΠΎΠ²ΠΊΡΒ». Π ΠΎΠ²Π½ΠΎ ΡΠ°ΠΊΠ°Ρ ΠΆΠ΅ ΡΠΈΡΡΠ°ΡΠΈΡ Π²ΠΎΠ·Π½ΠΈΠΊΠ½Π΅Ρ, ΠΈ Π΅ΡΠ»ΠΈ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΠΈΡΡΠΎΡΠ½ΠΈΠΊΠ° Π΄Π°Π½Π½ΡΡ Π΄Π»Ρ ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΠΌΡ ΠΏΠΎΠΏΡΠΎΠ±ΡΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΡΡΠΎΠΊΡ CTE, Π° Π½Π΅ Β«ΡΠ΅Π°Π»ΡΠ½ΠΎΠΉΒ» ΡΠ°Π±Π»ΠΈΡΡ.
Π ΡΡΠΎΠΌ ΡΠ»ΡΡΠ°Π΅ Π½Π°ΠΌ ΠΏΠΎΠΌΠΎΠ³ΡΡ
...
, p AS ( -- ΡΡΠΎ ΡΠΆΠ΅ CTE
SELECT
*
FROM
person
WHERE
...
)
, dict AS (
SELECT
json_object( -- ΡΠ΅ΠΏΠ΅ΡΡ ΡΡΠΎ ΡΠΆΠ΅ json
array_agg(id)::text[]
, array_agg(row_to_json(p))::text[] -- ΠΈ Π²Π½ΡΡΡΠΈ json Π΄Π»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΡΡΠΎΠΊΠΈ
)
FROM
p
)
SELECT
*
FROM
T
, LATERAL(
SELECT
*
FROM
json_to_record(
((TABLE dict) ->> author_id::text)::json -- ΠΈΠ·Π²Π»Π΅ΠΊΠ»ΠΈ ΠΈΠ· ΡΠ»ΠΎΠ²Π°ΡΡ ΠΊΠ°ΠΊ json
) AS j(name text, birth_date date) -- Π·Π°ΠΏΠΎΠ»Π½ΠΈΠ»ΠΈ Π½ΡΠΆΠ½ΡΡ Π½Π°ΠΌ ΡΡΡΡΠΊΡΡΡΡ
) j;
ΠΠ°Π΄ΠΎ ΠΎΡΠΌΠ΅ΡΠΈΡΡ, ΡΡΠΎ ΠΏΡΠΈ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠΈ ΡΠ΅Π»Π΅Π²ΠΎΠΉ ΡΡΡΡΠΊΡΡΡΡ ΠΌΡ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠ΅ΡΠ΅ΡΠΈΡΠ»ΡΡΡ Π½Π΅ Π²ΡΠ΅ ΠΏΠΎΠ»Ρ ΠΈΡΡ
ΠΎΠ΄Π½ΠΎΠΉ ΡΡΡΠΎΠΊΠΈ, Π° ΡΠΎΠ»ΡΠΊΠΎ ΡΠ΅, ΠΊΠΎΡΠΎΡΡΠ΅ Π½Π°ΠΌ Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΠΎ Π½ΡΠΆΠ½Ρ. ΠΡΠ»ΠΈ ΠΆΠ΅ Ρ Π½Π°Ρ Π΅ΡΡΡ Β«ΡΠΎΠ΄Π½Π°ΡΒ» ΡΠ°Π±Π»ΠΈΡΠ°, ΡΠΎ Π»ΡΡΡΠ΅ Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡΡΡ ΡΡΠ½ΠΊΡΠΈΠ΅ΠΉ json_populate_record
.
ΠΠΎΡΡΡΠΏ ΠΊ ΡΠ»ΠΎΠ²Π°ΡΡ Ρ Π½Π°Ρ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΡ ΠΏΠΎ-ΠΏΡΠ΅ΠΆΠ½Π΅ΠΌΡ ΠΎΠ΄Π½ΠΎΠΊΡΠ°ΡΠ½ΠΎ, Π½ΠΎ ΠΈΠ·Π΄Π΅ΡΠΆΠΊΠΈ Π½Π° json-[Π΄Π΅]ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ Π²Π΅Π»ΠΈΠΊΠΈ, ΠΏΠΎΡΡΠΎΠΌΡ ΡΠ°ΠΊΠΈΠΌ ΡΠΏΠΎΡΠΎΠ±ΠΎΠΌ ΡΠ°Π·ΡΠΌΠ½ΠΎ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡΡΡ ΡΠΎΠ»ΡΠΊΠΎ Π² Π½Π΅ΠΊΠΎΡΠΎΡΡΡ ΡΠ»ΡΡΠ°ΡΡ , ΠΊΠΎΠ³Π΄Π° Β«ΡΠ΅ΡΡΠ½ΡΠΉΒ» CTE Scan ΠΏΠΎΠΊΠ°Π·ΡΠ²Π°Π΅Ρ ΡΠ΅Π±Ρ Ρ ΡΠΆΠ΅.
Π’Π΅ΡΡΠΈΡΡΠ΅ΠΌ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ
ΠΡΠ°ΠΊ, ΠΌΡ ΠΏΠΎΠ»ΡΡΠΈΠ»ΠΈ Π΄Π²Π° ΡΠΏΠΎΡΠΎΠ±Π° ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π΄Π°Π½Π½ΡΡ Π² ΡΠ»ΠΎΠ²Π°ΡΡ β hstore / json_object. ΠΠΎΠΌΠΈΠΌΠΎ ΡΡΠΎΠ³ΠΎ, ΡΠ°ΠΌΠΈ ΠΌΠ°ΡΡΠΈΠ²Ρ ΠΊΠ»ΡΡΠ΅ΠΉ ΠΈ Π·Π½Π°ΡΠ΅Π½ΠΈΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΎΠ΄ΠΈΡΡ ΡΠΎΠΆΠ΅ Π΄Π²ΡΠΌΡ ΡΠΏΠΎΡΠΎΠ±Π°ΠΌΠΈ, Ρ Π²Π½ΡΡΡΠ΅Π½Π½ΠΈΠΌ ΠΈΠ»ΠΈ Π²Π½Π΅ΡΠ½ΠΈΠΌ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ ΠΊ ΡΠ΅ΠΊΡΡΡ: array_agg(i::text) / array_agg(i)::text[].
ΠΡΠΎΠ²Π΅ΡΠΈΠΌ ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΡΡΡ ΡΠ°Π·Π½ΡΡ Π²ΠΈΠ΄ΠΎΠ² ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π½Π° ΡΡΠ³ΡΠ±ΠΎ ΡΠΈΠ½ΡΠ΅ΡΠΈΡΠ΅ΡΠΊΠΎΠΌ ΠΏΡΠΈΠΌΠ΅ΡΠ΅ β ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·ΡΠ΅ΠΌ ΡΠ°Π·Π½ΠΎΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΠΊΠ»ΡΡΠ΅ΠΉ:
WITH dict AS (
SELECT
hstore(
array_agg(i::text)
, array_agg(i::text)
)
FROM
generate_series(1, ...) i
)
TABLE dict;
ΠΡΠ΅Π½ΠΎΡΠ½ΡΠΉ ΡΠΊΡΠΈΠΏΡ : ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ
WITH T AS (
SELECT
*
, (
SELECT
regexp_replace(ea[array_length(ea, 1)], '^Execution Time: (d+.d+) ms$', '1')::real et
FROM
(
SELECT
array_agg(el) ea
FROM
dblink('port= ' || current_setting('port') || ' dbname=' || current_database(), $$
explain analyze
WITH dict AS (
SELECT
hstore(
array_agg(i::text)
, array_agg(i::text)
)
FROM
generate_series(1, $$ || (1 << v) || $$) i
)
TABLE dict
$$) T(el text)
) T
) et
FROM
generate_series(0, 19) v
, LATERAL generate_series(1, 7) i
ORDER BY
1, 2
)
SELECT
v
, avg(et)::numeric(32,3)
FROM
T
GROUP BY
1
ORDER BY
1;
ΠΠ° PostgreSQL 11 ΠΏΡΠΈΠΌΠ΅ΡΠ½ΠΎ Π΄ΠΎ ΡΠ°Π·ΠΌΠ΅ΡΠ° ΡΠ»ΠΎΠ²Π°ΡΡ Π² 2^12 ΠΊΠ»ΡΡΠ΅ΠΉ ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π² json ΡΡΠ΅Π±ΡΠ΅Ρ ΠΌΠ΅Π½ΡΡΠ΅ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ. ΠΡΠΈ ΡΡΠΎΠΌ Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΠΉ ΡΠ²Π»ΡΠ΅ΡΡΡ ΠΊΠΎΠΌΠ±ΠΈΠ½Π°ΡΠΈΡ json_object ΠΈ Β«Π²Π½ΡΡΡΠ΅Π½Π½Π΅Π³ΠΎΒ» ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΡ ΡΠΈΠΏΠΎΠ² array_agg(i::text)
.
Π’Π΅ΠΏΠ΅ΡΡ Π΄Π°Π²Π°ΠΉΡΠ΅ ΠΏΠΎΠΏΡΠΎΠ±ΡΠ΅ΠΌ ΠΏΡΠΎΡΠΈΡΠ°ΡΡ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΊΠ»ΡΡΠ° ΠΏΠΎ 8 ΡΠ°Π· β Π²Π΅Π΄Ρ Π΅ΡΠ»ΠΈ ΠΊ ΡΠ»ΠΎΠ²Π°ΡΡ Π½Π΅ ΠΎΠ±ΡΠ°ΡΠ°ΡΡΡΡ, ΡΠΎ Π·Π°ΡΠ΅ΠΌ ΠΎΠ½ Π½ΡΠΆΠ΅Π½?
ΠΡΠ΅Π½ΠΎΡΠ½ΡΠΉ ΡΠΊΡΠΈΠΏΡ : ΡΡΠ΅Π½ΠΈΠ΅ ΠΈΠ· ΡΠ»ΠΎΠ²Π°ΡΡ
WITH T AS (
SELECT
*
, (
SELECT
regexp_replace(ea[array_length(ea, 1)], '^Execution Time: (d+.d+) ms$', '1')::real et
FROM
(
SELECT
array_agg(el) ea
FROM
dblink('port= ' || current_setting('port') || ' dbname=' || current_database(), $$
explain analyze
WITH dict AS (
SELECT
json_object(
array_agg(i::text)
, array_agg(i::text)
)
FROM
generate_series(1, $$ || (1 << v) || $$) i
)
SELECT
(TABLE dict) -> (i % ($$ || (1 << v) || $$) + 1)::text
FROM
generate_series(1, $$ || (1 << (v + 3)) || $$) i
$$) T(el text)
) T
) et
FROM
generate_series(0, 19) v
, LATERAL generate_series(1, 7) i
ORDER BY
1, 2
)
SELECT
v
, avg(et)::numeric(32,3)
FROM
T
GROUP BY
1
ORDER BY
1;
Πβ¦ ΡΠΆΠ΅ ΠΏΡΠΈΠΌΠ΅ΡΠ½ΠΎ ΠΏΡΠΈ 2^6 ΠΊΠ»ΡΡΠ΅ΠΉ ΡΡΠ΅Π½ΠΈΠ΅ ΠΈΠ· json-ΡΠ»ΠΎΠ²Π°ΡΡ Π½Π°ΡΠΈΠ½Π°Π΅Ρ ΠΊΡΠ°ΡΠ½ΠΎ ΠΏΡΠΎΠΈΠ³ΡΡΠ²Π°ΡΡ ΡΡΠ΅Π½ΠΈΡ ΠΈΠ· hstore, Π΄Π»Ρ jsonb ΡΠΎ ΠΆΠ΅ ΡΠ°ΠΌΠΎΠ΅ ΠΏΡΠΎΠΈΡΡ
ΠΎΠ΄ΠΈΡ ΠΏΡΠΈ 2^9.
ΠΡΠΎΠ³ΠΎΠ²ΡΠ΅ Π²ΡΠ²ΠΎΠ΄Ρ:
- Π΅ΡΠ»ΠΈ Π½Π°Π΄ΠΎ ΡΠ΄Π΅Π»Π°ΡΡ JOIN Ρ ΠΌΠ½ΠΎΠ³ΠΎΠΊΡΠ°ΡΠ½ΠΎ ΠΏΠΎΠ²ΡΠΎΡΡΡΡΠΈΠΌΠΈΡΡ Π·Π°ΠΏΠΈΡΡΠΌΠΈ β Π»ΡΡΡΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Β«ΠΎΡΠ»ΠΎΠ²Π°ΡΠΈΠ²Π°Π½ΠΈΠ΅Β» ΡΠ°Π±Π»ΠΈΡΡ
- Π΅ΡΠ»ΠΈ Π²Π°Ρ ΡΠ»ΠΎΠ²Π°ΡΡ ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΠΎ ΠΌΠ°Π»Π΅Π½ΡΠΊΠΈΠΉ ΠΈ ΡΠΈΡΠ°ΡΡ Π²Ρ ΠΈΠ· Π½Π΅Π³ΠΎ Π±ΡΠ΄Π΅ΡΠ΅ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ β ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ json[b]
- Π²ΠΎ Π²ΡΠ΅Ρ ΠΎΡΡΠ°Π»ΡΠ½ΡΡ ΡΠ»ΡΡΠ°ΡΡ hstore + array_agg(i::text) Π±ΡΠ΄Π΅Ρ ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½Π΅Π΅
ΠΡΡΠΎΡΠ½ΠΈΠΊ: habr.com