SQL Hogyan: while-ciklus Ă­rĂĄsa közvetlenĂŒl a lekĂ©rdezĂ©sben, vagy "ElemĂ©r hĂĄrom Ășt"

IdƑnkĂ©nt felmerĂŒl a szĂŒksĂ©g, hogy összefĂŒggƑ adatokat keressĂŒnk egy kulcskĂ©szlet alapjĂĄn, amĂ­g el nem Ă©rjĂŒk a kĂ­vĂĄnt összesĂ­tett rekordok szĂĄmĂĄt..

A legĂ©letszerƱbb pĂ©lda — megjelenĂ­teni a 20 legöregebb feladatot,amelyek szerepelnek a munkatĂĄrsak listĂĄjĂĄn, (pĂ©ldĂĄul egy adott rĂ©szlegen belĂŒl). KĂŒlönbözƑ menedzsment „dashbordok” esetĂ©ben, amelyek rövid összefoglalĂłkat adnak a munkaterĂŒletekrƑl, hasonlĂł tĂ©ma elĂ©g gyakran szĂŒksĂ©ges.

SQL Hogyan: while-ciklus Ă­rĂĄsa közvetlenĂŒl a lekĂ©rdezĂ©sben, vagy "ElemĂ©r hĂĄrom Ășt"

A cikkben a PostgreSQL „naiv” megoldĂĄsĂĄnak megvalĂłsĂ­tĂĄsĂĄt, egy „okosabb” Ă©s egy igazĂĄn bonyolult algoritmust fogunk megvizsgĂĄlni, SQL „ciklus” pĂ©ldĂĄjĂĄn keresztĂŒl, amely a megtalĂĄlt adatok alapjĂĄn lĂ©p ki,ami hasznos lehet a szemĂ©lyes fejlƑdĂ©s szempontjĂĄbĂłl, valamint mĂĄs hasonlĂł esetekben valĂł alkalmazĂĄsra is.

VegyĂŒnk egy tesztadat-kĂ©szletet, amely az elƑzƑ cikkbƑl szĂĄrmazik.Ahhoz, hogy a megjelenĂ­tett rekordok ne „ugrĂĄljanak” alkalomrĂłl alkalomra a rendezett Ă©rtĂ©kek megegyezĂ©sekor, tĂĄgĂ­tsuk az indexet az elsƑdleges kulcs hozzĂĄadĂĄsĂĄval.Ez egyszerre egyedivĂ© is teszi, Ă©s garantĂĄlja szĂĄmunkra a rendezĂ©si sorrend egyĂ©rtelmƱsĂ©gĂ©t:

CREATE INDEX ON task(owner_id, task_date, id);
-- a rĂ©git töröljĂŒk
DROP INDEX task_owner_id_task_date_idx;

Ahogy hallatszik, Ășgy is Ă­rjĂĄk.

ElƑször is vĂĄzoljuk fel a leginkĂĄbb alapvetƑ lekĂ©rdezĂ©st, azzal, hogy az ĂŒgyfelek ID-jĂĄt tömbkĂ©nt adjuk meg bemeneti paramĂ©terkĂ©nt.:

SELECT
  *
FROM
  task
WHERE
  owner_id = ANY('{1,2,4,8,16,32,64,128,256,512}'::integer[])
ORDER BY
  task_date, id
LIMIT 20;

SQL Hogyan: while-ciklus Ă­rĂĄsa közvetlenĂŒl a lekĂ©rdezĂ©sben, vagy "ElemĂ©r hĂĄrom Ășt"
[megtekintés az explain.tensor.ru-n]

Kicsit szomorĂș — csak 20 rekordot kĂ©rtĂŒnk, de az Index Scan összesen 960 sort adott vissza,amelyeket mĂ©g rendezni is kellett... Na, prĂłbĂĄljuk meg kevesebbet olvasni.

unnest + ARRAY

Az elsƑ Ă©szrevĂ©tel, ami segĂ­teni fog — ha csak 20 rendezett rekordra van szĂŒksĂ©gĂŒnk, akkor elegendƑ csak 20 rendezett rekordot olvasni a megfelelƑ sorrendben minden egyes kulcshoz. SzerencsĂ©re, a megfelelƑ index (owner_id, task_date, id) mĂĄr lĂ©tezik nĂĄlunk. HasznĂĄljuk ugyanazt a mechanizmust az adatkinyerĂ©shez Ă©s a „hasĂĄbokba fordĂ­tĂĄshoz”

