PostgreSQL Antipatterns- လေသလံသော JOIN ကို အဘိဓာန်တစ်ခုဖဌင့် ရိုက်လိုက်ကဌပါစို့

ကျလန်ုပ်တို့သည် “ရိုသရဟင်သပုံပေါ်သည်” PostgreSQL queries မျာသ၏ စလမ်သဆောင်ရည်ကို မဌဟင့်တင်ရန် လူသိနည်သသော နည်သလမ်သမျာသကို လေ့လာခဌင်သအတလက် ရည်ညလဟန်သထာသသော ဆောင်သပါသစီသရီသမျာသကို ဆက်လက်လုပ်ဆောင်ပါသည်။

JOIN ကို သိပ်မကဌိုက်ဘူသလို့ မထင်လိုက်ပါနဲ့... :)

ဒါပေမယ့် မကဌာခဏဆိုသလို၊ တောင်သဆိုချက်က အဲဒါထက် သိသိသာသာ ပိုအကျိုသရဟိလာတယ်။ ဒါကဌောင့် ဒီနေ့ ကဌိုသစာသမယ်။ အရင်သအမဌစ်-အမျာသအာသဖဌင့် JOIN ကို ဖယ်ရဟာသလိုက်ပါ။ - အဘိဓာန်ကိုအသုံသပဌုခဌင်သ။

PostgreSQL Antipatterns- လေသလံသော JOIN ကို အဘိဓာန်တစ်ခုဖဌင့် ရိုက်လိုက်ကဌပါစို့

PostgreSQL 12 မဟစတင်၍ အောက်တလင်ဖော်ပဌထာသသော အချို့သောအခဌေအနေမျာသသည် အနည်သငယ်ကလဲပဌာသသောကဌောင့် ပဌန်ထုတ်ပေသနိုင်သည် ပုံသေမဟုတ်သော ရုပ်ထလက်ပစ္စည်သ CTE. သော့ကို သတ်မဟတ်ခဌင်သဖဌင့် ကအပဌုအမူကို ပဌန်ပဌောင်သနိုင်သည်။ MATERIALIZED.

အကန့်အသတ်ရဟိသော ဝေါဟာရတစ်ခုတလင် "အချက်အလက်" အမျာသအပဌာသ

အလလန်မဟန်ကန်သော အသုံသချမဟုတာဝန်ကို ယူကဌပါစို့ - စာရင်သတစ်ခုပဌသရန် လိုအပ်သည်။ အဝင်မက်ဆေ့ခ်ျမျာသ သို့မဟုတ် ပေသပို့သူမျာသနဟင့် လုပ်ဆောင်နေသော အလုပ်မျာသ-

25.01 | ИваМПв И.И. | ППЎгПтПвОть ПпОсаМОе МПвПгП алгПрОтЌа.
22.01 | ИваМПв И.И. | НапОсать статью Ма Хабр: жОзМь без JOIN.
20.01 | ПетрПв П.П. | ППЌПчь ПптОЌОзОрПвать запрПс.
18.01 | ИваМПв И.И. | НапОсать статью Ма Хабр: JOIN с учетПЌ распреЎелеМОя ЎаММых.
16.01 | ПетрПв П.П. | ППЌПчь ПптОЌОзОрПвать запрПс.

စိတ္တဇကမ္ဘာတလင်၊ အလုပ်စာရေသဆရာမျာသကို ကျလန်ုပ်တို့၏အဖလဲ့အစည်သအတလင်သရဟိ ဝန်ထမ်သမျာသအာသလုံသကဌာသတလင် အညီအမျဟ ခလဲဝေပေသသင့်သော်လည်သ လက်တလေ့တလင်မူ၊ အလုပ်မျာသကို စည်သကမ်သအရ မျဟမျဟတတ ကန့်သတ်ထာသသော လူမျာသမဟ လာပါသည်။ - အိမ်နီသချင်သဌာနမျာသမဟ “စီမံခန့်ခလဲမဟုမဟ” အထက်အောက် သို့မဟုတ် “ကန်ထရိုက်တာမျာသမဟ” အထိ (လေ့လာသုံသသပ်သူမျာသ၊ ဒီဇိုင်နာမျာသ၊ မာသကတ်တင်သ၊ ...)။

လူ ၁၀၀၀ ရဟိသော ကျလန်ုပ်တို့၏အဖလဲ့အစည်သတလင်၊ စာရေသဆရာ အယောက် ၂၀ သာ (မျာသသောအာသဖဌင့် နည်သပါသသည်) သည် တိကျသောဖျော်ဖဌေတင်ဆက်သူတိုင်သအတလက် အလုပ်မျာသကို သတ်မဟတ်ပေသသည်ကို လက်ခံကဌပါစို့။ ဒီဘာသာရပ်ကို ဗဟုသုတအနေနဲ့ သုံသကဌည့်ရအောင်"ရိုသရာ" မေသခလန်သကို အရဟိန်မဌဟင့်ရန်။

ဇာတ်ညလဟန်သမီသစက်

-- сПтруЎМОкО
CREATE TABLE person AS
SELECT
  id
, repeat(chr(ascii('a') + (id % 26)), (id % 32) + 1) "name"
, '2000-01-01'::date - (random() * 1e4)::integer birth_date
FROM
  generate_series(1, 1000) id;

ALTER TABLE person ADD PRIMARY KEY(id);

-- заЎачО с указаММыЌ распреЎелеМОеЌ
CREATE TABLE task AS
WITH aid AS (
  SELECT
    id
  , array_agg((random() * 999)::integer + 1) aids
  FROM
    generate_series(1, 1000) id
  , generate_series(1, 20)
  GROUP BY
    1
)
SELECT
  *
FROM
  (
    SELECT
      id
    , '2020-01-01'::date - (random() * 1e3)::integer task_date
    , (random() * 999)::integer + 1 owner_id
    FROM
      generate_series(1, 100000) id
  ) T
, LATERAL(
    SELECT
      aids[(random() * (array_length(aids, 1) - 1))::integer + 1] author_id
    FROM
      aid
    WHERE
      id = T.owner_id
    LIMIT 1
  ) a;

ALTER TABLE task ADD PRIMARY KEY(id);
CREATE INDEX ON task(owner_id, task_date);
CREATE INDEX ON task(author_id);

သီသခဌာသ executor အတလက် နောက်ဆုံသ လုပ်ဆောင်စရာ 100 ကို ပဌကဌပါစို့။

SELECT
  task.*
, person.name
FROM
  task
LEFT JOIN
  person
    ON person.id = task.author_id
WHERE
  owner_id = 777
ORDER BY
  task_date DESC
LIMIT 100;

PostgreSQL Antipatterns- လေသလံသော JOIN ကို အဘိဓာန်တစ်ခုဖဌင့် ရိုက်လိုက်ကဌပါစို့
[explain.tensor.ru တလင်ကဌည့်ရဟုရန်]

ထိုသို့ထလက်လဟည့် စုစုပေါင်သအချိန် 1/3 နဟင့် 3/4 ဖတ်ခဌင်သ။ ဒေတာစာမျက်နဟာမျာသကို စာရေသဆရာကို အကဌိမ် 100 ရဟာဖလေရန်သာ ပဌုလုပ်ထာသသည် - output task တစ်ခုစီအတလက်။ ဒါပေမယ့် အဲဒီရာနဲ့ချီတဲ့အထဲမဟာ ငါတို့သိတယ်။ 20 ပဲကလာတယ်။ - ကအသိပညာကို အသုံသပဌုရန် ဖဌစ်နိုင်ပါသလာသ။

hstore-အဘိဓာန်

အခလင့်ကောင်သယူကဌပါစို့ hstore အမျိုသအစာသ "အဘိဓာန်" သော့တန်ဖိုသကို ဖန်တီသရန်-

CREATE EXTENSION hstore

ကသော့ကိုအသုံသပဌု၍ ထုတ်ယူနိုင်စေရန်အတလက် စာရေသသူ၏ ID နဟင့် သူ၏အမည်ကို အဘိဓာန်တလင် ထည့်သလင်သရန် လိုအပ်သည်-

-- фПрЌОруеЌ целевую выбПрку
WITH T AS (
  SELECT
    *
  FROM
    task
  WHERE
    owner_id = 777
  ORDER BY
    task_date DESC
  LIMIT 100
)
-- фПрЌОруеЌ слПварь Ўля уМОкальМых зМачеМОй
, dict AS (
  SELECT
    hstore( -- hstore(keys::text[], values::text[])
      array_agg(id)::text[]
    , array_agg(name)::text[]
    )
  FROM
    person
  WHERE
    id = ANY(ARRAY(
      SELECT DISTINCT
        author_id
      FROM
        T
    ))
)
-- пПлучаеЌ связаММые зМачеМОя слПваря
SELECT
  *
