PostgreSQL Antipatterns- CTE x CTE

ကျွန်ုပ်၏အလုပ်လိုင်းကြောင့်၊ developer မှ တောင်းဆိုချက်တစ်ခုရေးပြီး "ထင်သည်"အခြေခံသည် စမတ်ကျသည်၊ ၎င်းသည် အရာအားလုံးကို သူ့ဘာသာသူ ကိုင်တွယ်နိုင်သည်။«

အချို့သောကိစ္စများတွင် (တစ်စိတ်တစ်ပိုင်းအားဖြင့် ဒေတာဘေ့စ်၏စွမ်းရည်များကို မသိခြင်းကြောင့်၊ တစ်စိတ်တစ်ပိုင်းအားဖြင့် အချိန်မတန်မီ ပိုမိုကောင်းမွန်အောင်ပြုလုပ်ခြင်းမှ) ဤချဉ်းကပ်မှုသည် "Frankensteins" ၏အသွင်အပြင်ကို ဦးတည်စေသည်။

ပထမဦးစွာ၊ ဤကဲ့သို့သောတောင်းဆိုမှု၏ဥပမာတစ်ခုပေးပါမည်။

-- для каждой ключевой пары находим ассоциированные значения полей
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[explain.tensor.ru တွင်ကြည့်ရှုရန်]

အပိုင်းလိုက် ခွဲလိုက်

တောင်းဆိုချက်ကို အနီးကပ်လေ့လာပြီး ပဟေဋ္ဌိဖြစ်လိုက်ကြရအောင်။

  1. ထပ်ခါတလဲလဲ CTE များမရှိပါက အဘယ်ကြောင့် ဤနေရာတွင် RECURSIVE ရှိနေသနည်း။
  2. မည်သို့ပင်ဆိုစေကာမူ ၎င်းတို့ကို မူရင်းနမူနာနှင့် ချိတ်ဆက်ထားလျှင် သီးခြား CTE တွင် min/max တန်ဖိုးများကို အဘယ်ကြောင့် အုပ်စုဖွဲ့ရမည်နည်း။
    +25% အချိန်
  3. ယခင် CTE ကို ပြန်လုပ်ရန် အဆုံးတွင် ခြွင်းချက်မရှိ 'SELECT * FROM' ကို အဘယ်ကြောင့် သုံးသနည်း။
    +14% အချိန်

ဤကိစ္စတွင်၊ Hash Join သည် ချိတ်ဆက်မှုအတွက် Nested Loop မဟုတ်ဘဲ Nested Loop မဟုတ်ဘဲ CTE Scan pass တစ်ခုတည်းသာမဟုတ်၊ 10K သာ ရရှိမည်ဖြစ်သောကြောင့် ကျွန်ုပ်တို့ အလွန်ကံကောင်းပါသည်။

CTE Scan အကြောင်းအနည်းငယ်ဤတွင် ကျွန်ုပ်တို့သည် ထိုအရာကို မှတ်ထားရမည်။ CTE Scan သည် Seq Scan နှင့် ဆင်တူသည်။ - ဆိုလိုသည်မှာ၊ ညွှန်းကိန်းထုတ်ခြင်းမပြုဘဲ လိုအပ်မည့် ပြည့်စုံသောရှာဖွေမှုတစ်ခုသာဖြစ်သည်။ 10K x 0.3ms = 3000ms cte_max ဖြင့် သံသရာအတွက် သို့မဟုတ် 1K x 1.5ms = 1500ms cte_bind ဖြင့် looping လုပ်သောအခါ!
တကယ်တော့ ရလဒ်က ဘာကို လိုချင်တာလဲ။ ဟုတ်တယ်၊ များသောအားဖြင့် ဒါက "သုံးထပ်" မေးခွန်းတွေကို ခွဲခြမ်းစိတ်ဖြာတဲ့ ၅ မိနစ်မှာ တစ်နေရာရာမှာ တက်လာတဲ့ မေးခွန်းပါ။

ထူးခြားသောသော့အတွဲတစ်ခုစီအတွက် ထုတ်ပေးလိုပါသည်။ key_a ဖြင့် အုပ်စုမှ min/max.
ဒါဆို ဒီအတွက် သုံးကြည့်ရအောင် ဝင်းဒိုးလုပ်ဆောင်ချက်များ:

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
[explain.tensor.ru တွင်ကြည့်ရှုရန်]

ရွေးချယ်မှုနှစ်ခုစလုံးတွင် ဒေတာဖတ်ခြင်းမှာ ခန့်မှန်းခြေအားဖြင့် 4-5ms ကြာမြင့်သောကြောင့် ကျွန်ုပ်တို့၏အချိန်အားလုံး တိုးလာပါသည်။ -32% - ဒါက သူ့ရဲ့ အသန့်ရှင်းဆုံးပုံစံပါ။ အခြေခံ CPU မှ load ကိုဖယ်ရှားသည်။ထိုသို့သောတောင်းဆိုမှုကို မကြာခဏလုပ်ဆောင်ပါက လုံလောက်ပါသည်။

ယေဘူယျအားဖြင့်၊ သင်သည် အခြေခံအား "ပတ်ပတ်လည်ကိုထမ်း၍ လေးထောင့်ကိုလှိမ့်" ရန် အတင်းအကြပ်မလုပ်သင့်ပါ။

source: www.habr.com

မှတ်ချက် Add