az egĂ©sz tĂĄbla rekordjĂĄn , mint a. Emellett alkalmazzuk az ARRAY() funkciĂłt a tömbokkĂĄ valĂł tömörĂ­tĂ©shez. elƑzƑ cikkbenWITH T AS ( SELECT unnest(ARRAY( SELECT t FROM task t WHERE owner_id = unnest ORDER BY task_date, id LIMIT 20 -- itt korlĂĄtozzuk... )) r FROM unnest('{1,2,4,8,16,32,64,128,256,512}'::integer[]) ) SELECT (r).* FROM T ORDER BY (r).task_date, (r).id LIMIT 20; -- ... Ă©s itt is - ugyanĂșgy Oh, mĂĄr sokkal jobb!:

40%-kal gyorsabb, és 4,5-szer kevesebb adatot

SQL Hogyan: while-ciklus Ă­rĂĄsa közvetlenĂŒl a lekĂ©rdezĂ©sben, vagy "ElemĂ©r hĂĄrom Ășt"
[megtekintés az explain.tensor.ru-n]

kellett olvasni. A tĂĄblĂĄzatok rekordjainak anyagba ĂĄllĂ­tĂĄsa CTE-n keresztĂŒl. FelhĂ­vom a figyelmet arra, hogy

a rekordok bevonĂĄsa a cĂ©lnak megfelelƑen törtĂ©nik, Ă©s a szĂŒksĂ©ges adatokkal gazdagodik,amely az eredmĂ©nyek megfelelƑ Ă©rtelmezĂ©sĂ©t garantĂĄlja. bizonyos esetekben a keresett rekord mezƑivel valĂł közvetlen munkavĂ©gzĂ©s a beĂĄgyazott lekĂ©rdezĂ©s utĂĄn, anĂ©lkĂŒl, hogy "CTE-be" csomagolnĂĄnk, ilyenekhez vezethet a InitPlan "sokszorozĂĄsĂĄhoz" az emlĂ­tett mezƑk szĂĄmĂĄnak megfelelƑen:

SELECT
  ((
    SELECT
      t
    FROM
      task t
    WHERE
      owner_id = 1
    ORDER BY
      task_date, id
    LIMIT 1
  ).*);

EredmĂ©ny  (költsĂ©g=4.77..4.78 sor=1 szĂ©lessĂ©g=16) (valĂłs idƑ=0.063..0.063 sor=1 ciklus=1)
  Pufferek: megosztott hit=16
  InitPlan 1 (visszaadja $0)
    ->  Limit  (költsĂ©g=0.42..1.19 sor=1 szĂ©lessĂ©g=48) (valĂłs idƑ=0.031..0.032 sor=1 ciklus=1)
          Pufferek: megosztott hit=4
          ->  Index ÁtvizsgĂĄlĂĄs a task_owner_id_task_date_id_idx index alapjĂĄn a task t-n  (költsĂ©g=0.42..387.57 sor=500 szĂ©lessĂ©g=48) (valĂłs idƑ=0.030..0.030 sor=1 ciklus=1)
                Index feltétel: (owner_id = 1)
                Pufferek: megosztott hit=4
  InitPlan 2 (visszaadja $1)
    ->  Limit  (költsĂ©g=0.42..1.19 sor=1 szĂ©lessĂ©g=48) (valĂłs idƑ=0.008..0.009 sor=1 ciklus=1)
          Pufferek: megosztott hit=4
          ->  Index ÁtvizsgĂĄlĂĄs a task_owner_id_task_date_id_idx index alapjĂĄn a task t_1-en  (költsĂ©g=0.42..387.57 sor=500 szĂ©lessĂ©g=48) (valĂłs idƑ=0.008..0.008 sor=1 ciklus=1)
                Index feltétel: (owner_id = 1)
                Pufferek: megosztott hit=4
  InitPlan 3 (visszaadja $2)
    ->  Limit  (költsĂ©g=0.42..1.19 sor=1 szĂ©lessĂ©g=48) (valĂłs idƑ=0.008..0.008 sor=1 ciklus=1)
          Pufferek: megosztott hit=4
          ->  Index ÁtvizsgĂĄlĂĄs a task_owner_id_task_date_id_idx index alapjĂĄn a task t_2-n  (költsĂ©g=0.42..387.57 sor=500 szĂ©lessĂ©g=48) (valĂłs idƑ=0.008..0.008 sor=1 ciklus=1)
                Index feltétel: (owner_id = 1)
                Pufferek: megosztott hit=4
  InitPlan 4 (visszaadja $3)
    ->  Limit  (költsĂ©g=0.42..1.19 sor=1 szĂ©lessĂ©g=48) (valĂłs idƑ=0.009..0.009 sor=1 ciklus=1)
          Pufferek: megosztott hit=4
          ->  Index ÁtvizsgĂĄlĂĄs a task_owner_id_task_date_id_idx index alapjĂĄn a task t_3-on  (költsĂ©g=0.42..387.57 sor=500 szĂ©lessĂ©g=48) (valĂłs idƑ=0.009..0.009 sor=1 ciklus=1)
                Index feltétel: (owner_id = 1)
                Pufferek: megosztott hit=4

