PostgreSQL Antipatterns: "Irid ikun hemm wieħed biss!"

Fl-SQL, inti tiddeskrivi "dak" trid tikseb, mhux "kif" għandu jsir. Għalhekk, il-problema tal-iżvilupp ta' mistoqsijiet SQL fl-istil ta' "kif jinstema' kif inkiteb" tieħu postha ta' unur, flimkien ma' partikolaritajiet tal-evalwazzjoni tal-kundizzjoni fl-SQL.

Illum, bl-użu ta 'eżempji estremament sempliċi, ejja naraw x'jista' jwassal għal dan fil-kuntest tal-użu GROUP/DISTINCT и LIMIT maghhom.

Dak jekk ktibt fit-talba “L-ewwel qabbad dawn il-pilloli, u mbagħad armi d-duplikati kollha, għandu jkun hemm wieħed biss eżempju għal kull ċavetta" - dan huwa eżattament kif se taħdem, anke jekk il-konnessjoni ma kienet meħtieġa xejn.

U xi kultant int xortik tajba u "taħdem biss", xi drabi għandha effett spjaċevoli fuq il-prestazzjoni, u xi drabi tagħti effetti li huma assolutament mhux mistennija mil-lat tal-iżviluppatur.

PostgreSQL Antipatterns: "Irid ikun hemm wieħed biss!"
Ukoll, forsi mhux daqshekk spettakolari, imma...

"Koppja ħelwa": INGĦAQAD + DISTINTI

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

Kif ikun ċar dak li riedu agħżel tali rekords X, li għalihom f'Y hemm assoċjati mal-kundizzjoni sodisfatta. Ibgħat talba permezz JOIN - irċieva xi valuri ta 'pk diversi drabi (eżattament kemm rekords adattati rriżultaw li kienu f'Y). Kif tneħħi? Żgur DISTINCT!

Huwa speċjalment "pjaċevoli" meta għal kull X-rekord hemm bosta mijiet ta' Y-rekords relatati, u mbagħad id-duplikati jitneħħew b'mod erojku ...

PostgreSQL Antipatterns: "Irid ikun hemm wieħed biss!"

Kif tiffissa? Biex tibda, tirrealizza li l-kompitu jista 'jiġi modifikat għal "Agħżel dawk ir-rekords X li għalihom hemm TAL-ALQAS WIEĦED f'Y assoċjati mal-kundizzjoni li tkun qed tiġi sodisfatta" - wara kollox, m'għandna bżonn xejn mir-rekord Y innifsu.

Nested TEŻISTI

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

Xi verżjonijiet ta 'PostgreSQL jifhmu li f'JEŻISTI huwa biżżejjed li ssib l-ewwel rekord li jiltaqa' magħhom, dawk anzjani le. Għalhekk, nippreferi dejjem nindika LIMIT 1 внутри EXISTS.

LATERALI 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;

L-istess għażla tippermetti, jekk meħtieġ, li immedjatament tirritorna xi dejta mir-rekord Y assoċjat misjub fl-istess ħin. Għażla simili hija diskussa fl-artiklu "PostgreSQL Antipatterns: rekord rari se jilħaq in-nofs ta 'JOIN".

"Għaliex tħallas aktar": DISTINCT [ON] + LIMITU 1

Vantaġġ addizzjonali ta’ tali trasformazzjonijiet ta’ query huwa l-abbiltà li faċilment tiġi limitata l-enumerazzjoni ta’ rekords jekk ikun meħtieġ wieħed biss/ftit minnhom, bħal fil-każ li ġej:

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

Issa naqraw it-talba u nippruvaw nifhmu x'suppost jagħmel id-DBMS:

  • aħna jgħaqqdu l-pjanċi
  • uniku minn X.pk
  • agħżel wieħed mir-rekords li fadal

Allura x'ħadt? "Xi rekord wieħed" minn dawk uniċi - u jekk tieħu dan minn dawk mhux uniċi, ir-riżultat se jinbidel b'xi mod? .. "U jekk ma jkunx hemm differenza, għaliex tħallas aktar?"

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

U eżattament l-istess tema ma GROUP BY + LIMIT 1.

"Ikolli biss nistaqsi": impliċitu GRUPP + LIMITU

Affarijiet simili jseħħu f'diversi kontrolli mhux vojt tikketti jew CTEs hekk kif it-talba timxi 'l quddiem:

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

Funzjonijiet aggregati (count/min/max/sum/...) jiġu eżegwiti b'suċċess fuq is-sett kollu, anke mingħajr ma jispeċifikaw b'mod espliċitu GROUP BY. Biss hawn ma LIMIT ma tantx huma faċli.

L-iżviluppatur jista 'jaħseb "Issa, jekk hemm rekords hemmhekk, allura għandi bżonn mhux aktar minn LIMIT". Imma m'għandekx għalfejn! Minħabba li għall-bażi hija:

  • jgħoddu dak li jridu fuq ir-rekords kollha
  • jagħtu kemm jistaqsu linji

Skont il-kundizzjonijiet fil-mira, huwa xieraq li ssir waħda mis-sostituzzjonijiet li ġejjin:

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

"Kemm tiddendel fi grammi": ​​DISTINTI + LIMITU

SELECT DISTINCT
  pk
FROM
  X
LIMIT $1

Żviluppatur naive jista 'sinċerament jemmen li l-eżekuzzjoni ta' talba se tieqaf, hekk kif insibu l-ewwel $1 valuri differenti li jiltaqgħu magħhom.

F'xi żmien fil-futur, dan jista 'u se jaħdem grazzi għal nodu ġdid Indiċi Skip Scan, li l-implimentazzjoni tagħha bħalissa qed tiġi maħduma, iżda għadha mhix.

S'issa l-ewwel ir-rekords kollha se jiġu rkuprati, huma uniċi, u kemm minnhom biss kif mitluba jiġu rritornati. Huwa speċjalment imdejjaq jekk ridna xi ħaġa simili $ 1 = 4, u hemm mijiet ta’ eluf ta’ rekords fit-tabella...

Sabiex ma nkunux imdejjaq għalxejn, se nużaw mistoqsija rikorsiva "DISTRINT għall-Fqar" minn PostgreSQL Wiki:

PostgreSQL Antipatterns: "Irid ikun hemm wieħed biss!"

Sors: www.habr.com

Żid kumment