PostgreSQL āĻ…ā§āĻ¯āĻžāĻ¨ā§āĻŸāĻŋāĻĒā§āĻ¯āĻžāĻŸāĻžāĻ°ā§āĻ¨āĻ¸: CTE x CTE

āĻ†āĻŽāĻžāĻ° āĻ•āĻžāĻœā§‡āĻ° āĻ˛āĻžāĻ‡āĻ¨ā§‡āĻ° āĻ•āĻžāĻ°āĻŖā§‡, āĻ†āĻŽāĻžāĻ•ā§‡ āĻĒāĻ°āĻŋāĻ¸ā§āĻĨāĻŋāĻ¤āĻŋ āĻŽā§‹āĻ•āĻžāĻŦā§‡āĻ˛āĻž āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡ āĻ¯āĻ–āĻ¨ āĻāĻ•āĻœāĻ¨ āĻŦāĻŋāĻ•āĻžāĻļāĻ•āĻžāĻ°ā§€ āĻāĻ•āĻŸāĻŋ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ˛ā§‡āĻ–ā§‡āĻ¨ āĻāĻŦāĻ‚ āĻŽāĻ¨ā§‡ āĻ•āĻ°ā§‡āĻ¨ "āĻŦā§‡āĻ¸ āĻ¸ā§āĻŽāĻžāĻ°ā§āĻŸ, āĻāĻŸāĻŋ āĻ¨āĻŋāĻœā§‡āĻ‡ āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻ¸āĻžāĻŽāĻ˛āĻžāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡!ÂĢ

āĻ•āĻŋāĻ›ā§ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡ (āĻ†āĻ‚āĻļāĻŋāĻ•āĻ­āĻžāĻŦā§‡ āĻĄāĻžāĻŸāĻžāĻŦā§‡āĻ¸ā§‡āĻ° āĻ•ā§āĻˇāĻŽāĻ¤āĻž āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ…āĻœā§āĻžāĻ¤āĻž āĻĨā§‡āĻ•ā§‡, āĻ†āĻ‚āĻļāĻŋāĻ•āĻ­āĻžāĻŦā§‡ āĻ…āĻ•āĻžāĻ˛ āĻ…āĻĒā§āĻŸāĻŋāĻŽāĻžāĻ‡āĻœā§‡āĻļāĻ¨ āĻĨā§‡āĻ•ā§‡), āĻāĻ‡ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻŸāĻŋ "āĻĢā§āĻ°āĻžāĻ™ā§āĻ•ā§‡āĻ¨āĻ¸ā§āĻŸāĻžāĻ‡āĻ¨āĻ¸" āĻāĻ° āĻšā§‡āĻšāĻžāĻ°āĻžāĻ° āĻĻāĻŋāĻ•ā§‡ āĻ¨āĻŋāĻ¯āĻŧā§‡ āĻ¯āĻžāĻ¯āĻŧāĨ¤

āĻĒā§āĻ°āĻĨāĻŽāĻ¤, āĻ†āĻŽāĻŋ āĻāĻ‡ āĻ§āĻ°āĻ¨ā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻ‰āĻĻāĻžāĻšāĻ°āĻŖ āĻĻā§‡āĻŦ:

-- Đ´ĐģŅ ĐēĐ°ĐļдОК ĐēĐģŅŽŅ‡ĐĩвОК ĐŋĐ°Ņ€Ņ‹ ĐŊĐ°Ņ…ОдиĐŧ Đ°ŅŅĐžŅ†Đ¸Đ¸Ņ€ĐžĐ˛Đ°ĐŊĐŊŅ‹Đĩ СĐŊĐ°Ņ‡ĐĩĐŊиŅ ĐŋĐžĐģĐĩĐš
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);

āĻāĻŸāĻž āĻĻā§‡āĻ–āĻž āĻ¯āĻžāĻšā§āĻ›ā§‡ āĻ¯ā§‡ āĻĄā§‡āĻŸāĻž āĻĒāĻĄāĻŧāĻ¤ā§‡ āĻ¸āĻŽāĻ¯āĻŧ āĻ˛ā§‡āĻ—ā§‡āĻ›ā§‡ āĻāĻ• āĻšāĻ¤ā§āĻ°ā§āĻĨāĻžāĻ‚āĻļā§‡āĻ°āĻ“ āĻ•āĻŽ āĻĒā§āĻ°āĻļā§āĻ¨ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨:

PostgreSQL āĻ…ā§āĻ¯āĻžāĻ¨ā§āĻŸāĻŋāĻĒā§āĻ¯āĻžāĻŸāĻžāĻ°ā§āĻ¨āĻ¸: CTE x CTE[explain.tensor.ru āĻĻā§‡āĻ–ā§āĻ¨]

āĻŸā§āĻ•āĻ°ā§‹ āĻŸā§āĻ•āĻ°ā§‹ āĻ•āĻ°ā§‡ āĻ¨ā§‡āĻ“āĻ¯āĻŧāĻž

āĻ†āĻ¸ā§āĻ¨ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻŸāĻŋ āĻ˜āĻ¨āĻŋāĻˇā§āĻ āĻ­āĻžāĻŦā§‡ āĻĻā§‡āĻ–āĻŋ āĻāĻŦāĻ‚ āĻŦāĻŋāĻ­ā§āĻ°āĻžāĻ¨ā§āĻ¤ āĻšāĻ‡:

  1. āĻ¯āĻĻāĻŋ āĻ•ā§‹āĻ¨ āĻ°āĻŋāĻ•āĻžāĻ°ā§āĻ¸āĻŋāĻ­ CTE āĻ¨āĻž āĻĨāĻžāĻ•ā§‡ āĻ¤āĻžāĻšāĻ˛ā§‡ āĻāĻ–āĻžāĻ¨ā§‡ RECURSIVE āĻ•ā§‡āĻ¨?
  2. āĻ•ā§‡āĻ¨ āĻāĻ•āĻŸāĻŋ āĻĒā§ƒāĻĨāĻ• CTE-āĻ¤ā§‡ āĻ¨ā§āĻ¯ā§‚āĻ¨āĻ¤āĻŽ/āĻ¸āĻ°ā§āĻŦā§‹āĻšā§āĻš āĻŽāĻžāĻ¨āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻŽā§‚āĻ˛ āĻ¨āĻŽā§āĻ¨āĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ āĻ•ā§‡āĻ¨?
    +25% āĻ¸āĻŽāĻ¯āĻŧ
  3. āĻ•ā§‡āĻ¨ āĻĒā§‚āĻ°ā§āĻŦāĻŦāĻ°ā§āĻ¤ā§€ CTE āĻĒā§āĻ¨āĻ°āĻžāĻŦā§ƒāĻ¤ā§āĻ¤āĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻļā§‡āĻˇā§‡ āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻƒāĻļāĻ°ā§āĻ¤ 'SELECT * FROM' āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦā§‡āĻ¨?
    +14% āĻ¸āĻŽāĻ¯āĻŧ

āĻāĻ‡ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡, āĻ†āĻŽāĻ°āĻž āĻ–ā§āĻŦ āĻ­āĻžāĻ—ā§āĻ¯āĻŦāĻžāĻ¨ āĻ¯ā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ—ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻšā§āĻ¯āĻžāĻļ āĻœāĻ¯āĻŧā§‡āĻ¨āĻ•ā§‡ āĻŦā§‡āĻ›ā§‡ āĻ¨ā§‡āĻ“āĻ¯āĻŧāĻž āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛, āĻ¨ā§‡āĻ¸ā§āĻŸā§‡āĻĄ āĻ˛ā§āĻĒ āĻ¨āĻ¯āĻŧ, āĻ•āĻžāĻ°āĻŖ āĻ¤āĻ–āĻ¨ āĻ†āĻŽāĻ°āĻž āĻ•ā§‡āĻŦāĻ˛ āĻāĻ•āĻŸāĻŋ CTE āĻ¸ā§āĻ•ā§āĻ¯āĻžāĻ¨ āĻĒāĻžāĻ¸āĻ‡ āĻĒā§‡āĻ¤āĻžāĻŽ āĻ¨āĻž, 10K!

