Antipatterns e PostgreSQL: «Duhet të mbetet vetëm një!»

Në SQL, ju përshkruani «çfarë» dëshironi të merrni, dhe jo «si» duhet të zbatohet. Prandaj, problemi i zhvillimit të pyetjeve SQL në stilin «si dëgjohet, ashtu shkruhet» mban vendin e tij të nderuar, së bashku me veçoritë e llogaritjes së kushteve në SQL.

Sot do të shohim disa shembuj të thjeshtë se ku mund të çojë kjo në kontekstin e përdorimit të GROUP/DISTINCT dhe KUFIZO së bashku me ta.

Ja, nĂ«se shkruani nĂ« pyetje «sĂ« pari bashkoni kĂ«to tabela, pastaj heqni tĂ« gjithĂ« dublikatĂ«, duhet tĂ« mbetet vetĂ«m njĂ« exemplar pĂ«r çdo çelĂ«s» — pikĂ«risht kĂ«shtu do tĂ« funksionojĂ«, edhe nĂ«se bashkimi nuk ishte i nevojshĂ«m fare.

Dhe ndonjĂ«herĂ« ndihmohet dhe kjo «thjesht funksionon», ndonjĂ«herë—ka njĂ« efekt negativ nĂ« performancĂ«, e ndonjĂ«herĂ« jep rezultate krejtĂ«sisht tĂ« papritura pĂ«r zhvilluesin.

Antipatterns e PostgreSQL: «Duhet të mbetet vetëm një!»
Epo, ndoshta jo aq spektakolar, por


«Çifti i Ă«mbĂ«l»: JOIN + DISTINCT

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

Duket e qartĂ« se çfarĂ« dĂ«shironin tĂ« merrni ato regjistrime X, pĂ«r tĂ« cilat nĂ« Y ka lidhje me kushtin e ekzekutuar. e kishim shkruar pyetjen pĂ«rmes JOIN — morĂ«m disa vlera pk disa herĂ« (aq sa ishin regjistrimet pĂ«rkatĂ«se nĂ« Y). Si ta heqim? Sigurisht DISTINCT!

VeçanĂ«risht «gĂ«zon» kur pĂ«r çdo regjistrim X ndodhen disa qindra regjistrime tĂ« lidhura Y, dhe pastaj heroikisht hiqen dublikatë 

Antipatterns e PostgreSQL: «Duhet të mbetet vetëm një!»

Si ta rregullojmĂ«? SĂ« pari, duhet tĂ« kuptojmĂ« se detyra mund tĂ« modifikohet nĂ« «tĂ« marrĂ« regjistrimet X, pĂ«r tĂ« cilat nĂ« Y ka TË PAKTË NËNJË lidhje me kushtin e ekzekutuar» — sepse nga regjistrimi Y nuk na nevojitet asgjĂ«.

EXISTS e vendosur

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

Disa versione tĂ« PostgreSQL kuptojnĂ« se nĂ« EXISTS Ă«shtĂ« mjaft tĂ« gjejnĂ« regjistrimin e parĂ« qĂ« del, versionet mĂ« tĂ« vjetra — jo. Prandaj, unĂ« preferoj gjithmonĂ« tĂ« specifikoj LIMIT 1 brenda EKZISTON.

LATERAL JOIN

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;

Ky opsion gjithashtu lejon, nëse është e nevojshme, të kthehet menjëherë ndonjë të dhënë nga regjistrimi i lidhur Y që u gjet. Një variant i ngjashëm është shqyrtuar në artikullin «PostgreSQL Antipatterns: një regjistrim i rrallë do të arrijë në mes të JOIN».

«Pse të paguajmë më shumë»: DISTINCT [ON] + LIMIT 1

Një avantazh tjetër i tillë të transformimeve të pyetjes është mundësia për të kufizuar lehtësisht shfrytëzimin e regjistrave, nëse nevojiten vetëm një/s disa prej tyre, si në rastin e mëposhtëm:

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

