แแแแแแแแถแ แแถแแแทแ แแ แแแแแแแแแทแแแแแแแแแแแถแแแแแแแแแแแแแแปแแแแแพแแกแพแ แแ แผแแแแแแพแแแแฝแแแถแแ แแแฝแแแแแแแแแแถแแแปแแแแแแแแผแแแถแ.
แงแแถแ แแแ "แแธแแทแ" แแแแปแแแบแแแแ แถแ 20 แแแแ แถแ แแแถแแแแถแแแ, แแถแ แแ แแแแปแแแแแแธแแปแแแแแทแ (แงแแถแ แแแแแ แแแแปแแแถแแแแแแถแแแแแฝแ) แ แแแแแถแแ "แแแแถแแแแแแแแแแแ" แแถแ แแแพแแแแแแถแแแถแแแแแแแแแแแธแแแแแแแแแแแแถแแแถแ แแแแแถแแแแแแแแแแแแแถแแบแแแแผแแแถแแแถแแแถแแแถแแนแแแถแแแ
แแ
แแแแปแแขแแแแแ แแพแแแนแแแทแ
แถแแแถแแพแแถแแขแแปแแแแแแพ PostgreSQL แแแแแแ "แแแแแแแแ" แแแแถแแแแแแแแถแแแแแ แถแแแแแแ แแแแฝแแแแแแแแถแ "แแแแถแแแถแ" แแทแแแแแปแแแแแถแแแแแปแแ "แแแแแทแแแปแ" แแ
แแแแปแ SQL แแถแแฝแแแนแแแแแแแแแแ
แถแแ
แแแแธแแทแแแแแแแแแแแถแแแแแพแแแแแขแถแ
แแถแแแแแแแแแแแถแแแแถแแขแแทแแแแแแแแผแแ
แแทแแแแแแถแแแแแแพแแแแถแแแแแแปแแแแแธแแแแแแแแแแถแแแแแแแแแ
แแแแแแแแแปแแแทแแแแแแแแถแแแแแแแธ
CREATE INDEX ON task(owner_id, task_date, id);
-- ะฐ ััะฐััะน - ัะดะฐะปะธะผ
DROP INDEX task_owner_id_task_date_idx;
แแผแ โแแโแแถแโแฎโแแผแ แแแแโแ แพแ แแพแโแแโแแแแแ
แแถแแแแผแ แ
แผแแแพแแแผแแ
แแแแผแแแแแแแถแแแแแแแแปแแแแแแแพ แแแแแแแแแถแแแแแแแแแแถแแแแแแแขแแแแแแแแ
SELECT
*
FROM
task
WHERE
owner_id = ANY('{1,2,4,8,16,32,64,128,256,512}'::integer[])
ORDER BY
task_date, id
LIMIT 20;
แแแแแ แแแแแทแ - แแพแแแถแแแแแแถแแทแแแ 20 แแแแแแแแแถแแแปแแแแแ แ แพแ Index Scan แแถแแแแแแแแแแแพแแแทแแ 960 แแฝแแแแแแแแแถแแแแแแแแแแผแแแแแแแ ... แ แพแแแผแแแแแถแแถแแขแถแแแทแ แ
unnest + ARRAY
แแถแแแทแ แถแแแถแแแแผแแแแแแนแแแฝแแแพแ - แแแแแทแแแพแแพแแแแแผแแแถแ แแแปแ 20 แแแแแแ แแแแแแแแแถ, แแถแแแแแแแแแถแแแแแแปแแแถแแขแถแ แแทแแแพแแแธ 20 แแแแแแแแถแแแแแถแแแแผแ แแแแถแแแแแถแแแแธแแฝแแ แแแแแนแแ แแแข แแแแแแแแแแแแแแแ (owner_id, task_date, id) แแพแแแถแแ
แ
แผแแแแแพแแแแแแถแแแผแ
แแแแถแแแแถแแแแแแแ
แแแแทแ "แแแแแแ
แแถแแฝแแแ" แแถแแปแแถแแถแแขแถแแแแแแแแถแแ, แแผแ
โแแถโแแ
โแแแแปแ ARRAY()
:
WITH T AS (
SELECT
unnest(ARRAY(
SELECT
t
FROM
task t
WHERE
owner_id = unnest
ORDER BY
task_date, id
LIMIT 20 -- ะพะณัะฐะฝะธัะธะฒะฐะตะผ ััั...
)) r
FROM
unnest('{1,2,4,8,16,32,64,128,256,512}'::integer[])
)
SELECT
(r).*
FROM
T
ORDER BY
(r).task_date, (r).id
LIMIT 20; -- ... ะธ ััั - ัะพะถะต
แขแผ แแถโแแแขโแแถแโแแปแโแ แพแ! แแฟแแแถแ 40% แแทแแแทแแแแแแแแทแ แแถแ 4.5 แแ แแแแผแแแแขแถแแ
แแถแแแแแแพแแแแแแแแแแถแแถแแถแแแถแแแแ CTEแแแแปแแแนแแแแแ แแแถแ แแแแธโแแแแ แแถแแแแปแแแแแแพแแแแธแแแแพแแถแแแแแถแแแแถแแฝแแแนแแแถแแแแแแแแแแถแแแแแถแแแแธแแแแแแแแแถแแ แแแแปแแแแแฝแแแ แแแแแแแถแ "แแถแแแปแ" แแ แแแแปแ CTE แขแถแ แแถแแฑแแ "แแปแ" InitPlan แแแถแแถแแแแแ แแนแแ แแแฝแแแแแถแแแผแ แแแแถแแถแแแแแแ
SELECT
((
SELECT
t
FROM
task t
WHERE
owner_id = 1
ORDER BY
task_date, id
LIMIT 1
).*);
Result (cost=4.77..4.78 rows=1 width=16) (actual time=0.063..0.063 rows=1 loops=1)
Buffers: shared hit=16
InitPlan 1 (returns $0)
-> Limit (cost=0.42..1.19 rows=1 width=48) (actual time=0.031..0.032 rows=1 loops=1)
Buffers: shared hit=4
-> Index Scan using task_owner_id_task_date_id_idx on task t (cost=0.42..387.57 rows=500 width=48) (actual time=0.030..0.030 rows=1 loops=1)
Index Cond: (owner_id = 1)
Buffers: shared hit=4
InitPlan 2 (returns $1)
-> Limit (cost=0.42..1.19 rows=1 width=48) (actual time=0.008..0.009 rows=1 loops=1)
Buffers: shared hit=4
-> Index Scan using task_owner_id_task_date_id_idx on task t_1 (cost=0.42..387.57 rows=500 width=48) (actual time=0.008..0.008 rows=1 loops=1)
Index Cond: (owner_id = 1)
Buffers: shared hit=4
InitPlan 3 (returns $2)
-> Limit (cost=0.42..1.19 rows=1 width=48) (actual time=0.008..0.008 rows=1 loops=1)
Buffers: shared hit=4
-> Index Scan using task_owner_id_task_date_id_idx on task t_2 (cost=0.42..387.57 rows=500 width=48) (actual time=0.008..0.008 rows=1 loops=1)
Index Cond: (owner_id = 1)
Buffers: shared hit=4"
InitPlan 4 (returns $3)
-> Limit (cost=0.42..1.19 rows=1 width=48) (actual time=0.009..0.009 rows=1 loops=1)
Buffers: shared hit=4
-> Index Scan using task_owner_id_task_date_id_idx on task t_3 (cost=0.42..387.57 rows=500 width=48) (actual time=0.009..0.009 rows=1 loops=1)
Index Cond: (owner_id = 1)
Buffers: shared hit=4
แแแแแแแแแถแแผแ แแแแถแแแแผแแแถแ "แแแแแแแ" 4 แแ... แแ แผแแแแ PostgreSQL 11 แฅแแทแแถแแแแแแแพแแกแพแแแถแแแแแถแแ แ แพแแแแแแแแแแถแแแบ "แแปแ" แแ แแแแปแ CTE แแแแแถแแแแแแแแแแแแแแถแแแแแแแแแแแแแแถแแแแแแแแทแแธแแแแแพแแแแแแทแแแแแถแแแ แแแแปแแแแแแแถแแแแแแ
แงแแแแแแแแแปแแกแพแแแทแ
แแ แแแแปแแแแแแแปแแแพแแขแถแแแแปแ 200 แแฝแ แแแแแถแแแแถแแแแแแแแแแแแถแแ แถแแแถแ แ 20. แแฝแ แแ แ แพแแแทแแแแ 960, แแแปแแแแแแผแแแแธแแแแทแ แแถแ - แแพแแถแขแถแ แแ แแฝแ แแ?
แ แผแแแพแแแแแถแแถแแแแแพแ แแแแแแนแแแแแแพแแแแแผแแแถแ แแแปแ แฆแ แแแแแแแแแถแ แแแโแแบโแแพแโแแนแโแแแแพโแแถแโแแโแแทแแแแแแโแแแแแโแแ แผแโแแแโแ แแแฝแโแแแโแแพแโแแแแผแโแแถแโแแแแผแโแแถแโแแแแ
แแแ แถแแแธ 1: แ แถแแแแแแพแแแแแแธ
แแถแแแแแแแ แแแแแธ "แแแแแ " แแแแถแแปแ แแแฝแ 20 แแแแแแพแแแฝแแแแ แถแแแแแแพแแแแแแถแแป "แแแแผแ" แแแแแถแแแแแแแ แถแแ_id แแแแแแพแแ แแผแ แแแแแแแแผแแแพแแแแแพแแแแแแแ "แแแแผแแแแแปแ" แแแแแถแแแแแแธแแฝแแ แ แพแแแถแแแแถแแ แแแแปแแแแแแธแแแแแแแแแแแถแแถแแแแแถแแแแแแแพแแ แแแแถแ - (task_date, id)แ
แแแ แถแแแธ 2: แแแแแแแแแแแแแแแแถ "แแแแแถแแ"
แฅแกแผแแแแแแแแแทแแแพแแพแแแแแถแแปแแแแผแแแธแแแแแธแแแแแแพแแ แพแแ แถแแแแแแพแ "แแแ แถแ" แแแแแแแแแแ แปแแแแแแแแแแแแแแแ แแถแแฝแแแนแแแถแแแแแแถแแปแ owner_id-key แแแแแถแแแแแแแแแแแแแถแแแแแถแแแแแพแแแถแแแขแแแแบแแแแถแแแแแแถแแแแแแแแถแแแแ แแแแปแแแถแแแแแพแแแพแแแแแแแแแแปแแแแแแ แแถแแถแแแทแแแถแแแแถแแแ แแ แผแแแแแแพแแแแแแแถแแแแแแแแแถแแขแแปแแแแ แแถแแปแแธแแธแแแ แแแแปแแแแแแธแ
แแแแแทแแแพแแถแแแแแแถแแพแ "แแแแแแถแแ" แแถแแปแแธแแธแแแแแแถแแแแ แแถแแปแแแแแถแแขแถแแ แปแแแแแแแแฝแแแแแแแผแแแถแแแแแแแแแ แแแแปแแแแแแธแแแแฝแแฑแแแแแแแธแแฝแ (แแถแแฝแ owner_id แแผแ แแแแถ) แแแแแถแแแแธแแแแแแแแธแแแแผแแแถแแแแแแแแแแแแแแแ
แแแแแบแแพแแแแแแแแแฝแแแถแแแถแแแแแธแแทแแแถแแแถแแปแแพแแแธแแฝแแแแแแถแแแแแแธแแฝแแแแ (แแแแแทแแแพแแถแแปแแแแผแแแถแแแแแ
แแแ แพแแแพแแแทแแแถแ "แแแแแแถแแ" แแแแแถแแปแแแแผแแแนแแแถแแแแธแแแแแธแ แพแแแแแถแแขแแแธแแนแแแแแผแแแถแแแแแแแแแแ ), แ แพแโแแฝแโแแ แแแแแแแแแแแ แแ
แแแแปแแแแแถแแแกแพแแแแแผแแแแแแแแแทแแธ (task_date, id) แ
แแแ แถแแแธ 3แ แแแแ แแทแแแแแแธแแแแแแแแแแถ
แแ
แแแแปแแแแแแแแแแฝแแแแแแแแถแแแแแพแแแพแแกแพแแแทแแแแแแแพแ แแแแแแแแแถแแฝแแ
แแแฝแ rv
แแแแผแแแถแแ
แแแแ - แแแแผแแแพแแแแแพแแแผแ
แแถ "แแแแแแถแแแแแแแแแแแแแถแแปแแธ 2 แแแแแแแธ" แ แพแแแแแแถแแแแแแพแแแแแฝแแแแ 1 แแธแแแแแธแ แแผแ
แแแแแ แพแ แแถแแแพแแกแพแแแแแผแแแฝแแแแแแแผแแแถแแแแแแ
แแแ
แแแแฝแแ แปแแแแแแแแแแฝแแฑแแแแแแแแแถแ
WITH RECURSIVE T AS (
-- #1 : ะทะฐะฝะพัะธะผ ะฒ ัะฟะธัะพะบ "ะฟะตัะฒัะต" ะทะฐะฟะธัะธ ะฟะพ ะบะฐะถะดะพะผั ะธะท ะบะปััะตะน ะฝะฐะฑะพัะฐ
WITH wrap AS ( -- "ะผะฐัะตัะธะฐะปะธะทัะตะผ" record'ั, ััะพะฑั ะพะฑัะฐัะตะฝะธะต ะบ ะฟะพะปัะผ ะฝะต ะฒัะทัะฒะฐะปะพ ัะผะฝะพะถะตะฝะธั InitPlan/SubPlan
WITH T AS (
SELECT
(
SELECT
r
FROM
task r
WHERE
owner_id = unnest
ORDER BY
task_date, id
LIMIT 1
) r
FROM
unnest('{1,2,4,8,16,32,64,128,256,512}'::integer[])
)
SELECT
array_agg(r ORDER BY (r).task_date, (r).id) list -- ัะพััะธััะตะผ ัะฟะธัะพะบ ะฒ ะฝัะถะฝะพะผ ะฟะพััะดะบะต
FROM
T
)
SELECT
list
, list[1] rv
, FALSE not_cross
, 0 size
FROM
wrap
UNION ALL
-- #2 : ะฒััะธััะฒะฐะตะผ ะทะฐะฟะธัะธ 1-ะณะพ ะฟะพ ะฟะพััะดะบั ะบะปััะฐ, ะฟะพะบะฐ ะฝะต ะฟะตัะตัะฐะณะฝะตะผ ัะตัะตะท ะทะฐะฟะธัั 2-ะณะพ
SELECT
CASE
-- ะตัะปะธ ะฝะธัะตะณะพ ะฝะต ะฝะฐะนะดะตะฝะพ ะดะปั ะบะปััะฐ 1-ะน ะทะฐะฟะธัะธ
WHEN X._r IS NOT DISTINCT FROM NULL THEN
T.list[2:] -- ัะฑะธัะฐะตะผ ะตะต ะธะท ัะฟะธัะบะฐ
-- ะตัะปะธ ะผั ะะ ะฟะตัะตัะตะบะปะธ ะฟัะธะบะปะฐะดะฝะพะน ะบะปัั 2-ะน ะทะฐะฟะธัะธ
WHEN X.not_cross THEN
T.list -- ะฟัะพััะพ ะฟัะพััะณะธะฒะฐะตะผ ัะพั ะถะต ัะฟะธัะพะบ ะฑะตะท ะผะพะดะธัะธะบะฐัะธะน
-- ะตัะปะธ ะฒ ัะฟะธัะบะต ัะถะต ะฝะตั 2-ะน ะทะฐะฟะธัะธ
WHEN T.list[2] IS NULL THEN
-- ะฟัะพััะพ ะฒะพะทะฒัะฐัะฐะตะผ ะฟัััะพะน ัะฟะธัะพะบ
'{}'
-- ะฟะตัะตัะพััะธัะพะฒัะฒะฐะตะผ ัะปะพะฒะฐัั, ัะฑะธัะฐั 1-ั ะทะฐะฟะธัั ะธ ะดะพะฑะฐะฒะปัั ะฟะพัะปะตะดะฝัั ะธะท ะฝะฐะนะดะตะฝะฝัั
ELSE (
SELECT
coalesce(T.list[2] || array_agg(r ORDER BY (r).task_date, (r).id), '{}')
FROM
unnest(T.list[3:] || X._r) r
)
END
, X._r
, X.not_cross
, T.size + X.not_cross::integer
FROM
T
, LATERAL(
WITH wrap AS ( -- "ะผะฐัะตัะธะฐะปะธะทัะตะผ" record
SELECT
CASE
-- ะตัะปะธ ะฒัะต-ัะฐะบะธ "ะฟะตัะตัะฐะณะฝัะปะธ" ัะตัะตะท 2-ั ะทะฐะฟะธัั
WHEN NOT T.not_cross
-- ัะพ ะฝัะถะฝะฐั ะทะฐะฟะธัั - ะฟะตัะฒะฐั ะธะท ัะฟะฟะธัะบะฐ
THEN T.list[1]
ELSE ( -- ะตัะปะธ ะฝะต ะฟะตัะตัะตะบะปะธ, ัะพ ะบะปัั ะพััะฐะปัั ะบะฐะบ ะฒ ะฟัะตะดัะดััะตะน ะทะฐะฟะธัะธ - ะพััะฐะปะบะธะฒะฐะตะผัั ะพั ะฝะตะต
SELECT
_r
FROM
task _r
WHERE
owner_id = (rv).owner_id AND
(task_date, id) > ((rv).task_date, (rv).id)
ORDER BY
task_date, id
LIMIT 1
)
END _r
)
SELECT
_r
, CASE
-- ะตัะปะธ 2-ะน ะทะฐะฟะธัะธ ัะถะต ะฝะตั ะฒ ัะฟะธัะบะต, ะฝะพ ะผั ั
ะพัั ััะพ-ัะพ ะฝะฐัะปะธ
WHEN list[2] IS NULL AND _r IS DISTINCT FROM NULL THEN
TRUE
ELSE -- ะฝะธัะตะณะพ ะฝะต ะฝะฐัะปะธ ะธะปะธ "ะฟะตัะตัะฐะณะฝัะปะธ"
coalesce(((_r).task_date, (_r).id) < ((list[2]).task_date, (list[2]).id), FALSE)
END not_cross
FROM
wrap
) X
WHERE
T.size < 20 AND -- ะพะณัะฐะฝะธัะธะฒะฐะตะผ ััั ะบะพะปะธัะตััะฒะพ
T.list IS DISTINCT FROM '{}' -- ะธะปะธ ะฟะพะบะฐ ัะฟะธัะพะบ ะฝะต ะบะพะฝัะธะปัั
)
-- #3 : "ัะฐะทะฒะพัะฐัะธะฒะฐะตะผ" ะทะฐะฟะธัะธ - ะฟะพััะดะพะบ ะณะฐัะฐะฝัะธัะพะฒะฐะฝ ะฟะพ ะฟะพัััะพะตะฝะธั
SELECT
(rv).*
FROM
T
WHERE
not_cross; -- ะฑะตัะตะผ ัะพะปัะบะพ "ะฝะตะฟะตัะตัะตะบะฐััะธะต" ะทะฐะฟะธัะธ
แแผแ แแแแแแพแ แแถแแแฝแแแผแแแทแแแแแแ 50% แขแถแแแแแแถแแแแแแแแแแแแแทแแแแแท 20%. แแแแแบแแแแแทแแแพแขแแแแแถแแ แแแปแแแแพแแแแธแแฟแแถแแถแแขแถแแขแถแ แแถแแแแแแแแแผแ (แงแแถแ แแแ แแทแแแแแแแ แแแพแแแแแทแแแ แแแแปแแแแแถแแแแแแแถแแ แ แพแแขแแแแแแแผแแ แผแแแ แแถแแแแถแแแแแแถแแแแถ) แแแแแถแแแแแแถแแแแแแแแแขแแแแขแถแ แแนแแแแขแแแแพแแถแแขแถแแแทแ แ
แแแแปแแแแแธแแถแแแแแแแแแแแแถแแแแแทแแแแแทแแถแแแแแแแ
แแถแแแแแพแแแถแแแ
แแแแปแแแแแแพแแแแแผแ "แแแแแแแแ" แ แแแปแแแแแแพแแแแแพแ 3 แแถแแแแแแแผแแแแแพแแบแขแถแแแแแแแพแขแแแแ
แแแแแ: www.habr.com