CTE āĻ¸ā§āĻ•ā§āĻ¯āĻžāĻ¨ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻāĻ•āĻŸā§āĻāĻ–āĻžāĻ¨ā§‡ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻāĻŸāĻž āĻŽāĻ¨ā§‡ āĻ°āĻžāĻ–āĻ¤ā§‡ āĻšāĻŦā§‡ CTE āĻ¸ā§āĻ•ā§āĻ¯āĻžāĻ¨ Seq Scan āĻāĻ° āĻŽāĻ¤āĻ‡ - āĻ…āĻ°ā§āĻĨāĻžā§Ž, āĻ•ā§‹āĻ¨ āĻ‡āĻ¨ā§āĻĄā§‡āĻ•ā§āĻ¸āĻŋāĻ‚ āĻ¨āĻ¯āĻŧ, āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻāĻ•āĻŸāĻŋ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻ…āĻ¨ā§āĻ¸āĻ¨ā§āĻ§āĻžāĻ¨, āĻ¯āĻžāĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻšāĻŦā§‡ 10K x 0.3ms = 3000ms cte_max āĻĻā§āĻŦāĻžāĻ°āĻž āĻšāĻ•ā§āĻ°ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŦāĻž 1K x 1.5ms = 1500ms cte_bind āĻĻā§āĻŦāĻžāĻ°āĻž āĻ˛ā§āĻĒ āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ!
āĻ†āĻ¸āĻ˛ā§‡, āĻ†āĻĒāĻ¨āĻŋ āĻĢāĻ˛āĻžāĻĢāĻ˛ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻ•āĻŋ āĻĒā§‡āĻ¤ā§‡ āĻšā§‡āĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛ā§‡āĻ¨? āĻšā§āĻ¯āĻžāĻ, āĻ¸āĻžāĻ§āĻžāĻ°āĻŖāĻ¤ āĻāĻ‡ āĻĒā§āĻ°āĻļā§āĻ¨āĻŸāĻŋ "āĻ¤āĻŋāĻ¨-āĻ¤āĻ˛āĻž" āĻĒā§āĻ°āĻļā§āĻ¨āĻ—ā§āĻ˛āĻŋ āĻŦāĻŋāĻļā§āĻ˛ā§‡āĻˇāĻŖ āĻ•āĻ°āĻžāĻ° 5 āĻ¤āĻŽ āĻŽāĻŋāĻ¨āĻŋāĻŸā§‡ āĻ•ā§‹āĻĨāĻžāĻ“ āĻ†āĻ¸ā§‡āĨ¤

āĻ†āĻŽāĻ°āĻž āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻ…āĻ¨āĻ¨ā§āĻ¯ āĻ•ā§€ āĻœā§‹āĻĄāĻŧāĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻ‰āĻŸāĻĒā§āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻšā§‡āĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛āĻžāĻŽ 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);

PostgreSQL āĻ…ā§āĻ¯āĻžāĻ¨ā§āĻŸāĻŋāĻĒā§āĻ¯āĻžāĻŸāĻžāĻ°ā§āĻ¨āĻ¸: CTE x CTE
[explain.tensor.ru āĻĻā§‡āĻ–ā§āĻ¨]

āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻ‰āĻ­āĻ¯āĻŧ āĻŦāĻŋāĻ•āĻ˛ā§āĻĒā§‡ āĻĄā§‡āĻŸāĻž āĻĒāĻĄāĻŧāĻ¤ā§‡ āĻāĻ•āĻ‡ āĻ†āĻ¨ā§āĻŽāĻžāĻ¨āĻŋāĻ• 4-5ms āĻ˛āĻžāĻ—ā§‡, āĻ¤āĻžāĻ°āĻĒāĻ° āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ¸āĻŽāĻ¯āĻŧ āĻ˛āĻžāĻ­ -32% - āĻāĻŸāĻŋ āĻ¤āĻžāĻ° āĻŦāĻŋāĻļā§āĻĻā§āĻ§āĻ¤āĻŽ āĻ†āĻ•āĻžāĻ°ā§‡ āĻŦā§‡āĻ¸ āĻ¸āĻŋāĻĒāĻŋāĻ‡āĻ‰ āĻĨā§‡āĻ•ā§‡ āĻ˛ā§‹āĻĄ āĻ¸āĻ°āĻžāĻ¨ā§‹ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¯āĻĻāĻŋ āĻāĻ‡ āĻ§āĻ°āĻ¨ā§‡āĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻĒā§āĻ°āĻžāĻ¯āĻŧāĻ‡ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤

āĻ¸āĻžāĻ§āĻžāĻ°āĻŖāĻ­āĻžāĻŦā§‡, āĻ†āĻĒāĻ¨āĻžāĻ° āĻŦā§‡āĻ¸āĻŸāĻŋāĻ•ā§‡ "āĻ—ā§‹āĻ˛āĻžāĻ•āĻžāĻ°āĻŸāĻŋ āĻŦāĻšāĻ¨ āĻ•āĻ°āĻ¤ā§‡, āĻŦāĻ°ā§āĻ—āĻžāĻ•āĻžāĻ°āĻŸāĻŋ āĻ°ā§‹āĻ˛ āĻ•āĻ°āĻ¤ā§‡" āĻŦāĻžāĻ§ā§āĻ¯ āĻ•āĻ°āĻž āĻ‰āĻšāĻŋāĻ¤ āĻ¨āĻ¯āĻŧāĨ¤

āĻ‰āĻ¤ā§āĻ¸: www.habr.com

āĻāĻ•āĻŸāĻŋ āĻŽāĻ¨ā§āĻ¤āĻŦā§āĻ¯ āĻœā§āĻĄāĻŧā§āĻ¨