PostgreSQL Antipatterns፡ 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 Antipatterns፡ CTE x CTE[ማብራሪያውን ይመልከቱ.tensor.ru]

ለየብቻ ወስዶ

ጥያቄውን በጥልቀት እንመልከተው እና ግራ እንጋባ፡-

  1. ተደጋጋሚ CTEs ከሌሉ ለምን ከሪከርሲቭ ጋር እዚህ አለ?
  2. ለምንድነው አነስተኛ/ከፍተኛ ዋጋዎችን በተለየ CTE ውስጥ ያሰባሰቡት ከዚያ በኋላ ከዋናው ናሙና ጋር የተሳሰሩ ከሆነ?
    + 25% ጊዜ
  3. ያለፈውን CTE ለመድገም መጨረሻ ላይ ያለ ቅድመ ሁኔታ 'SELECT * FROM' ለምን ይጠቀሙ?
    + 14% ጊዜ

በዚህ አጋጣሚ፣ Hash Join ለግንኙነቱ መመረጡ በጣም እድለኞች ነበርን፣ እና Nsted Loop አይደለም፣ ምክንያቱም ያኔ አንድ የCTE Scan ማለፊያ ብቻ ሳይሆን 10 ኪ!

ስለ CTE Scan ትንሽእዚህ ያንን ማስታወስ አለብን CTE Scan ከሴክ ስካን ጋር ተመሳሳይ ነው። - ማለትም, ምንም መረጃ ጠቋሚ የለም, ነገር ግን የተሟላ ፍለጋ ብቻ ነው, ይህም ያስፈልገዋል 10ኪ x 0.3ms = 3000ms ለዑደት በ cte_max ወይም 1ኪ 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 Antipatterns፡ CTE x CTE
[ማብራሪያውን ይመልከቱ.tensor.ru]

በሁለቱም አማራጮች ውስጥ ያለው መረጃ ማንበብ በግምት ከ4-5 ሚሰ ያህል ይወስዳል ፣ ከዚያ ሁሉም ጊዜያችን ይጨምራል -32% - ይህ በንጹህ መልክ ነው ጭነት ከመሠረታዊ ሲፒዩ ተወግዷል, እንደዚህ አይነት ጥያቄ ብዙ ጊዜ በቂ ከሆነ.

በአጠቃላይ መሰረቱን "ክብን እንዲሸከም, ካሬውን አንከባለል" እንዲል ማስገደድ የለብዎትም.

ምንጭ: hab.com

አስተያየት ያክሉ