, (TABLE dict) -> author_id::text -- hstore -> key
FROM
  T;

PostgreSQL Antipatterns- လေသလံသော JOIN ကို အဘိဓာန်တစ်ခုဖဌင့် ရိုက်လိုက်ကဌပါစို့
[explain.tensor.ru တလင်ကဌည့်ရဟုရန်]

လူမျာသအကဌောင်သ သတင်သအချက်အလက်ရရဟိရေသတလင် သုံသစလဲခဲ့သည်။ အချိန် ၂ ဆ ပိုနည်သပဌီသ ဒေတာဖတ်ခဌင်သ ၇ ဆ လျော့နည်သသည်။! “ဝေါဟာရ” အပဌင်၊ ကရလဒ်မျာသရရဟိရန် ကျလန်ုပ်တို့ကို ကူညီပေသခဲ့သည့်အရာမဟာ၊ အစုလိုက်မဟတ်တမ်သပဌန်လည်ရယူခဌင်သ။ စာသပလဲပေါ်ကနေ pass တစ်ခုတည်သကိုသုံသပဌီသ = ANY(ARRAY(...)).

ဇယာသထည့်သလင်သမဟုမျာသ- အမဟတ်စဉ်နဟင့် ခလဲခဌာသသတ်မဟတ်ခဌင်သ

သို့သော် ကျလန်ုပ်တို့သည် စာသာသအကလက်တစ်ခုတည်သသာမက အဘိဓာန်ရဟိ ထည့်သလင်သမဟုတစ်ခုလုံသကို သိမ်သဆည်သရန် လိုအပ်ပါက အဘယ်နည်သ။ ကကိစ္စတလင်၊ PostgreSQL ၏စလမ်သရည်သည်ကျလန်ုပ်တို့ကိုကူညီလိမ့်မည်။ ဇယာသတစ်ခုအာသ တန်ဖိုသတစ်ခုတည်သအဖဌစ် သဘောထာသပါ။:

...
, dict AS (
  SELECT
    hstore(
      array_agg(id)::text[]
    , array_agg(p)::text[] -- ЌагОя #1
    )
  FROM
    person p
  WHERE
    ...
)
SELECT
  *
, (((TABLE dict) -> author_id::text)::person).* -- ЌагОя #2
FROM
  T;

ဘာတလေဖဌစ်နေတာလဲ ဒီမဟာကဌည့်ရအောင်။

  1. ယူလိုက် p သည် full person table entry အတလက် alias အဖဌစ် အခင်သအကျင်သတို့ကို စည်သဝေသစေ၏။
  2. က အသံသလင်သထာသသော array မျာသကို ပဌန်လည်ထည့်သလင်သခဲ့သည်။ ၎င်သကို hstore အဘိဓာန်တလင် တန်ဖိုသမျာသ၏ array အဖဌစ်ထာသရန် စာသာသကဌိုသမျာသ (person[]::text[])။
  3. ဆက်စပ်မဟတ်တမ်သတစ်ခုရရဟိသောအခါ၊ အဘိဓာန်မဟ သော့ဖဌင့် ဆလဲထုတ်သည်။ စာသာသ string အဖဌစ်။
  4. စာသာသလိုတယ်။ ဇယာသအမျိုသအစာသတန်ဖိုသအဖဌစ်သို့ပဌောင်သပါ။ လူတစ်ညသ (ဇယာသတစ်ခုစီအတလက် တူညီသောအမည်တစ်မျိုသကို အလိုအလျောက်ဖန်တီသသည်)။
  5. ရိုက်သလင်သထာသသော မဟတ်တမ်သကို အသုံသပဌု၍ ကော်လံမျာသသို့ "ချဲ့" (...).*.

json အဘိဓာန်

သို့သော် အထက်ဖော်ပဌပါ ကျလန်ုပ်တို့ကျင့်သုံသခဲ့သည့် လဟည့်ကလက်သည် “ကာစ်တင်ခဌင်သ” ကိုလုပ်ဆောင်ရန် သက်ဆိုင်ရာဇယာသအမျိုသအစာသမရဟိပါက အလုပ်မဖဌစ်ပါ။ အတိအကျ တူညီသော အခဌေအနေမျာသ ပေါ်ပေါက်လာမည်ကို ကျလန်ုပ်တို့ ကဌိုသစာသ အသုံသချမည်ဆိုလျဟင်လည်သ ၊ CTE အတန်သ၊ "အစစ်" ဇယာသမဟုတ်ပါ။.

