Å odien SQL nebÅ«s sarežģītu gadÄ«jumu un izsmalcinÄtu algoritmu. Viss bÅ«s ļoti vienkÄrÅ”i, Captain Obvious lÄ«menÄ« - darÄ«sim to apskatot notikumu reÄ£istru sakÄrtoti pÄc laika.
Tas ir, datu bÄzÄ ir zÄ«me events
, un viÅai ir lauks ts
- tieÅ”i laiks, kurÄ mÄs vÄlamies Å”os ierakstus parÄdÄ«t sakÄrtotÄ veidÄ:
CREATE TABLE events(
id
serial
PRIMARY KEY
, ts
timestamp
, data
json
);
CREATE INDEX ON events(ts DESC);
Ir skaidrs, ka mums tur nebÅ«s ducis ierakstu, tÄpÄc mums bÅ«s vajadzÄ«gs kÄds no ierakstiem lapas navigÄcija.
#0. "Es esmu savas mÄtes pogromists"
cur.execute("SELECT * FROM events;")
rows = cur.fetchall();
rows.sort(key=lambda row: row.ts, reverse=True);
limit = 26
print(rows[offset:offset+limit]);
Tas gandrÄ«z nav joks ā tas ir reti sastopams, bet savvaÄ¼Ä sastopams. Dažreiz pÄc darba ar ORM var bÅ«t grÅ«ti pÄrslÄgties uz ātieÅ”oā darbu ar SQL.
Bet pÄriesim pie biežÄk sastopamÄm un mazÄk acÄ«mredzamÄm problÄmÄm.
#1. OFFSET
SELECT
...
FROM
events
ORDER BY
ts DESC
LIMIT 26 OFFSET $1; -- 26 - Š·Š°ŠæŠøŃŠµŠ¹ Š½Š° ŃŃŃŠ°Š½ŠøŃŠµ, $1 - Š½Š°ŃŠ°Š»Š¾ ŃŃŃŠ°Š½ŠøŃŃ
No kurienes cÄlies skaitlis 26? Å is ir aptuvenais ierakstu skaits, lai aizpildÄ«tu vienu ekrÄnu. PrecÄ«zÄk, 25 parÄdÄ«tie ieraksti plus 1, kas signalizÄ, ka tÄlÄk paraugÄ ir vismaz kaut kas cits un ir jÄga doties tÄlÄk.
Protams, Å”o vÄrtÄ«bu nevar āieŔūtā pieprasÄ«juma pamattekstÄ, bet gan nodot caur 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 viegli izvÄlÄsies neefektÄ«vu plÄnu.
Un, lai gan lietojumprogrammas saskarnÄ reÄ£istra apskate tiek Ä«stenota kÄ pÄrslÄgÅ”anÄs starp vizuÄlajÄm ālapÄmā, neviens neko aizdomÄ«gu ilgu laiku nepamana. TieÅ”i lÄ«dz brÄ«dim, kad, cÄ«noties par ÄrtÄ«bÄm, UI/UX nolemj interfeisu pÄrveidot uz ābezgalÄ«gu ritinÄÅ”anuā - tas ir, visi reÄ£istra ieraksti tiek sastÄdÄ«ti vienÄ sarakstÄ, kuru lietotÄjs var ritinÄt uz augÅ”u un uz leju.
Un tÄ nÄkamÄs pÄrbaudes laikÄ jÅ«s tiekat pieÄ·erts ierakstu dublÄÅ”anÄs reÄ£istrÄ. KÄpÄc, jo tabulÄ ir normÄls indekss (ts)
, uz kuru balstÄs jÅ«su vaicÄjums?
TieÅ”i tÄpÄc, ka jÅ«s to neÅÄmÄt vÄrÄ ts
nav unikÄla atslÄga Å”ajÄ tabulÄ. PatiesÄ«bÄ, un tÄs vÄrtÄ«bas nav unikÄlas, tÄpat kÄ jebkurÅ” ālaiksā reÄlos apstÄkļos ā tÄpÄc viens un tas pats ieraksts divos blakus esoÅ”ajos vaicÄjumos viegli āpÄrlecā no lapas uz lapu, jo vienas un tÄs paÅ”as atslÄgas vÄrtÄ«bas kÄrtoÅ”anas ietvaros ir atŔķirÄ«ga galÄ«gÄ secÄ«ba.
PatiesÄ«bÄ Å”eit ir paslÄpta arÄ« otra problÄma, kuru ir daudz grÅ«tÄk pamanÄ«t - daži ieraksti netiks rÄdÄ«ti pavisam! Galu galÄ ierakstu dublikÄti ieÅÄma kÄda cita vietu. DetalizÄtu skaidrojumu ar skaistiem attÄliem var atrast
Indeksa paplaÅ”inÄÅ”ana
ViltÄ«gs izstrÄdÄtÄjs saprot, ka indeksa atslÄga ir jÄpadara unikÄla, un vienkÄrÅ”Äkais veids ir to paplaÅ”inÄt ar acÄ«mredzami unikÄlu lauku, kuram PK ir lieliski piemÄrots:
CREATE UNIQUE INDEX ON events(ts DESC, id DESC);
Un pieprasÄ«jums mainÄs:
SELECT
...
ORDER BY
ts DESC, id DESC
LIMIT 26 OFFSET $1;
#2. PÄrslÄgties uz ākursoriemā
PÄc kÄda laika pie jums atnÄk DBA un ir āgandarÄ«tsā par jÅ«su pieprasÄ«jumu
SELECT
...
WHERE
(ts, id) < ($1, $2) -- ŠæŠ¾ŃŠ»ŠµŠ“Š½ŠøŠµ ŠæŠ¾Š»ŃŃŠµŠ½Š½ŃŠµ Š½Š° ŠæŃŠµŠ“ŃŠ“ŃŃŠµŠ¼ ŃŠ°Š³Šµ Š·Š½Š°ŃŠµŠ½ŠøŃ
ORDER BY
ts DESC, id DESC
LIMIT 26;
Tu atviegloti nopÅ«ties, lÄ«dz tas atnÄca...
#3. TīrīŔanas indeksi
Jo kÄdu dienu jÅ«su DBA izlasÄ«ja (ts DESC)
.
Bet ko darÄ«t ar sÄkotnÄjo problÄmu āpÄrlÄktā ierakstus starp lapÄm?.. Un viss ir vienkÄrÅ”i - jÄatlasa bloki ar nefiksÄtu ierakstu skaitu!
VispÄr, kurÅ” mums aizliedz lasÄ«t nevis ātieÅ”i 26ā, bet gan āne mazÄk par 26ā? PiemÄram, lai nÄkamajÄ blokÄ bÅ«tu ieraksti ar acÄ«mredzami atŔķirÄ«gu nozÄ«mi ts
- tad nebÅ«s problÄmu ar ierakstu ālÄkÅ”anuā starp blokiem!
LÅ«k, kÄ to sasniegt:
SELECT
...
WHERE
ts < $1 AND
ts >= coalesce((
SELECT
ts
FROM
events
WHERE
ts < $1
ORDER BY
ts DESC
LIMIT 1 OFFSET 25
), '-infinity')
ORDER BY
ts DESC;
Kas Ŕeit notiek?
- MÄs veicam 25 ierakstus āuz lejuā un iegÅ«stam ārobežasā vÄrtÄ«bu
ts
. - Ja tur jau nekÄ nav, aizstÄjiet NULL vÄrtÄ«bu ar
-infinity
. - No saÅemtÄs vÄrtÄ«bas mÄs atÅemam visu vÄrtÄ«bu segmentu
ts
un parametrs $1, kas nodots no saskarnes (iepriekÅ”ÄjÄ āpÄdÄjÄā renderÄtÄ vÄrtÄ«ba). - Ja bloks tiek atgriezts ar mazÄk nekÄ 26 ierakstiem, tas ir pÄdÄjais.
Vai arÄ« tas pats attÄls:
Jo tagad mums ir paraugam nav nekÄda konkrÄta āsÄkumaā, tad nekas neliedz mums āizvÄrstā Å”o pieprasÄ«jumu pretÄjÄ virzienÄ un Ä«stenot datu bloku dinamisku ielÄdi no āatskaites punktaā abos virzienos - gan uz leju, gan uz augÅ”u.
Piezīme:
- JÄ, Å”ajÄ gadÄ«jumÄ mÄs piekļūstam indeksam divas reizes, bet viss notiek ātÄ«ri pÄc indeksaā. TÄpÄc apakÅ”vaicÄjums radÄ«s tikai uz vienu papildu tikai indeksa skenÄÅ”anu.
- Ir pilnÄ«gi skaidrs, ka Å”o paÅÄmienu var izmantot tikai tad, ja jums ir vÄrtÄ«bas
ts
var ŔķÄrsot tikai nejauÅ”i, un tÄdu nav daudz. Ja jÅ«su tipiskais gadÄ«jums ir āmiljons ierakstu pulksten 00:00:00.000ā, jums tas nevajadzÄtu darÄ«t. Es domÄju, jums nevajadzÄtu pieļaut, ka Å”Äds gadÄ«jums notiek. Bet, ja tÄ notiek, izmantojiet opciju ar paplaÅ”inÄtu indeksu.
Avots: www.habr.com