Ugyanazt a rekordot "kerestĂŒk" meg 4 alkalommal... A PostgreSQL 11-ig ez a viselkedĂ©s rendszeres volt, Ă©s a megoldĂĄs a "CTE-be" valĂł csomagolĂĄs, amely ezekben a verziĂłkban a lekĂ©rdezĂ©soptimalizĂĄlĂł hatĂĄrvonalĂĄt kĂ©pezi.

RekurzĂ­v akkumulĂĄtor

A korĂĄbbi vĂĄltozatban összesen 200 sort olvastunk a szĂŒksĂ©ges 20-Ă©rt. MĂĄr nem 960, de mĂ©g kevesebb – lehetsĂ©ges?

PrĂłbĂĄljuk meg felhasznĂĄlni azt a tudĂĄst, hogy nekĂŒnk összesen 20 rekordra van szĂŒksĂ©gĂŒnk. TehĂĄt csak addig iterĂĄlunk az adatok kiolvasĂĄsĂĄn, amĂ­g elĂ©rjĂŒk a szĂŒksĂ©ges mennyisĂ©get.

1. lĂ©pĂ©s: kezdƑ lista

NyilvĂĄnvalĂł, hogy a cĂ©lzott 20 rekordbĂłl ĂĄllĂł listĂĄnknak az "elsƑ" rekordokkal kell kezdenie, egyes owner_id kulcsok között. EzĂ©rt elƑször ilyeneket kell talĂĄlnunk "legelsƑket" minden egyes kulcs alapjĂĄn Ă©s fel kell venni a listĂĄba, a kĂ­vĂĄnt sorrendben rendezve – (task_date, id).

SQL Hogyan: while-ciklus Ă­rĂĄsa közvetlenĂŒl a lekĂ©rdezĂ©sben, vagy "ElemĂ©r hĂĄrom Ășt"

2. lĂ©pĂ©s: megtalĂĄljuk a "következƑ" rekordokat

Most, ha az elsƑ rekordot vesszĂŒk a listĂĄnkbĂłl Ă©s elkezdĂŒnk "lĂ©pkedni" tovĂĄbb az indexen a tulajdonos_azonosĂ­tĂł kulcs megtartĂĄsĂĄval az összes megtalĂĄlt bejegyzĂ©s pontosan a következƑ a lekĂ©rdezĂ©si eredmĂ©nyben. TermĂ©szetesen csak amĂ­g nem lĂ©pjĂŒk ĂĄt az alkalmazĂĄsi kulcsot a lista mĂĄsodik bejegyzĂ©sĂ©t.

Ha Ășgy alakult, hogy a mĂĄsodik bejegyzĂ©st "ĂĄtlĂ©ptĂŒk", akkor az utolsĂł olvasott bejegyzĂ©st kell hozzĂĄadni a listĂĄhoz az elsƑ helyett (ugyanazzal a tulajdonos_azonosĂ­tĂłval), majd a listĂĄt Ășjra rendezni kell.

SQL Hogyan: while-ciklus Ă­rĂĄsa közvetlenĂŒl a lekĂ©rdezĂ©sben, vagy "ElemĂ©r hĂĄrom Ășt"

