Å odien nebÅ«s nekÄdu sarežģītu gadÄ«jumu un muļķīgu algoritmu SQL. Viss bÅ«s ļoti vienkÄrÅ”i, KapteiÅa AcÄ«mredzamÄ«ba lÄ«menÄ« ā darÄm notikumu reÄ£istra apskate sacensÄ«bÄm pa laiku.
TÄtad Å”ajÄ datubÄzÄ ir tabula events, un tai ir lauks ts ā tieÅ”i tas pats laiks, pÄc kura mÄs vÄlamies Å”os ierakstus kÄrtot parÄdÄ«t:
CREATE TABLE events(
id
serial
PRIMARY KEY
, ts
timestamp
, data
json
);
CREATE INDEX ON events(ts DESC);Ir skaidrs, ka ierakstu tur bÅ«s ne desmit, tÄdÄļ mums kaut kÄdÄ veidÄ lappuÅ”u navigÄcija.
#0. «Я Ń Š¼Š°Š¼Ń ŠæŠ¾Š³ŃŠ¾Š¼Š¼ŠøŃŃĀ»
cur.execute("SELECT * FROM events;")
rows = cur.fetchall();
rows.sort(key=lambda row: row.ts, reverse=True);
limit = 26
print(rows[offset:offset+limit]);
PatiesÄ«bÄ tÄ nav pat joks ā tas notiek reti, bet dažreiz sastopams brÄ«vÄ dabÄ. Dažreiz pÄc darba ar ORM ir grÅ«ti pÄriet uz "tieÅ”o" darbu ar SQL.
Bet pÄriesim pie izplatÄ«tÄkÄm un mazÄk acÄ«mredzamÄm problÄmÄm.
#1. OFFSET
SELECT
...
FROM
events
ORDER BY
ts DESC
LIMIT 26 OFFSET $1; -- 26 - ierakstu skaits lapÄ, $1 - lappuses sÄkumsKÄpÄc Å”eit ir skaitlis 26? Tas ir aptuvenais ierakstu skaits, kas nepiecieÅ”ams viena ekrÄna aizpildīŔanai. PrecÄ«zÄk, 25 attÄlotie ieraksti, plus 1, kas signalizÄ, ka tÄlÄk izvÄlÄ ir kaut kas cits, un ir jÄga turpinÄt.
Protams, Å”o vÄrtÄ«bu varÄtu nepievienot jautÄjumam, bet nodot to kÄ parametru. Bet Å”ajÄ gadÄ«jumÄ PostgreSQL plÄnotÄjs nevarÄs paļauties uz zinÄÅ”anÄm, ka ierakstu vajadzÄtu bÅ«t salÄ«dzinoÅ”i maz, ā un bildÄtu neefektÄ«vu plÄnu.
Un kamÄr lietojumprogrammas saskarnÄ notikumu reÄ£istra apskate tiek Ä«stenota kÄ pÄrslÄgÅ”anÄs starp vizuÄlÄm "lappusÄm", neviens ilgi nemanÄ«s neko aizdomÄ«gu. TieÅ”i lÄ«dz brÄ«dim, kad cÄ«ÅÄ par Ärtumu UI/UX nolemj pÄrveidot saskarni uz "bezgalÄ«go ritinÄÅ”anu" ā tas ir, visi reÄ£istra ieraksti tiek parÄdÄ«ti vienÄ sarakstÄ, ko lietotÄjs var ritinÄt uz augÅ”u un uz leju.
Un, veicot kÄrtÄjo testÄÅ”anu, jÅ«s sastopat ierakstu dublÄÅ”anu reÄ£istrÄ. KÄpÄc, ja tabulai ir normÄls indekss (ts), uz kuru balstÄs jÅ«su pieprasÄ«jums?
TieÅ”i tÄpÄc, ka jÅ«s neesat ÅÄmuÅ”i vÄrÄ, ka ts nav unikÄls atslÄga Å”ajÄ tabulÄ. PatiesÄ«bÄ arÄ« tÄ vÄrtÄ«bas nav unikÄlas, kÄ jebkurÄ ālaikÄā reÄlajos apstÄkļos ā tÄpÄc viena un tÄ pati ieraksts divÄs blakus esoÅ”Äs pieprasÄ«jumos viegli ālÄcā no lapas uz lapu, pateicoties citam galÄ«gajam secÄ«bÄ tÄdas paÅ”as atslÄgas vÄrtÄ«bas kÄrtÄ«bÄ.
PatiesÄ«bÄ Å”eit slÄpjas vÄl otra problÄma, kuru pamanÄ«t ir daudz grÅ«tÄk ā daži ieraksti vispÄr netiks parÄdÄ«ti! Jo āduplikÄtiā ieraksti aizÅÄma kÄda cita vietu. DetalizÄtu skaidrojumu ar skaistÄm bildÄm var .
PaplaÅ”inÄm indeksu
ViltÄ«gs izstrÄdÄtÄjs saprot ā jÄpadara indeksa atslÄga unikÄla, un vienkÄrÅ”Äkais veids ir to paplaÅ”inÄt ar iepriekÅ” noteiktu unikÄlu lauku, kÄ tam lieliski piemÄrots bÅ«s PK:
CREATE UNIQUE INDEX ON events(ts DESC, id DESC);Un pieprasÄ«jums mutÄ:
SELECT
...
ORDER BY
ts DESC, id DESC
LIMIT 26 OFFSET $1;#2. ŠŠµŃŠµŃ Š¾Š“ на «кŃŃŃŠ¾ŃŃĀ»
PÄc kÄda laika pie jums nÄk DBA un āpriecÄā, ka jÅ«su pieprasÄ«jumi , un vispÄr, ir laiks pÄriet uz navigÄciju no pÄdÄjÄ rÄdÄ«tÄ vÄrtÄ«ba. JÅ«su pieprasÄ«jums atkal mutÄ:
SELECT
...
WHERE
(ts, id) < ($1, $2) -- pÄdÄjÄs iegÅ«tÄs vÄrtÄ«bas iepriekÅ”ÄjÄ solÄ«
ORDER BY
ts DESC, id DESC
LIMIT 26;JÅ«s atviegloti ieelpojat, lÄ«dz nebeidzÄs...
#3. ЧиŃŃŠŗŠ° ŠøŠ½Š“ŠµŠŗŃŠ¾Š²
TÄpÄc, ka kÄdu dienu jÅ«su DBA izlasÄ«ja un saprata, ka āne pÄdÄjaisā timestamps ā tas nav labi.Un atkal atnÄca pie jums ā tagad ar domu, ka Å”im indeksam tomÄr vajadzÄtu atgriezties (ts DESC).
Bet ko darÄ«t ar sÄkotnÄjo problÄmu ālÄcienaā ierakstiem starp lapÄm?.. Viss ir vienkÄrÅ”i ā ir jÄizvÄlas bloki ar nefixÄtu ierakstu skaitu!
VispÄr, kurÅ” mums aizliedz lasÄ«t ne āprecÄ«zi 26ā, bet āne mazÄk kÄ 26ā? PiemÄram, tÄ, lai nÄkamajÄ blokÄ bÅ«tu ieraksti ar noteikti citÄdÄm vÄrtÄ«bÄm ts ā tad jau nebÅ«s arÄ« problÄmu ar ālÄcieniemā ierakstiem starp blokiem!
Å Ädi to var panÄkt:
SELECT
...
WHERE
ts = coalesce((
SELECT
ts
FROM
events
WHERE
ts < $1
ORDER BY
ts DESC
LIMIT 1 OFFSET 25
), '-infinity')
ORDER BY
ts DESC;Kas Å”eit vispÄr notiek?
- Izsoļojam par 25 ierakstiem āuz lejuā un iegÅ«stam ārobežuā vÄrtÄ«bu
ts. - Ja tur vairs nav neko, tad nomainÄm NULL vÄrtÄ«bu uz
-infinity. - IzslÄdzam visu vÄrtÄ«bu segmentu starp iegÅ«to vÄrtÄ«bu
tsun nodoto no saskarnes parametru $1 (iepriekÅ”Äjo āpÄdÄjoā uzzÄ«mÄto vÄrtÄ«bu). - Ja, ja, blokam, kas atgriežas ar mazÄk nekÄ 26 ierakstiem ā tas ir pÄdÄjais.
Vai tas paÅ”as parÄdÄs attÄlÄ:

Tagad mums ir paraugs nav noteikts "sÄkums", tÄpÄc nekas neļauj mums "pagriezt" Å”o pieprasÄ«jumu pretÄjÄ virzienÄ un realizÄt dinamisko datu bloku ielÄdÄÅ”anu no "atsauces punkta" abos virzienos ā gan uz leju, gan uz augÅ”u.
Piezīme
- JÄ, Å”ÄdÄ gadÄ«jumÄ mÄs piekļūstam indeksam divreiz, taÄu viss "tÄ«ri pÄc indeksa". TÄpÄc iegultais pieprasÄ«jums radÄ«s tikai vienu papildu Index Only Scan.
- Pietiekami acÄ«mredzami, ka Ŕī metodika ir izmantojama tikai tad, ja jums ir vÄrtÄ«bas
tsvar pÄrsniegt tikai nejauÅ”i, un to ir maz. Ja jÅ«su tipisks gadÄ«jums ir "miljons ierakstu 00:00:00.000", tad tÄ nedrÄ«kst darÄ«t. Proti, nedrÄ«kst pieļaut Å”Ädu gadÄ«jumu. Bet, ja tÄ nu ir sanÄcis, izmantojiet paplaÅ”inÄtÄ indikatora variantu.
Avots: habr.com