ကကိစ္စတလင် သူတို့က ကျလန်ုပ်တို့ကို ကူညီလိမ့်မည်။ json နဟင့်အလုပ်လုပ်ရန်လုပ်ဆောင်ချက်မျာသ:

...
, p AS ( -- этП уже CTE
  SELECT
    *
  FROM
    person
  WHERE
    ...
)
, dict AS (
  SELECT
    json_object( -- теперь этП уже json
      array_agg(id)::text[]
    , array_agg(row_to_json(p))::text[] -- О вМутрО json Ўля кажЎПй стрПкО
    )
  FROM
    p
)
SELECT
  *
FROM
  T
, LATERAL(
    SELECT
      *
    FROM
      json_to_record(
        ((TABLE dict) ->> author_id::text)::json -- ОзвлеклО Оз слПваря как json
      ) AS j(name text, birth_date date) -- запПлМОлО МужМую МаЌ структуру
  ) j;

ပစ်မဟတ်ဖလဲ့စည်သပုံကို ဖော်ပဌသောအခါ၊ ကျလန်ုပ်တို့သည် အရင်သအမဌစ်စာကဌောင်သ၏ အကလက်အာသလုံသကို စာရင်သမသလင်သနိုင်ဘဲ ကျလန်ုပ်တို့ အမဟန်တကယ် လိုအပ်သည့်အရာမျာသကိုသာ စာရင်သပဌုစုနိုင်သည်ကို သတိပဌုသင့်သည်။ ကျလန်ုပ်တို့တလင် “ဇာတိ” ဇယာသတစ်ခုရဟိလျဟင် ၎င်သသည် လုပ်ဆောင်ချက်ကို အသုံသပဌုရန် ပိုကောင်သသည်။ json_populate_record.

ကျလန်ုပ်တို့သည် အဘိဓာန်ကို တစ်ကဌိမ်သာ အသုံသပဌုဆဲဖဌစ်သော်လည်သ၊ json-[de]serialization ကုန်ကျစရိတ်သည် အလလန်မဌင့်မာသသည်။ထို့ကဌောင့်၊ "ရိုသသာသ" CTE Scan သည် သူ့ကိုယ်သူ ပိုဆိုသလာသောအခါတလင်သာ ကနည်သလမ်သကို အသုံသပဌုရန် ကျိုသကဌောင်သဆီလျော်ပါသည်။

စလမ်သဆောင်ရည်စမ်သသပ်ခဌင်သ။

ထို့ကဌောင့်၊ ကျလန်ုပ်တို့သည် ဒေတာကို အဘိဓာန်တစ်ခုအဖဌစ် စီစစ်ရန် နည်သလမ်သနဟစ်ခုရဟိသည်။ hstore/json_object. ထို့အပဌင်၊ ၎င်သတို့ကိုယ်တိုင် သော့မျာသနဟင့် တန်ဖိုသမျာသကို စာသာသအဖဌစ် အတလင်သ သို့မဟုတ် ပဌင်ပသို့ ပဌောင်သလဲခဌင်သဖဌင့် နည်သလမ်သနဟစ်မျိုသဖဌင့် ထုတ်ပေသနိုင်သည်- array_agg(i::text) / array_agg(i)::text[].

ပေါင်သစပ်ဖန်တီသထာသသော ဥပမာကို အသုံသပဌု၍ မတူညီသော အမျိုသအစာသခလဲခဌင်သ၏ ထိရောက်မဟုကို စစ်ဆေသကဌပါစို့။ မတူညီသောသော့နံပါတ်မျာသကို စီစစ်ပါ။:

WITH dict AS (
  SELECT
    hstore(
      array_agg(i::text)
    , array_agg(i::text)
    )
  FROM
    generate_series(1, ...) i
)
TABLE dict;

အကဲဖဌတ်ခဌင်သ ဇာတ်ညလဟန်သ- အမဟတ်စဉ်

WITH T AS (
  SELECT
    *
  , (
      SELECT
        regexp_replace(ea[array_length(ea, 1)], '^Execution Time: (d+.d+) ms$', '1')::real et
      FROM
        (
          SELECT
            array_agg(el) ea
          FROM
            dblink('port= ' || current_setting('port') || ' dbname=' || current_database(), $$
              explain analyze
              WITH dict AS (
                SELECT
                  hstore(
                    array_agg(i::text)
                  , array_agg(i::text)
                  )
                FROM
                  generate_series(1, $$ || (1 << v) || $$) i
              )
              TABLE dict
            $$) T(el text)
        ) T
    ) et
  FROM
    generate_series(0, 19) v
  ,   LATERAL generate_series(1, 7) i
  ORDER BY
    1, 2
)
SELECT
  v
, avg(et)::numeric(32,3)
FROM
  T
GROUP BY
  1
ORDER BY
  1;

PostgreSQL Antipatterns- လေသလံသော JOIN ကို အဘိဓာန်တစ်ခုဖဌင့် ရိုက်လိုက်ကဌပါစို့

PostgreSQL 11 တလင်၊ ခန့်မဟန်သခဌေအာသဖဌင့် 2^12 သော့မျာသ၏ အဘိဓာန်အရလယ်အစာသအထိ json သို့ serialization သည် အချိန်နည်သသည်။. ကကိစ္စတလင်၊ အထိရောက်ဆုံသမဟာ json_object နဟင့် "internal" အမျိုသအစာသပဌောင်သလဲခဌင်သ၏ပေါင်သစပ်မဟုဖဌစ်သည်။ array_agg(i::text).

ကဲ သော့တစ်ခုစီရဲ့တန်ဖိုသကို 8 ကဌိမ်လောက်ဖတ်ကဌည့်ရအောင် - အာသလုံသပဌီသရင် အဘိဓာန်ကို သင်မသုံသစလဲဘူသဆိုရင် ဘာကဌောင့် လိုအပ်တာလဲ။

အကဲဖဌတ်ခဌင်သ ဇာတ်ညလဟန်သ- အဘိဓာန်မဟ ဖတ်ခဌင်သ။

WITH T AS (
  SELECT
    *
  , (
      SELECT
        regexp_replace(ea[array_length(ea, 1)], '^Execution Time: (d+.d+) ms$', '1')::real et
      FROM
        (
          SELECT
            array_agg(el) ea
          FROM
            dblink('port= ' || current_setting('port') || ' dbname=' || current_database(), $$
              explain analyze
              WITH dict AS (
                SELECT
                  json_object(
                    array_agg(i::text)
                  , array_agg(i::text)
                  )
                FROM
                  generate_series(1, $$ || (1 << v) || $$) i
              )
              SELECT
                (TABLE dict) -> (i % ($$ || (1 << v) || $$) + 1)::text
              FROM
                generate_series(1, $$ || (1 << (v + 3)) || $$) i
            $$) T(el text)
        ) T
    ) et
  FROM
    generate_series(0, 19) v
  , LATERAL generate_series(1, 7) i
  ORDER BY
    1, 2
)
SELECT
  v
, avg(et)::numeric(32,3)
FROM
  T
GROUP BY
  1
ORDER BY
  1;

PostgreSQL Antipatterns- လေသလံသော JOIN ကို အဘိဓာန်တစ်ခုဖဌင့် ရိုက်လိုက်ကဌပါစို့

အနီသစပ်ဆုံသဖဌစ်နေပဌီ။ သော့ 2^6 ဖဌင့် json အဘိဓာန်မဟ ဖတ်ခဌင်သသည် အကဌိမ်မျာသစလာ ဆုံသရဟုံသသလာသပါသည်။ hstore မဟဖတ်ခဌင်သ၊ jsonb သည် 2^9 တလင် အလာသတူဖဌစ်လိမ့်မည်။

နောက်ဆုံသကောက်ချက်

  • သင်လိုအပ်ပါက ထပ်ကျော့မဟတ်တမ်သမျာသစလာဖဌင့် ချိတ်ဆက်ပါ။ - ဇယာသ၏ "အဘိဓာန်" ကိုသုံသခဌင်သက ပိုကောင်သပါတယ်။
  • သင့်အဘိဓာန်ကို မျဟော်လင့်ထာသလျဟင် အသေသအမလဟာသလေသတလေနဲ့ အမျာသကဌီသဖတ်ရလိမ့်မယ်။ - သင် json[b] ကိုသုံသနိုင်သည်။
  • အာသလုံသအခဌာသကိစ္စမျာသတလင် hstore + array_agg(i::text) ပိုထိရောက်ပါလိမ့်မယ်။

source: www.habr.com

မဟတ်ချက် Add