Ez azt jelenti, hogy folyamatosan olyan helyzet ĂĄll elƑ, hogy a listĂĄban legfeljebb egy bejegyzĂ©s van minden kulcs szĂĄmĂĄra (ha a bejegyzĂ©sek elfogytak, Ă©s mi nem "lĂ©ptĂŒk ĂĄt", akkor az elsƑ bejegyzĂ©s egyszerƱen eltƱnik a listĂĄbĂłl, Ă©s semmi nem kerĂŒl hozzĂĄ), Ă©s ezek mindig rendezettek az alkalmazĂĄsi kulcs (task_date, id) növekvƑ sorrendjĂ©ben.

SQL Hogyan: while-ciklus Ă­rĂĄsa közvetlenĂŒl a lekĂ©rdezĂ©sben, vagy "ElemĂ©r hĂĄrom Ășt"

3. lĂ©pĂ©s: szƱrjĂŒk Ă©s "kiterjesztjĂŒk" a bejegyzĂ©seket

A rekuzĂ­v lekĂ©rdezĂ©s egyes sorai esetĂ©ben nĂ©hĂĄny bejegyzĂ©s rv megismĂ©tlƑdik - elƑször megtalĂĄljuk azokat, amelyek "ĂĄtlĂ©pik a lista 2. bejegyzĂ©sĂ©nek hatĂĄrĂĄt", majd az elsƑkĂ©nt helyettesĂ­tjĂŒk Ƒket a listĂĄban. Nos, az elsƑ elƑfordulĂĄsĂĄt ki kell szƱrni.

SzörnyƱ vĂ©gsƑ lekĂ©rdezĂ©s

REKURZÍV T KÉPVISELƐJELENETAS SELECT * GI SORNÁKRA MINDEN KULCSOT RÉSZÉRE KIALAKÍTOTT KEDVEZMÉNYLEHETƐSÉGKÉRÉSSEL MINDEN KULCSOT KÜLÖN KELLETT HASZNÁLNI! A WRAP ( - A HESTE VISSZAHÚZÁSÁVAL, ÉS A SEGÍTSÉGEK NEM CSÖKKENK FOLYAMATOS LEÍRÁSA MALCOLM ELEMENTÁRI RECORD-HOZ TISZTESSÉG RÉF ‘FELBONTÁS’ AZ HATÓANYAGOK MINT KÜLÖN ÖSSZEFONÓDÁSKI, TEHÁT A 3-IK HATÓANYAGOT KIZÁRJA, RÉG KEDVEZMÉNY ÉS MULTIPLICEI FORGÓK KERÜLNEK A LISTÁBÓL. LEGOLDALASBAN A FELIRAT NEM LETTED EZT A PONTOT, HANEM ENNEK AZ OLDTALAN PONTNAK A FƐ LEBONYOLÍTÁSÁVAL RÉGIVEL, HANEM KIEGÉSZÍTETT A KONDÍCIÓVAL KAPCSOLÓDÓ TARTALMAZÁSNAK FEJLƐDÉSÉRE.

SQL Hogyan: while-ciklus Ă­rĂĄsa közvetlenĂŒl a lekĂ©rdezĂ©sben, vagy "ElemĂ©r hĂĄrom Ășt"
[megtekintés az explain.tensor.ru-n]

EzĂ©rt 50%-os adatolvasĂĄsra 20%-os futĂĄsi idƑt cserĂ©ltĂŒnk.TehĂĄt, ha Ășgy gondolja, hogy az olvasĂĄs hosszĂș ideig eltarthat (pĂ©ldĂĄul, ha az adatok gyakran nincsenek a gyorsĂ­tĂłtĂĄrban, Ă©s a lemezen kell Ƒket keresni), akkor ebben az esetben kevesebbet lehet fĂŒggni az olvasĂĄstĂłl.

Mindenesetre a vĂ©grehajtĂĄsi idƑ jobban alakult, mint a „naiv” elsƑ vĂĄltozatban. De hogy melyik ezek közĂŒl a 3 vĂĄltozatot hasznĂĄlja – az az Ön döntĂ©se.

ForrĂĄs: habr.com

MegbĂ­zhatĂł hosting vĂĄsĂĄrlĂĄsa weboldalak szĂĄmĂĄra, DDoS vĂ©delemmel, VPS VDS szerverek. đŸ”„ MegbĂ­zhatĂł webtĂĄrhely vĂĄsĂĄrlĂĄsa DDoS vĂ©delemmel, VPS VDS szerverek | ProHoster