Cursor — query natijasidagi rowlar to‘plami bo‘ylab bosqichma-bosqich yurish imkonini beradigan database mexanizmi. Cursor bir vaqtning o‘zida butun natijani application memory’siga yuklamasdan rowlarni ketma-ket olish yoki procedure ichida har rowga alohida ishlov berish uchun ishlatiladi.
Cursor atamasi database server cursor, client cursor va pagination cursor ma’nolarida ishlatilishi mumkin.
Result set holati
Oddiy query ko‘p row qaytaradi.
Cursor:
- qaysi query;
- qaysi row pozitsiyasi;
- transaction yoki session;
- fetch hajmi
haqida holat saqlashi mumkin.
Client keyingi rowlar guruhini FETCHga o‘xshash amal bilan oladi.
Declare, open, fetch va close
Server-side cursor lifecycle’i odatda:
- declare;
- open;
- fetch;
- kerakli processing;
- close.
Soddalashtirilgan misol:
DECLARE user_cursor CURSOR FOR
SELECT id, email FROM users;
FETCH 100 FROM user_cursor;
Aniq syntax database’ga bog‘liq.
Server-side cursor
Natija serverda saqlanadi yoki query execution holati server tomonidan yuritiladi.
Afzalliklari:
- client memory kam;
- katta natijani batch bilan olish;
- stream processing;
- network paketlarini boshqarish.
Kamchiligi — connection va transaction uzoq vaqt ochiq qolishi mumkin.
Client-side cursor
Driver barcha natijani clientga olib, client memory’da cursor kabi boshqarishi mumkin.
Application API bir xil ko‘rinsa ham haqiqiy streaming bo‘lmasligi mumkin.
Katta queryda driver documentation va memory profiling tekshiriladi.
Fetch size
Har network round-tripda nechta row olinishi fetch size bilan boshqariladi.
Kichik fetch:
- kam memory;
- ko‘p network request.
Katta fetch:
- ko‘p memory;
- kam round-trip.
Row hajmi va processing tezligiga mos qiymat tanlanadi.
Forward-only cursor
Faqat oldinga yuradi.
Bu eng sodda va samarali cursor turi.
Katta export va stream processing uchun qulay.
Oldingi rowga qaytish kerak bo‘lsa application o‘zi saqlashi yoki boshqa cursor turi ishlatiladi.
Scrollable cursor
Oldinga, orqaga yoki aniq pozitsiyaga yurishi mumkin.
Bu qo‘shimcha server yoki client resursini talab qiladi.
Natija o‘zgarganda cursor eski snapshot yoki yangi rowlarni qanday ko‘rishi sensitivity modeliga bog‘liq.
Read-only cursor
Faqat natijani o‘qiydi.
Ko‘p query uchun shu model yetarli.
Updatable cursor rowni joriy pozitsiya orqali o‘zgartirishi mumkin, ammo portability va concurrency murakkabroq.
Cursor sensitivity
Cursor base table o‘zgarishlarini ko‘rishi yoki ko‘rmasligi mumkin.
Tushunchalar:
- insensitive — snapshotga yaqin;
- sensitive — o‘zgarishlarni ko‘rishi mumkin;
- asensitive — implementation tanlaydi.
Aniq xatti-harakat database driver va isolation levelga bog‘liq.
Procedure cursor
Stored procedure query natijasini row-by-row qayta ishlash uchun cursor ochishi mumkin.
Masalan:
har invoice’ni olish
→ hisoblash
→ status yangilash
Bu procedural usul tushunarli bo‘lishi mumkin, ammo katta datasetda sekin.
Set-based SQL
Relational database butun rowlar to‘plami ustida ishlashga optimallashtirilgan.
Cursor loop:
har rowni o‘qi
har rowni update qil
o‘rniga bitta:
UPDATE ...
WHERE ...
statement ko‘pincha tezroq.
Cursor faqat set-based ifoda murakkab yoki external ketma-ket interaction talab qilganda ishlatiladi.
N+1ga o‘xshash xarajat
Cursor ichida har row uchun boshqa query bajarilsa katta round-trip va index lookup soni paydo bo‘ladi.
Masalan, 100 000 row uchun 100 000 qo‘shimcha query.
Join, bulk lookup yoki temporary table bilan querylar birlashtiriladi.
Transaction bilan bog‘liqlik
Server cursor ko‘pincha transaction doirasida mavjud.
Transaction commit qilinsa cursor yopilishi yoki saqlanishi mumkin.
Uzoq cursor:
- eski snapshot;
- vacuumga to‘sqinlik;
- lock;
- connection bandligi
yaratishi mumkin.
Holdable cursor
Ayrim database’larda commitdan keyin ham cursor davom etishi uchun holdable model mavjud.
Database natijani materializatsiya qilishi mumkin.
Bu storage va temp file xarajatini oshiradi.
Cursor va pagination
API pagination cursor — server-side SQL cursorning aynan o‘zi bo‘lishi shart emas.
Ko‘pincha u oxirgi sort keyni encode qiladi:
created_at + id
Keyingi query WHERE orqali davom etadi.
Bu stateless keyset pagination.
Cursor token
Tashqi clientga berilgan cursor:
saqlashi mumkin.
Token imzolanadi yoki server-side holatga reference qiladi.
Base64 tokenni o‘zgartirishdan himoya qilmaydi.
Resource cleanup
Cursor yopilmasa:
- server memory;
- temporary file;
- connection;
- transaction;
- lock
uzoq saqlanishi mumkin.
Driver context manager, finally yoki avtomatik close ishlatadi.
Connection poolga qaytarishdan oldin cursorlar yopiladi.
Failure
Network uzilsa server-side cursor yo‘qolishi mumkin.
Application davom etish uchun:
- oxirgi processed key;
- checkpoint;
- idempotent processing
saqlaydi.
Uzoq exportni boshidan boshlash shart bo‘lmaydi.
Cursor nomi
Server-side cursor session doirasida noyob nomga ega bo‘lishi mumkin.
Bir connection pool orqali parallel ishlaganda cursor nomlari collision qilmasligi kerak.
Driver ko‘pincha bu nomlarni avtomatik boshqaradi.
Batch commit
Millionlab rowni cursor bilan qayta ishlaganda bitta ulkan transaction o‘rniga checkpointli batchlar ishlatilishi mumkin.
Har batch oxirgi processed keyni saqlaydi.
Qayta ishga tushishda ayni keydan davom etish uchun operation idempotent bo‘ladi.
Ordering
Cursor qayta davom ettirilishi uchun query aniq va barqaror ORDER BYga ega bo‘ladi. Tartib unique tie-breaker bilan yakunlanmasa row o‘tkazib yuborilishi mumkin.
Bog‘liq tushunchalar
Database cursor, Result set, Server-side cursor, Fetch size, Forward-only cursor, Stored procedure, Set-based SQL, Keyset pagination, Transaction