Tani lexojmë pyetjen dhe përpiqemi të kuptojmë se çfarë propozohet të bëjë DBMS:

  • bashkojmĂ« tabelat
  • e unikizojmĂ« sipas X.pk
  • nga regjistrat e mbetur zgjedhim njĂ« tĂ« vetĂ«m

Pra, çfarĂ« morĂ«m? „NjĂ« regjistĂ«r tĂ« caktuar“ nga tĂ« unikizuarit — dhe sikur ta marrim kĂ«tĂ« njĂ« nga ata qĂ« nuk janĂ« unikĂ«, rezultatet do tĂ« ndryshonin ndonjĂ«herĂ«?.. „E nĂ«se nuk ka dallime, pĂ«rse tĂ« paguajmĂ« mĂ« shumĂ«?“

SELECT
  *
FROM
  (
    SELECT
      *
    FROM
      X
    -- këtu mund të fusim kushte të përshtatshme
    LIMIT 1 -- +1 Limit
  ) X
JOIN
  Y
    ON Y.fk = X.pk
LIMIT 1;

Dhe një temë e ngjashme me GROUP BY + LIMIT 1.

„MĂ« duhet vetĂ«m tĂ« pyes”: GROUP implicit + LIMIT

Këto gjëra ndodhin në kontrollin e ndryshueshmërisë tabelës ose CTE gjatë ekzekutimit të pyetjeve: ... CASE WHEN ( SELECT count(*) FROM X LIMIT 1 ) = 0 THEN ...

Funksionet agreguese (

count/min/max/sum/...) përfundojnë me sukses në të gjithë grupin, edhe pa një tregues të dukshëm. Por me GRUPIM NGAnuk janë shumë të lidhura. KUFIZO Programuesi mund të mendojë

„po nĂ«se ka regjistra, atĂ«herĂ« mĂ« duhet jo mĂ« shumĂ« se LIMIT“ . Por nuk Ă«shtĂ« ashtu! Sepse pĂ«r bazĂ«n e tĂ« dhĂ«nave, kjo Ă«shtĂ«:numĂ«ro se çfarĂ« duan

  • pĂ«r tĂ« gjitha regjistrat kthe sa rreshta kĂ«rkohen
  • NĂ« varĂ«si tĂ« kushteve tĂ« synuara, kĂ«tu Ă«shtĂ« e pĂ«rshtatshme tĂ« bĂ«het njĂ« nga zĂ«vendĂ«simet:

(count + LIMIT 1) = 0

  • NOT EXISTS(LIMIT 1) nĂ« (count + LIMIT 1) > 0
  • EXISTS(LIMIT 1) nĂ« count >= N
  • (SELECT count(*) FROM (... LIMIT N)) nĂ« „Sa tĂ« varfĂ«r nĂ« gramĂ«â€: DISTINCT + LIMIT

SELECT DISTINCT pk FROM X LIMIT $1

Programuesi naiv mund të mendojë sinqerisht se ekzekutimi i pyetjes do të ndalet,

sa herë që të gjejmë $1 vlerat e para të rastësishme të ndryshme Në të ardhmen, mund të funksionojë në këtë mënyrë falë nyjës së re.

Index Skip Scan , implementimi i së cilës tani po zhvillohet, por për momentin - jo.Për momentin, fillimisht

do tĂ« nxirren tĂ« gjitha regjistrat , do tĂ« unikizohen, dhe vetĂ«m nga ato do tĂ« kthehet aq sa Ă«shtĂ« kĂ«rkuar. Sidomos Ă«shtĂ« e trishtueshme nĂ«se dĂ«shironim diçka si, dhe regjistrat nĂ« tabelĂ« — qindra mijĂ«ra
 $1 = 4QĂ« tĂ« mos trishtohemi kot, le tĂ« pĂ«rdorim pyetjen rikursive

„DISTINCT pĂ«r tĂ« varfrit” nga PostgreSQL Wiki NĂ« SQL pĂ«rshkruani "çfarĂ«" dĂ«shironi tĂ« merrni, jo "si" duhet ekzekutuar.:

Antipatterns e PostgreSQL: «Duhet të mbetet vetëm një!»

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster