PostgreSQL Antipatterns: "Divê tenê yek hebe!"

Di SQL de, hûn "çi" ku hûn dixwazin bi dest bixin diyar dikin, ne "çawa" divê were darve kirin. Ji ber vê yekê, pirsgirêka pêşvebirina pirsên SQL bi şêwaza "wek ku tê bihîstin ew çawa tête nivîsandin" cihê xwe yê rûmetê digire. taybetmendiyên hesabkirina şertên di SQL de.

Îro, nimûneyên pir hêsan bikar tînin, em bibînin ka ev di çarçoweya karanîna de dikare bibe sedema çi GROUP/DISTINCT и LIMIT bi wan re.

Naha, heke we di daxwaznameyê de nivîsand "Pêşî van nîşanan girêdin, û dûv re hemî dubareyan bavêjin, divê tenê yek bimîne kopî ji bo her key" - bi vî rengî ew ê çawa bixebite, her çend pêwendiyek qet ne hewce bû.

Û carinan hûn bi şens in û ew "tenê dixebite", carinan ew bandorek ne xweş li ser performansê dike, û carinan jî ew bandorên ku ji nêrîna pêşdebiran bi tevahî nediyar in dide.

PostgreSQL Antipatterns: "Divê tenê yek hebe!"
Welê, dibe ku ne ew qas balkêş be, lê…

"Hevala şîrîn": BİXWÎNE + CUDA

SELECT DISTINCT
  X.*
FROM
  X
JOIN
  Y
    ON Y.fk = X.pk
WHERE
  Y.bool_condition;

Dê eşkere bibûya ku wan çi dixwest tomarên X-ê yên ku di Y-yê de tomarên ku bi şertê pêk hatiye ve girêdayî ne hilbijêrin. Bi rêya daxwaznameyek nivîsand JOIN - çend caran hin nirxên pk wergirtin (bi rastî çend navnîşên minasib di Y de xuya bûn). Çawa jêbirin? Bicî DISTINCT!

Bi taybetî "kêfxweş" e dema ku ji bo her tomarek X-ê çend sed tomarên Y yên têkildar hene, û dûv re jî dubare bi qehremanî têne rakirin ...

PostgreSQL Antipatterns: "Divê tenê yek hebe!"

Meriv çawa rast bike? Ji bo destpêkê, fêm bikin ku pirsgirêk dikare were guhertin "qeydên X hilbijêrin ku ji bo wan di Y de KÊTÎ YEK bi şertê pêk hatiye ve girêdayî ye" - her tiştî, em ji qeyda Y bixwe ne hewce ne tiştek.

Nested HEBÛNE

SELECT
  *
FROM
  X
WHERE
  EXISTS(
    SELECT
      NULL
    FROM
      Y
    WHERE
      fk = X.pk AND
      bool_condition
    LIMIT 1
  );

Hin guhertoyên PostgreSQL fêm dikin ku di EXISTS de bes e ku meriv têketina yekem a ku derdikeve bibîne, yên pîr nabînin. Ji ber vê yekê ez tercîh dikim ku her dem destnîşan bikim LIMIT 1 hundur EXISTS.

TEVLÊBÛNA LATERAL

SELECT
  X.*
FROM
  X
, LATERAL (
    SELECT
      Y.*
    FROM
      Y
    WHERE
      fk = X.pk AND
      bool_condition
    LIMIT 1
  ) Y
WHERE
  Y IS DISTINCT FROM NULL;

Heman vebijark dihêle, ger hewce be, tavilê hin daneyan ji tomara Y-ya têkildar vegerîne. Vebijarkek wekhev di gotarê de tê nîqaş kirin "PostgreSQL Antipatterns: tomarek nadir dê bigihîje nîvê JOIN".

"Çima bêtir bidin": DISTINCT [ON] + SÎNOR 1

Feydeyek zêde ya veguheztinên pirsê yên weha ew e ku meriv bi hêsanî lêgerîna tomaran sînordar bike heke tenê yek an çend ji wan hewce be, wek di rewşa jêrîn de:

SELECT DISTINCT ON(X.pk)
  *
FROM
  X
JOIN
  Y
    ON Y.fk = X.pk
LIMIT 1;

Naha em daxwazê ​​dixwînin û hewl didin ku fêm bikin ka DBMS çi tê pêşniyar kirin ku bike:

  • girêdana nîşanan
  • yekta ji hêla X.pk
  • ji navnîşên mayî, yek hilbijêrin

Îcar we çi girt? "Tenê yek têketin" ji yên yekta - û ger em vê yekê ji yên ne-taybetî bigirin, gelo dê encam bi rengekî biguhêre?.. "Û heke ferq tunebe, çima bêtir bidin?"

SELECT
  *
FROM
  (
    SELECT
      *
    FROM
      X
    -- сюда можно подсунуть подходящих условий
    LIMIT 1 -- +1 Limit
  ) X
JOIN
  Y
    ON Y.fk = X.pk
LIMIT 1;

Û tam heman mijarê bi GROUP BY + LIMIT 1.

"Divê ez tenê bipirsim": GROUP + LIMIT nepenî

Tiştên bi vî rengî li cihêreng çêdibin kontrolên ne-valayî nîşan an CTE dema ku daxwaz pêşve diçe:

...
CASE
  WHEN (
    SELECT
      count(*)
    FROM
      X
    LIMIT 1
  ) = 0 THEN ...

Fonksiyonên berhevkirî (count/min/max/sum/...) bi serketî li ser tevahiya setê têne darve kirin, tewra bêyî rêwerzên eşkere GROUP BY. Tenê bi LIMIT ew ne pir dostane ne.

Pêşvebir dikare bifikire "eger tomar li wir hebin, wê hingê ji LIMIT bêtir hewcedariya min tune". Lê wisa nekin! Ji ber ku ji bo bingehîn ev e:

  • bijmêre ka ew çi dixwazin li gorî hemû qeydan
  • bi qasî ku ew bixwazin rêzan bidin

Bi şert û mercên armancê ve girêdayî, guncan e ku meriv yek ji veguheztina jêrîn were çêkirin:

  • (count + LIMIT 1) = 0 li ser NOT EXISTS(LIMIT 1)
  • (count + LIMIT 1) > 0 li ser EXISTS(LIMIT 1)
  • count >= N li ser (SELECT count(*) FROM (... LIMIT N))

"Gelo bi graman çendî ye": DISTINCT + SÎNOR

SELECT DISTINCT
  pk
FROM
  X
LIMIT $1

Pêşvebirek nefsbiçûk dibe ku ji dil bawer bike ku daxwaz dê bicîhkirinê rawestîne. gava ku em 1 $ ji nirxên cûda yên yekem ên ku têne dîtin bibînin.

Carekê di pêşerojê de ev dibe û dê bi saya nodek nû bixebite Indeks Skip Scan, pêkanîna ku niha tê xebitandin, lê hîn ne.

Ji bo niha pêşî hemî tomar dê bêne girtin, yekta ne, û tenê ji wan dê mîqdara tê xwestin were vegerandin. Bi taybetî xemgîn e ku em tiştek mîna dixwazin $ 1 = 4, û di tabloyê de bi sed hezaran tomar hene...

Ji bo ku bêhnteng nebin, bila pirsek paşverû bikar bînin "DISTINCT ji bo belengazan e" ji PostgreSQL Wiki:

PostgreSQL Antipatterns: "Divê tenê yek hebe!"

Source: www.habr.com

Add a comment