ΠΠ΅ΡΠΈΠΎΠ΄ΠΈΡΠ΅ΡΠΊΠΈ Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ Π·Π°Π΄Π°ΡΠ° ΠΏΠΎΠΈΡΠΊΠ° ΡΠ²ΡΠ·Π°Π½Π½ΡΡ Π΄Π°Π½Π½ΡΡ ΠΏΠΎ Π½Π°Π±ΠΎΡΡ ΠΊΠ»ΡΡΠ΅ΠΉ, ΠΏΠΎΠΊΠ° Π½Π΅ Π½Π°Π±Π΅ΡΠ΅ΠΌ Π½ΡΠΆΠ½ΠΎΠ΅ ΡΡΠΌΠΌΠ°ΡΠ½ΠΎΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Π·Π°ΠΏΠΈΡΠ΅ΠΉ.
ΠΠ°ΠΈΠ±ΠΎΠ»Π΅Π΅ Β«ΠΆΠΈΠ·Π½Π΅Π½Π½ΡΠΉΒ» ΠΏΡΠΈΠΌΠ΅Ρ β Π²ΡΠ²Π΅ΡΡΠΈ 20 ΡΠ°ΠΌΡΡ ΡΡΠ°ΡΡΡ Π·Π°Π΄Π°Ρ, ΡΠΈΡΠ»ΡΡΠΈΡ ΡΡ Π½Π° ΡΠΏΠΈΡΠΊΠ΅ ΡΠΎΡΡΡΠ΄Π½ΠΈΠΊΠΎΠ² (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, Π² ΡΠ°ΠΌΠΊΠ°Ρ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ΄ΡΠ°Π·Π΄Π΅Π»Π΅Π½ΠΈΡ). ΠΠ»Ρ ΡΠ°Π·Π»ΠΈΡΠ½ΡΡ ΡΠΏΡΠ°Π²Π»Π΅Π½ΡΠ΅ΡΠΊΠΈΡ Β«Π΄Π°ΡΠ±ΠΎΡΠ΄ΠΎΠ²Β» Ρ ΠΊΡΠ°ΡΠΊΠΈΠΌΠΈ Π²ΡΠΆΠΈΠΌΠΊΠ°ΠΌΠΈ ΠΏΠΎ ΡΡΠ°ΡΡΠΊΠ°ΠΌ ΡΠ°Π±ΠΎΡΡ ΠΏΠΎΡ ΠΎΠΆΠ°Ρ ΡΠ΅ΠΌΠ° ΡΡΠ΅Π±ΡΠ΅ΡΡΡ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ ΡΠ°ΡΡΠΎ.
Π ΡΡΠ°ΡΡΠ΅ ΡΠ°ΡΡΠΌΠΎΡΡΠΈΠΌ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ Π½Π° PostgreSQL Β«Π½Π°ΠΈΠ²Π½ΠΎΠ³ΠΎΒ» Π²Π°ΡΠΈΠ°Π½ΡΠ° ΡΠ΅ΡΠ΅Π½ΠΈΡ ΡΠ°ΠΊΠΎΠΉ Π·Π°Π΄Π°ΡΠΈ, Β«ΠΏΠΎΡΠΌΠ½Π΅Π΅Β» ΠΈ ΡΠΎΠ²ΡΠ΅ΠΌ ΡΠ»ΠΎΠΆΠ½ΡΠΉ Π°Π»Π³ΠΎΡΠΈΡΠΌ Β«ΡΠΈΠΊΠ»Π°Β» Π½Π° SQL Ρ ΡΡΠ»ΠΎΠ²ΠΈΠ΅ΠΌ Π²ΡΡ
ΠΎΠ΄Π° ΠΎΡ Π½Π°ΠΉΠ΄Π΅Π½Π½ΡΡ
Π΄Π°Π½Π½ΡΡ
, ΠΊΠΎΡΠΎΡΡΠΉ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΏΠΎΠ»Π΅Π·Π΅Π½ ΠΊΠ°ΠΊ Π΄Π»Ρ ΠΎΠ±ΡΠ΅Π³ΠΎ ΡΠ°Π·Π²ΠΈΡΠΈΡ, ΡΠ°ΠΊ ΠΈ Π΄Π»Ρ ΠΏΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΡ Π² Π΄ΡΡΠ³ΠΈΡ
ΠΏΠΎΡ
ΠΎΠΆΠΈΡ
ΡΠ»ΡΡΠ°ΡΡ
.
ΠΠΎΠ·ΡΠΌΠ΅ΠΌ ΡΠ΅ΡΡΠΎΠ²ΡΠΉ Π½Π°Π±ΠΎΡ Π΄Π°Π½Π½ΡΡ
ΠΈΠ·
CREATE INDEX ON task(owner_id, task_date, id);
-- Π° ΡΡΠ°ΡΡΠΉ - ΡΠ΄Π°Π»ΠΈΠΌ
DROP INDEX task_owner_id_task_date_idx;
ΠΠ°ΠΊ ΡΠ»ΡΡΠΈΡΡΡ, ΡΠ°ΠΊ ΠΈ ΠΏΠΈΡΠ΅ΡΡΡ
Π‘Π½Π°ΡΠ°Π»Π° Π½Π°Π±ΡΠΎΡΠ°Π΅ΠΌ ΡΠ°ΠΌΡΠΉ ΠΏΡΠΎΡΡΠΎΠΉ Π²Π°ΡΠΈΠ°Π½Ρ Π·Π°ΠΏΡΠΎΡΠ°, ΠΏΠ΅ΡΠ΅Π΄Π°Π²Π°Ρ ID ΠΈΡΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»Π΅ΠΉ
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, Π½ΠΎ Π΅ΡΠ΅ ΠΌΠ΅Π½ΡΡΠ΅ β ΠΌΠΎΠΆΠ½ΠΎ?
ΠΠ°Π²Π°ΠΉΡΠ΅ ΠΏΠΎΠΏΡΠΎΠ±ΡΠ΅ΠΌ Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡΡΡ Π·Π½Π°Π½ΠΈΠ΅ΠΌ, ΡΡΠΎ Π½Π°ΠΌ Π½Π°Π΄ΠΎ Π²ΡΠ΅Π³ΠΎ 20 Π·Π°ΠΏΠΈΡΠ΅ΠΉ. Π’ΠΎ Π΅ΡΡΡ Π±ΡΠ΄Π΅ΠΌ ΠΈΡΠ΅ΡΠΈΡΠΎΠ²Π°ΡΡ Π²ΡΡΠΈΡΠΊΡ Π΄Π°Π½Π½ΡΡ ΡΠΎΠ»ΡΠΊΠΎ Π΄ΠΎ Π΄ΠΎΡΡΠΈΠΆΠ΅Π½ΠΈΡ Π½ΡΠΆΠ½ΠΎΠ³ΠΎ Π½Π°ΠΌ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π°.
Π¨Π°Π³ 1: ΡΡΠ°ΡΡΠΎΠ²ΡΠΉ ΡΠΏΠΈΡΠΎΠΊ
ΠΡΠ΅Π²ΠΈΠ΄Π½ΠΎ, ΡΡΠΎ Π½Π°Ρ Β«ΡΠ΅Π»Π΅Π²ΠΎΠΉΒ» ΡΠΏΠΈΡΠΎΠΊ ΠΈΠ· 20 Π·Π°ΠΏΠΈΡΠ΅ΠΉ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π½Π°ΡΠΈΠ½Π°ΡΡΡΡ Ρ Β«ΠΏΠ΅ΡΠ²ΡΡ Β» Π·Π°ΠΏΠΈΡΠ΅ΠΉ ΠΏΠΎ ΠΎΠ΄Π½ΠΎΠΌΡ ΠΈΠ· Π½Π°ΡΠΈΡ owner_id-ΠΊΠ»ΡΡΠ΅ΠΉ. ΠΠΎΡΡΠΎΠΌΡ ΡΠ½Π°ΡΠ°Π»Π° Π½Π°ΠΉΠ΄Π΅ΠΌ ΡΠ°ΠΊΠΈΠ΅ Β«ΡΠ°ΠΌΡΠ΅ ΠΏΠ΅ΡΠ²ΡΠ΅Β» ΠΏΠΎ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡ ΠΈΠ· ΠΊΠ»ΡΡΠ΅ΠΉ ΠΈ Π·Π°Π½Π΅ΡΠ΅ΠΌ Π² ΡΠΏΠΈΡΠΎΠΊ, ΠΎΡΡΠΎΡΡΠΈΡΠΎΠ²Π°Π² Π΅Π³ΠΎ Π² ΠΏΠΎΡΡΠ΄ΠΊΠ΅, ΠΊΠΎΡΠΎΡΡΠΉ Ρ ΠΎΡΠΈΠΌ β (task_date, id).
Π¨Π°Π³ 2: Π½Π°Ρ ΠΎΠ΄ΠΈΠΌ Β«ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅Β» Π·Π°ΠΏΠΈΡΠΈ
Π’Π΅ΠΏΠ΅ΡΡ, Π΅ΡΠ»ΠΈ ΠΌΡ Π²ΠΎΠ·ΡΠΌΠ΅ΠΌ ΠΈΠ· Π½Π°ΡΠ΅Π³ΠΎ ΡΠΏΠΈΡΠΊΠ° ΠΏΠ΅ΡΠ²ΡΡ Π·Π°ΠΏΠΈΡΡ ΠΈ Π½Π°ΡΠ½Π΅ΠΌ Β«ΡΠ°Π³Π°ΡΡΒ» Π΄Π°Π»ΡΡΠ΅ ΠΏΠΎ ΠΈΠ½Π΄Π΅ΠΊΡΡ Ρ ΡΠΎΡ ΡΠ°Π½Π΅Π½ΠΈΠ΅ΠΌ owner_id-ΠΊΠ»ΡΡΠ°, ΡΠΎ Π²ΡΠ΅ Π½Π°ΠΉΠ΄Π΅Π½Π½ΡΠ΅ Π·Π°ΠΏΠΈΡΠΈ β ΠΊΠ°ΠΊ ΡΠ°Π· ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ Π² ΡΠ΅Π·ΡΠ»ΡΡΠΈΡΡΡΡΠ΅ΠΉ Π²ΡΠ±ΠΎΡΠΊΠ΅. ΠΠΎΠ½Π΅ΡΠ½ΠΎ, ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΠΊΠ° ΠΌΡ Π½Π΅ ΠΏΠ΅ΡΠ΅ΡΠ΅ΡΠ΅ΠΌ ΠΏΡΠΈΠΊΠ»Π°Π΄Π½ΠΎΠΉ ΠΊΠ»ΡΡ Π²ΡΠΎΡΠΎΠΉ Π·Π°ΠΏΠΈΡΠΈ Π² ΡΠΏΠΈΡΠΊΠ΅.
ΠΡΠ»ΠΈ ΠΏΠΎΠ»ΡΡΠΈΠ»ΠΎΡΡ, ΡΡΠΎ ΠΌΡ Π²ΡΠΎΡΡΡ Π·Π°ΠΏΠΈΡΡ Β«ΠΏΠ΅ΡΠ΅ΡΠ΅ΠΊΠ»ΠΈΒ», ΡΠΎ ΠΏΠΎΡΠ»Π΅Π΄Π½ΡΡ ΠΏΡΠΎΡΠΈΡΠ°Π½Π½Π°Ρ Π·Π°ΠΏΠΈΡΡ Π΄ΠΎΠ»ΠΆΠ½Π° Π±ΡΡΡ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π° Π² ΡΠΏΠΈΡΠΎΠΊ Π²ΠΌΠ΅ΡΡΠΎ ΠΏΠ΅ΡΠ²ΠΎΠΉ (Ρ ΡΠ΅ΠΌ ΠΆΠ΅ 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 Π²Π°ΡΠΈΠ°Π½ΡΠΎΠ² ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡΡΡ β Π²ΡΠ±ΠΈΡΠ°ΡΡ Π²Π°ΠΌ.
ΠΡΡΠΎΡΠ½ΠΈΠΊ: habr.com