ืื ื ืืืฉืืืื ืืช ืกืืจืช ืืืืืจืื ืืืืงืืฉืื ืืืืงืจ ืฉื ืืจืืื ืื ืืืืขืืช ืืฉืืคืืจ ืืืืฆืืขืื ืฉื ืฉืืืืชืืช PostgreSQL "ืคืฉืืืืช ืืืืืจื":
ืฉืื ื ืืืจ ืืืืข ืืืืฆืข JOIN ืืขืจืื JOIN ืกืืืืคืืื JOIN ื-OR ืืืืงืื CTE ืืฆืืจืฃ ื-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
ืื ืื ื ืจืง ืฆืจืืืื ืืฉืื ืืช ืชืขืืืช ืืืืืช ืฉื ืืืืืจ ืืืช ืฉืื ืืืืืื ืืื ืฉื ืืื ืืืืฅ ืืืืฆืขืืช ืืืคืชื ืืื:
-- ัะพัะผะธััะตะผ ัะตะปะตะฒัั ะฒัะฑะพัะบั
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 ืืืื ืื ืืขืจื ืืืืื ืฉื ืืืื ืืืื ืืืจืืืื ืืขืจื ืืื.
- ืื ืืขืจื ืืืงืืืืช ืืื ืืืืฉ ืืืขืจื ืฉื ืืืจืืืืช ืืงืกื (ืืื[]::ืืงืกื[]) ืืื ืืืงื ืืืชื ืืืืืื hstore ืืืขืจื ืฉื ืขืจืืื.
- ืืืฉืจ ืื ื ืืงืืืื ืจืฉืืื ืงืฉืืจื, ืื ื ื ืฉืืฃ ืืืืืืื ืืืคืชื ืืืืจืืืช ืืงืกื.
- ืื ืื ื ืฆืจืืืื ืืงืกื ืืืคืื ืืขืจื ืกืื ืืืื ืืื (ืขืืืจ ืื ืืืื ื ืืฆืจ ืืืืืืืืช ืกืื ืืืืชื ืฉื).
- "ืืจืื" ืืช ืืจืฉืืื ืืืืงืืืช ืืขืืืืืช ืืืืฆืขืืช
(...).*
.
ืืืืื 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-[de]serialization ืืืืืืช ืืืืืืื, ืกืืืจ ืืืฉืชืืฉ ืืฉืืื ืื ืจืง ืืืงืจืื ืืกืืืืื ืืืฉืจ ืกืจืืงืช ื-CTE ื"ืื ื" ืืจืื ืืช ืขืฆืื ืืจืืขื ืืืชืจ.
ืืืืงืช ืืืฆืืขืื
ืื ืืฉ ืื ื ืฉืชื ืืจืืื ืืกืืืืจ ื ืชืื ืื ืืืืืื - 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.
ืืกืงื ืืช ืกืืคืืืช:
- ืื ืืชื ืฆืจืื ืืขืฉืืช ืืช ืื ืืฆืืจืฃ ืขื ืืกืคืจ ืจืฉืืืืช ืฉืืืืจืืช ืขื ืขืฆืื - ืขืืืฃ ืืืฉืชืืฉ ื"ืืืืื" ืฉื ืืืืื
- ืื ืืืืืื ืฉืื ืฆืคืื ืงืื ืืื ืชืงืจืื ืืื ื ืืจืื - ืืชื ืืืื ืืืฉืชืืฉ ื-json[b]
- ืืื ืฉืืจ ืืืงืจืื hstore + array_agg(i::text) ืืืื ืืขืื ืืืชืจ
ืืงืืจ: www.habr.com