ืืฉื ืงื ืืขืืืื ืฉืื, ืื ื ื ืืืฅ ืืืชืืืื ืขื ืืฆืืื ืฉืืื ืืคืชื ืืืชื ืืงืฉื ืืืืฉื "ืืืกืืก ืืื, ืืื ืืืื ืืืชืืืื ืขื ืืื ืืขืฆืื!ยซ
ืืืงืจืื ืืกืืืืื (ืืืงื ืืืืจืืช ืืืืืืืช ืฉื ืืกื ืื ืชืื ืื, ืืืงื ืืืืคืืืืืืฆืืืช ืืืงืืืืช), ืืืฉื ืื ืืืืืื ืืืืคืขืช "ืคืจื ืงื ืฉืืืื".
ืจืืฉืืช, ืืชื ืืืืื ืืืงืฉื ืืื:
-- ะดะปั ะบะฐะถะดะพะน ะบะปััะตะฒะพะน ะฟะฐัั ะฝะฐั
ะพะดะธะผ ะฐััะพัะธะธัะพะฒะฐะฝะฝัะต ะทะฝะฐัะตะฝะธั ะฟะพะปะตะน
WITH RECURSIVE cte_bind AS (
SELECT DISTINCT ON (key_a, key_b)
key_a a
, key_b b
, fld1 bind_fld1
, fld2 bind_fld2
FROM
tbl
)
-- ะฝะฐั
ะพะดะธะผ min/max ะทะฝะฐัะตะฝะธะน ะดะปั ะบะฐะถะดะพะณะพ ะฟะตัะฒะพะณะพ ะบะปััะฐ
, cte_max AS (
SELECT
a
, max(bind_fld1) bind_fld1
, min(bind_fld2) bind_fld2
FROM
cte_bind
GROUP BY
a
)
-- ัะฒัะทัะฒะฐะตะผ ะฟะพ ะฟะตัะฒะพะผั ะบะปััั ะบะปััะตะฒัะต ะฟะฐัั ะธ min/max-ะทะฝะฐัะตะฝะธั
, cte_a_bind AS (
SELECT
cte_bind.a
, cte_bind.b
, cte_max.bind_fld1
, cte_max.bind_fld2
FROM
cte_bind
INNER JOIN
cte_max
ON cte_max.a = cte_bind.a
)
SELECT * FROM cte_a_bind;
ืืื ืืืขืจืื ืืืืคื ืืืืชื ืืช ืืืืืช ืืืงืฉื, ืืืื ื ืืฆืืจ ืืขืจื ื ืชืื ืื ืฉืจืืจืืชื:
CREATE TABLE tbl AS
SELECT
(random() * 1000)::integer key_a
, (random() * 1000)::integer key_b
, (random() * 10000)::integer fld1
, (random() * 10000)::integer fld2
FROM
generate_series(1, 10000);
CREATE INDEX ON tbl(key_a, key_b);
ืืกืชืืจ ืฉ ืงืจืืืช ืื ืชืื ืื ืืจืื ืคืืืช ืืจืืข ืืืืื ืืืฆืืข ืฉืืืืชื:
ืืคืจืงืื ืืืชื ืืืง ืืืจ ืืืง
ืืืื ื ืกืชืื ืืงืจืื ืขื ืืืงืฉื ืื ืชืืื:
- ืืื WITH RECURSIVE ื ืืฆื ืืื ืื ืืื CTEs ืจืงืืจืกืืื?
- ืืื ืืงืืฅ ืขืจืื ืืื ืืืื/ืืงืกืืืื ื-CTE ื ืคืจื ืื ืื ืงืฉืืจืื ืื ืืืืื ืืืงืืจื ืืื ืืงืจื?
+25% ืืื - ืืื ืืืฉืชืืฉ ื'SELECT * FROM' ืืื ืชื ืื ืืกืืฃ ืืื ืืืืืจ ืขื ื-CTE ืืงืืื?
+14% ืืื
ืืืงืจื ืืื, ืืื ืื ื ืืื ืืืื ืฉ-Hash Join ื ืืืจ ืืืืืืจ, ืืื Nested Loop, ืื ืื ืืืื ื ืืงืืืื ืื ืจืง ืืจืืืก CTE Scan ืืื, ืืื 10K!
ืงืฆืช ืขื CTE Scanืืื ืขืืื ื ืืืืืจ ืืืช CTE Scan ืืืื ื-Seq Scan - ืืืืืจ, ืืื ืืื ืืงืก, ืืื ืจืง ืืืคืืฉ ืฉืื, ืฉืืืจืืฉ 10K x 0.3ms = 3000ms ืขืืืจ ืืืืืจืื ืืคื cte_max ืื 1K x 1.5ms = 1500ms ืืขืช ืืืืื ืขื ืืื cte_bind!
ืืขืฆื, ืื ืจืฆืืช ืืงืื ืืชืืฆืื ืืื? ืื, ืืืจื ืืื ืื ืืฉืืื ืฉืขืืื ืื ืฉื ืืืงื ืืืืืฉืืช ืฉื ื ืืชืื ืฉืืืืชืืช "ืฉืืืฉ ืงืืืืช".
ืจืฆืื ื ืืืืฆืื ืขืืืจ ืื ืืื ืืคืชืืืช ืืืืืื min/max ืืงืืืฆื ืืคื key_a.
ืื ืืืื ื ืฉืชืืฉ ืืื ืืฉืืื ืื
SELECT DISTINCT ON(key_a, key_b)
key_a a
, key_b b
, max(fld1) OVER(w) bind_fld1
, min(fld2) OVER(w) bind_fld2
FROM
tbl
WINDOW
w AS (PARTITION BY key_a);
ืืืืืื ืฉืงืจืืืช ื ืชืื ืื ืืฉืชื ืืืคืฉืจืืืืช ืืืงืืช ืืืชื ืืืจ ืืขืจื 4-5ms, ืื ืื ืืืื ืฉืื ื ืืจืืืื -32% - ืื ืืฆืืจืชื ืืืืืจื ืืืืชืจ ืขืืืก ืืืกืจ ืืืืขืื ืืืกืืกื, ืื ืืงืฉื ืืื ืืืืฆืขืช ืืขืชืื ืงืจืืืืช ืืกืคืืง.
ืืืืคื ืืืื, ืืชื ืื ืฆืจืื ืืืืจืื ืืช ืืืกืืก "ืืกืืื ืืช ืืขืืื, ืืืืื ืืช ืืืจืืืข".
ืืงืืจ: www.habr.com