Пагинатсия ва курсорҳо
1) Чаро саҳифабандӣ лозим аст
Пагинатсия миқдори маълумоти интиқолшуда ва пешниҳодкардаи муштариро маҳдуд мекунад, сарбориро дар анбор/шабакаҳо коҳиш медиҳад ва роҳи муайянкунандаи "рафтан" -ро тавассути коллексия муқаррар мекунад. Дар системаҳои воқеӣ, саҳифабандӣ на танҳо 'саҳифа = 1 & лимит = 50', балки маҷмӯи шартномаҳои протокол ва инвариантҳои пайдарҳамӣ мебошад.
Ҳадафҳои маъмулӣ:- Назорати хотира ва хотира барои як дархост.
- Паймоиши устувор ҳангоми тағир додани маҷмӯа (ворид/нест кардан).
- Қобилияти дубора аз ҷой (дубора оғоз кардан).
- Кэшинг ва пешпардохт (префетч).
- Муҳофизат аз сӯиистифода (маҳдудкунии меъёрҳо, ақибмонӣ).
2) Моделҳои пагинатсия
2. 1 OFFSET/LIMIT (саҳифа)
Идея: "хатҳои N гузаред, М.-ро баргардонед".
Тарафдор: содда, бо қариб ҳама гуна SQL/No.SQL мувофиқ аст.
- Таназзули хатӣ: OFFSET-ҳои калон ба скан/арзиши пурраи онҳо оварда мерасонанд.
- Ноустуворӣ ҳангоми воридкунӣ/несткунӣ байни дархостҳо (ҷуброни "шино").
- Таъмини дақиқи "барқароршавӣ" мушкил аст.
sql
SELECT
FROM orders
ORDER BY created_at DESC, id DESC
OFFSET 1000 LIMIT 50;
2. 2 Курсор/Keyset/Ҷустуҷӯ-саҳифа
Идея: "бо калиди K равед. "Курсор мавқеъ дар маҷмӯи мураттаб аст.
Тарафдор:- O (1) дастрасӣ барои идома додани индекс.
- Устуворӣ ҳангоми тағирёбии ҷамъоварӣ.
- Беҳтарин таъхир дар "саҳифаҳои" амиқ.
- Ба мо калидҳои қатъии муайяншуда, беназир ва якхела лозиманд.
- Татбиқ ва ислоҳи он мушкилтар аст.
sql
-- Resumption after steam (created_at, id) = (:last_ts,:last_id)
SELECT
FROM orders
WHERE (created_at, id) < (:last_ts,:last_id)
ORDER BY created_at DESC, id DESC
LIMIT 50;
2. 3 Нишонаҳои давомдор
Идея: сервер аломати ношаффофро бармегардонад, ки дар он "мавқеъ" рамзгузорӣ шудааст (ва эҳтимолан ҳолати шардҳо/филтрҳо). Мизоҷ дохилиҳоро намефаҳмад ва танҳо аломати саҳифаи навбатиро бармегардонад.
Тарафдор: чандирӣ, қобилияти тағир додани схема бидуни шикастани API.
Омӯз: идоракунии мӯҳлати нишона, мутобиқат бо амонатҳо.
2. 4 Курсорҳои вақт ва мантиқӣ
Вақт асос ёфтааст: "ҳама сабтҳо то T", курсор - мӯҳри вақт (барои риштаҳои танҳо замима мувофиқ аст).
Log-sequence/offset-based: курсор - ҷуброн дар журнал (Кафка офсет, журнал seq).
ID-ҳои глобалии монотоникӣ: ҳамчун калидҳои ҷудошаванда барои ҷустуҷӯи устувор.
3) Тарроҳии курсҳо ва нишонаҳо
3. 1 Хусусиятҳои курсори хуб
Opaque-Мизоҷ формати мустақил аст.
Муаллиф/якпорчагӣ: имзои HMAC барои пешгирии ғорат/қаллобӣ.
Контекст: навъбандӣ, филтрҳо, версияи схема, иҷорагир/шардро дар бар мегирад.
Давомнокии умр: TTL ва "такрорӣ" ҳангоми тағир додани индексатсияҳо/ҳуқуқҳои дастрасӣ.
Андоза: паймон (<= 1-2 KB), ки барои URL мувофиқ аст.
3. 2 Формати токен
Анбори тавсияшуда: JSON → фишурдасозӣ (zstd/deflate) → Base64URL → HMAC.
Сохтори сарборӣ (мисол):json
{
"v": 3 ,//token version
"sort": ["created_at:desc","id:desc"],
"pos": {"created_at":"2025-10-30T12:34:56. 789Z","id":"987654321"},
"filters": {"user_id":"42","status":["paid","shipped"]},
"tenant": "eu-west-1",
"shards": [{"s ": "a, "" hi":"..."}] ,//optional: cross-shard context
"issued_at": "2025-10-31T14:00:00Z",
"ttl_sec": 3600
}
'mac = HMAC (махфӣ, сарборӣ)' дар боло илова карда мешавад ва ҳама чиз ба як аломати сатр рамзгузорӣ мешавад.
3. 3 Бехатарӣ
Имзо (HMAC/SHA-256).
Рамзгузории ихтиёрӣ (AES-GCM) дар ҳузури арзишҳои ҳассос (PII).
Тасдиқи сервер: версия, TTL, мақомоти корбар (RBAC/ABAC).
4) Мутобиқат ва ғайривариантҳо
4. 1 Навъбандии устувор
Детерминизмро пурра истифода баред: 'Фармоиш бо DESC, id DESC'.
Калиди навъбандӣ бояд беназир бошад ('id' -ро ҳамчун tiebreaker илова кунед).
Индекс бояд ба шохиси пӯшиш мувофиқат кунад.
4. 2 Лаҳзаҳо ва ҷудокунӣ
Барои саҳифаҳои ғайри jumbo, лаҳзаи хонишро пайваста истифода баред (MVCC/txid).
Агар сурат ғайриимкон бошад (гарон/бисёр маълумот), шартнома тартиб диҳед: "курсор унсурҳоро ба таври қатъӣ пеш аз мавқеъ бармегардонад. "Ин барои навигариҳои навигарӣ табиӣ аст.
4. 3 Воридкунӣ/несткунӣ дар байни саҳифаҳо
Ҷустуҷӯ-модел "нусхаҳо/нуқсонҳо" -ро кам мекунад.
Рафтори нест кардан/тағир додани ҳуҷҷатҳо: "сӯрохиҳои" нодир дар байни саҳифаҳо иҷозат дода мешаванд, аммо на "бо гузашти вақт".
5) Нақшаҳои индексатсия ва ID
Нишондиҳандаҳои таркибӣ ба таври қатъӣ ба тартиб оварда мешаванд: '(created_at DESC, id DESC)'.
ID-ҳои Monotone: Snowflake/UUIDv7 фармоишро саривақт фармоиш диҳед
Калидҳои гарм: бо калиди shard тақсим кунед (масалан, 'иҷорагир _ ид', 'минтақа') ва дар дохили шард ҷудо кунед.
Генераторҳои ID: пешгирӣ аз бархӯрд ва "skew соат" - ҳамоҳангсозии вақт, "регрессия" ҳангоми ҷаҳиши NTP.
6) Пагинатсияи салиб-шард
6. 1 схемаҳо
Scatter-Gather: дархостҳои мувозӣ ба ҳама shards, курсҳои ҷустуҷӯии маҳаллӣ, сипас k-way дар агрегат.
Курсорҳои Per-Shard: Нишона мавқеъҳоро дар ҳар як шард дорад.
Маҳдудияти мухлиси маҳдудшуда шумораи shards барои як қадам (меъёри маҳдудият/буҷаи вақт).
6. 2 Токенҳо барои бисёр шард
Массаи '{shard _ id, last_pos}'. Дар қадами навбатӣ, барои ҳар як риштаи фаъол дубора оғоз кунед ва дубора нигоҳ дошта, саҳифаи глобалии мураттабро диҳед.
7) Шартномаҳои протокол
7. 1 ИСТИРОҲАТ
Дархост:
GET /v1/orders? limit=50&cursor=eyJ2IjoiMyIsInNvcnQiOiJjcmVh... (opaque)
Ҷавоб:
json
{
"items": [ /... / ],
"page": {
"limit": 50,
"next_cursor": "eyJ2IjozLCJwb3MiOiJjcmVh...==",
"has_more": true
}
}
Тавсияҳо:
- 'limit' with сарҳади болоӣ (масалан, max = 200).
- 'next _ cursor' мавҷуд нест, агар 'has _ more = false'.
- Idempotence, қобилияти посухҳоро бидуни 'next _ cursor' гиред (саҳифаи аввал бо филтрҳои собит ва сурат).
7. 2 Диаграммаи QL (Равиши эстафета)
Шартномаи маъмулии "пайвастшавӣ":graphql type Query {
orders(first: Int, after: String, filter: OrderFilter): OrderConnection!
}
type OrderConnection {
edges: [OrderEdge!]!
pageInfo: PageInfo!
}
type OrderEdge {
node: Order!
cursor: String! // opaque
}
type PageInfo {
hasNextPage: Boolean!
endCursor: String
}
'cursor' must ношаффоф ва имзо бошад; "хом Base64 (id)" -ро бе HMAC истифода набаред.
7. 3 GRPC
Истифодаи 'page _ size' ва 'page _ token':proto message ListOrdersRequest {
string filter = 1;
int32 page_size = 2;
string page_token = 3; // opaque
}
message ListOrdersResponse {
repeated Order items = 1;
string next_page_token = 2; // opaque bool has_more = 3;
}
7. 4 Риштаҳо ва веб-сокетҳо
Барои наворҳои бефосила: курсор ҳамчун "офсет/тс охирин дида мешавад".
Дастгирии 'resume _ from' ҳангоми пайвастшавӣ:json
{ "action":"subscribe", "topic":"orders", "resume_from":"2025-10-31T12:00:00Z#987654321" }
8) Caching, Preload, CDN
ET bag/If-None-Match барои саҳифаи аввал бо филтрҳои устувор.
Кэш-Назорат бо TTL кӯтоҳ (масалан, 5-30 с) барои рӯйхати оммавӣ.
Prefetch: бозгашт 'next _ cursor' ва маслиҳатҳо ('Link: rel = "next"), муштарӣ метавонад саҳифаи навбатиро бор кунад.
Вариантҳо: 'Филтр/навъ/локал/иҷорагир' -ро ҳамчун калиди қисми кэш баррасӣ кунед.
9) Идоракунии сарборӣ ва маҳдудият
Сарҳади болоӣ 'limit', масалан 200.
Пуштибонии канори сервер: агар вақти дархост> буҷа бошад, дар ҷавоб "маҳдудият" -ро кам кунед (ва ба таври возеҳ ба муштарӣ андозаи воқеии саҳифаро бигӯед).
Меъёри нархҳо барои як корбар/токен/иҷорагир.
Вақт/Retry: таваққуфи экспоненсиалӣ, дархостҳои такрории idempotent.
10) Ҷанбаҳои UX
Ҳаракат ба рақамгузорӣ: ҳаракатҳои беохир → курсорҳо; саҳифаҳои рақамҳо → ҷуброн карда мешаванд (аммо ҳангоми нав кардани маълумот носаҳеҳиро шарҳ диҳед).
Бозгашт ба ҷои тугма: Анбори курсори мизоҷро нигоҳ доред.
Саҳифаҳои холӣ: Агар 'has _ more = false' бошад, тугмаи Бештарро нишон надиҳед.
Сарҳадҳои устувор: "ҳамагӣ" -ро танҳо дар сурати арзон нишон диҳед (вагарна ин тақрибан "равиш _ total" аст).
11) Парвандаҳои санҷишӣ ва канорӣ
Рӯйхати назоратӣ:- Гурӯҳбандии устувор: Ашёҳо бо ҳамон 'ts' "чашм напӯшанд".
- Иловаҳо/Нест кардан - Нусхаҳо дар чорроҳаи саҳифа пайдо намешаванд.
- Тағйир додани филтрҳо дар байни саҳифаҳо: Токен бояд ҳамчун кӯҳна/номувофиқ рад карда шавад.
- Токен TTL: Хатои дуруст баъди ба охир расидани мӯҳлат.
- Чуқурии калон: Таъхир ба таври хаттӣ афзоиш намеёбад.
- Multishard: тартиби дурусти якҷояшавӣ, набудани гуруснагӣ "суст".
python
Generate N entries with random inserts between calls
Verify that all pages are merged = = whole ordered fetch
12) Мушоҳида ва SLO
Нишондиҳандаҳо:- 'list _ request _ latency _ ms' (P50/P95/P99) аз рӯи дарозии саҳифа.
- 'search _ index _ hit _ таносуб' (таносуби дархостҳое, ки бо шохиси фарогирӣ гузошта шудаанд).
- 'next _ cursor _ valiid _ rate' (хатогиҳои санҷиш/TTL/имзо).
- 'merge _ fanout' (шумораи shards ҷалбшуда дар як саҳифа).
- 'duplicates _ on _ boundary' ва 'холигоҳҳо _ on _ boundary' (муайянкунӣ дар телеметрияи муштарӣ).
- Коррелятсияи 'курсор _ ид' дар гузоришҳо, сарбории ниқоб.
- Андозаи теги: 'page _ size', 'source _ shards', 'db _ index _ used'.
- Мавҷудият: 99. 9% аз усулҳои 'Рӯйхат'.
- Таъхир: P95 <200 ms барои 'page _ size <= 50' бо пардохти маҳаллӣ.
- Хатои токен: <0. 1% шумораи умумии зангҳо.
13) Муҳоҷират ва созгорпазирӣ
Фаъол кардани 'v' дар аломат ва нусхаҳои кӯҳнаи ҳафтаҳои N.
Ҳангоми тағир додани тугмаҳои навъ - хатои "мулоим" '409 низоъ' -ро бо дархости иҷрои рӯйхати нав бидуни курсор фиристед.
Ҳолати фалокатбор (ғавғои ҳама нишонаҳо): тағир додани 'имзо _ key _ id' ва рад кардани кӯҳнаҳо.
14) Намунаҳои татбиқ
14. 1 Насли токен (псевдокод)
python payload = json. dumps({...}). encode()
compressed = zlib. compress(payload)
mac = hmac_sha256(signing_key, compressed)
token = base64url_encode(mac + compressed)
14. 2 Тасдиқи токен
python raw = base64url_decode(token)
mac, compressed = raw[:32], raw[32:]
assert mac == hmac_sha256(signing_key, compressed)
payload = json. loads(zlib. decompress(compressed))
assert now() - payload["issued_at"] < payload["ttl_sec"]
assert payload["filters"] == req. filters
14. 3 Ҷустуҷӯи дархост бо калиди таркибӣ
sql
-- Page # 1
SELECT FROM feed
WHERE tenant_id =:t
ORDER BY ts DESC, id DESC
LIMIT:limit;
-- Next pages, continued after (ts0, id0)
SELECT FROM feed
WHERE tenant_id =:t
AND (ts <:ts0 OR (ts =:ts0 AND id <:id0))
ORDER BY ts DESC, id DESC
LIMIT:limit;
15) Бехатарӣ ва риояи
Майдонҳои хомро ба нишонаҳое, ки аз онҳо PII гирифтан мумкин аст, дохил накунед.
Имзо ва маҳдуд TTL.
Кӯшиш кунед, ки нишонаҳоро дар байни корбарон тоқатнопазир созед ('sub/иҷорагир/нақшҳоро' дар сарборӣ нависед ва ҳангоми санҷиш тафтиш кунед).
Журнал танҳо hash токен.
16) Хатогиҳои зуд-зуд ва зидди намунаҳо
Base64 (id) ҳамчун курсор: қалбакӣ/гирифтан осон аст, ҳангоми тағир додани навъ шартномаро вайрон мекунад.
Ягон галстук нест: 'ORDER BY ts DESC' бидуни 'id' → нусхабардорӣ/ҷаҳиш.
Тағйир додани филтрҳо дар байни саҳифаҳо бе беэътибор кардани нишона.
OFFSET Deep: Оҳиста ва пешгӯинашаванда.
Токенҳо бе версия ва TTL.
17) Татбиқи рӯйхати мини назоратӣ
1. Навъро муайян кунед ва галстуки беназирро илова кунед.
2. Сохтани индекси паҳнкунӣ барои ин тартиб.
3. Моделро интихоб кунед: ҷустуҷӯи + аломати ношаффоф.
4. Амалисозии имзои токен (ва агар лозим бошад, рамзгузорӣ).
5. TTL ва версияро гузоред.
6. Шартномаҳои 'дорои _ more', 'next _ cursor' таҳия ва ҳуҷҷат кунед.
7. Схемаи кроссвордро (агар лозим бошад) ва якҷояшавии k-way-ро баррасӣ кунед.
8. Илова кардани ченакҳо, огоҳиҳо ва SLO.
9. Саҳифаи ба амвол асосёфтаро бо озмоишҳо фаро гиред.
10. Стратегияи муҳоҷиратро барои нишонаҳо тавсиф кунед.
18) Тавсияҳои мухтасар оид ба интихоби равиш
Феҳристҳо/ҷустуҷӯҳо, ки дар он "рақами саҳифа" ва шумораи тахминии онҳо муҳиманд: биёед 'OFFSET/LIMIT' + кэш бигӯем; гузориш диҳед, ки ҳамагӣ тақрибан аст.
Каналҳо, таҳлилҳо, рӯйхатҳои амиқ, RPS-и баланд: курсор/танҳо ҷустуҷӯ.
Маҷмӯаҳои Shardy/тақсимшуда: курсорҳои ҳар як шард + аломати якҷояшавӣ.
Риштаҳо/CDC: курсорҳо ҳамчун ҷуброн/ts бо резюме.
19) Намунаи созишномаи API (хулоса)
'GET/v1/ашё? лимит = 50 & курсор =... '
Ҷавоб ҳамеша 'саҳифаро дар бар мегирад. маҳдуд ',' саҳифа. has_more', ихтиёрӣ. next_cursor'.
Курсор номуайян аст, бо TTL имзо шудааст.
Sort ин муайянкунандаи 'ORDER BY created_at DESC, id DESC' мебошад.
Тағйир додани рафтор-Ҷузъҳо нисбат ба курсор "барнагарданд".
Нишондиҳандаҳо ва хатогиҳо стандартизатсия карда мешаванд: 'нодуруст _ курсор', 'мӯҳлати таъиншуда _ курсор', 'номувофиқатии _ филтрҳо'.
Ин мақола принсипҳои меъморӣ ва намунаҳои тайёрро барои тарроҳии саҳифа, ки ҳатто дар додаҳои калон, шармгин ва фаъолона тағирёбанда боқӣ мемонанд, таъмин менамояд.