Leo hakutakuwa na kesi ngumu na algorithms ya kisasa katika SQL. Kila kitu kitakuwa rahisi sana, kwa kiwango cha Kapteni Dhahiri - wacha tuifanye kutazama rejista ya tukio kupangwa kwa wakati.
Hiyo ni, kuna ishara katika hifadhidata events
, na ana shamba ts
- wakati hasa ambao tunataka kuonyesha rekodi hizi kwa njia ya utaratibu:
CREATE TABLE events(
id
serial
PRIMARY KEY
, ts
timestamp
, data
json
);
CREATE INDEX ON events(ts DESC);
Ni wazi kuwa hatutakuwa na rekodi kadhaa hapo, kwa hivyo tutahitaji aina fulani ya urambazaji wa ukurasa.
#0. "Mimi ni mchawi wa mama yangu"
cur.execute("SELECT * FROM events;")
rows = cur.fetchall();
rows.sort(key=lambda row: row.ts, reverse=True);
limit = 26
print(rows[offset:offset+limit]);
Ni karibu si utani - ni nadra, lakini hupatikana katika pori. Wakati mwingine, baada ya kufanya kazi na ORM, inaweza kuwa vigumu kubadili kazi ya "moja kwa moja" na SQL.
Lakini wacha tuendelee kwenye shida za kawaida na zisizo wazi.
#1. OFFSET
SELECT
...
FROM
events
ORDER BY
ts DESC
LIMIT 26 OFFSET $1; -- 26 - Π·Π°ΠΏΠΈΡΠ΅ΠΉ Π½Π° ΡΡΡΠ°Π½ΠΈΡΠ΅, $1 - Π½Π°ΡΠ°Π»ΠΎ ΡΡΡΠ°Π½ΠΈΡΡ
Namba 26 ilitoka wapi? Hii ndiyo idadi ya takriban ya maingizo ya kujaza skrini moja. Kwa usahihi zaidi, rekodi 25 zilizoonyeshwa, pamoja na 1, zikiashiria kwamba kuna angalau kitu kingine zaidi katika sampuli na inaleta maana kuendelea.
Kwa kweli, dhamana hii haiwezi "kushonwa" kwenye mwili wa ombi, lakini kupita kwa paramu. Lakini katika kesi hii, kipanga ratiba cha PostgreSQL hataweza kutegemea maarifa kwamba kunapaswa kuwa na rekodi chache - na atachagua kwa urahisi mpango usiofaa.
Na ukiwa kwenye kiolesura cha programu, kutazama sajili kunatekelezwa kama kubadili kati ya "kurasa" zinazoonekana, hakuna mtu anayeona chochote cha kutiliwa shaka kwa muda mrefu. Hasa hadi wakati ambapo, katika mapambano ya urahisishaji, UI/UX itaamua kutengeneza tena kiolesura kuwa "kusogeza bila mwisho" - yaani, maingizo yote ya usajili yamechorwa katika orodha moja ambayo mtumiaji anaweza kusogeza juu na chini.
Na kwa hivyo, wakati wa majaribio yanayofuata, utakamatwa kurudia kumbukumbu katika Usajili. Kwa nini, kwa sababu meza ina index ya kawaida (ts)
, swali lako linategemea lipi?
Hasa kwa sababu haukuzingatia hilo ts
sio ufunguo wa kipekee katika meza hii. Kwa kweli, na maadili yake si ya kipekee, kama "wakati" wowote katika hali halisi - kwa hivyo, rekodi sawa katika hoja mbili zilizo karibu "huruka" kwa urahisi kutoka ukurasa hadi ukurasa kwa sababu ya mpangilio tofauti wa mwisho ndani ya mfumo wa kupanga thamani sawa ya ufunguo.
Kwa kweli, pia kuna shida ya pili iliyofichwa hapa, ambayo ni ngumu zaidi kugundua - baadhi ya maingizo hayataonyeshwa hata kidogo! Baada ya yote, rekodi za "duplicate" zilichukua nafasi ya mtu mwingine. Maelezo ya kina na picha nzuri yanaweza kupatikana
Kupanua index
Msanidi programu janja anaelewa kuwa ufunguo wa faharasa unahitaji kufanywa kuwa wa kipekee, na njia rahisi ni kuupanua kwa uga wa kipekee, ambao PK inafaa kabisa:
CREATE UNIQUE INDEX ON events(ts DESC, id DESC);
Na ombi linabadilika:
SELECT
...
ORDER BY
ts DESC, id DESC
LIMIT 26 OFFSET $1;
#2. Badili hadi "cursors"
Muda fulani baadaye, DBA inakuja kwako na "imefurahishwa" kwamba maombi yako
SELECT
...
WHERE
(ts, id) < ($1, $2) -- ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡΡΠ΅Π½Π½ΡΠ΅ Π½Π° ΠΏΡΠ΅Π΄ΡΠ΄ΡΡΠ΅ΠΌ ΡΠ°Π³Π΅ Π·Π½Π°ΡΠ΅Π½ΠΈΡ
ORDER BY
ts DESC, id DESC
LIMIT 26;
Ulishusha pumzi hadi ikafika...
#3. Fahirisi za kusafisha
Kwa sababu siku moja DBA yako ilisoma (ts DESC)
.
Lakini ni nini cha kufanya na shida ya awali ya rekodi za "kuruka" kati ya kurasa?
Kwa ujumla, ni nani anayetuzuia kusoma "haswa 26", lakini "si chini ya 26"? Kwa mfano, ili katika block inayofuata kuna rekodi zenye maana tofauti dhahiri ts
- basi hakutakuwa na shida na rekodi za "kuruka" kati ya vitalu!
Hivi ndivyo jinsi ya kufikia hili:
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;
Nini kinaendelea hapa?
- Tunaweka rekodi 25 "chini" na kupata thamani ya "mpaka".
ts
. - Ikiwa hakuna kitu hapo tayari, basi badilisha thamani ya NULL na
-infinity
. - Tunaondoa sehemu nzima ya thamani kati ya thamani iliyopokelewa
ts
na kigezo cha $1 kilichopitishwa kutoka kwa kiolesura (thamani ya awali ya "mwisho" iliyotolewa). - Ikiwa kizuizi kitarejeshwa na rekodi chini ya 26, ni ya mwisho.
Au picha sawa:
Kwa sababu sasa tunayo sampuli haina "mwanzo" maalum, basi hakuna kitakachotuzuia "kupanua" ombi hili katika mwelekeo tofauti na kutekeleza upakiaji unaobadilika wa vizuizi vya data kutoka kwa "hatua ya marejeleo" katika pande zote mbili - chini na juu.
Kumbuka
- Ndiyo, katika kesi hii tunapata index mara mbili, lakini kila kitu ni "purely by index". Kwa hivyo, subquery itasababisha tu kwa Fahirisi moja ya ziada Pekee Scan.
- Ni dhahiri kabisa kwamba mbinu hii inaweza kutumika tu wakati una maadili
ts
inaweza kuvuka kwa bahati tu, na hakuna wengi wao. Ikiwa kesi yako ya kawaida ni "rekodi milioni saa 00:00:00.000", hupaswi kufanya hivyo. Namaanisha, haupaswi kuruhusu kesi kama hiyo kutokea. Lakini ikiwa hii itatokea, tumia chaguo na index iliyopanuliwa.
Chanzo: mapenzi.com