ORDER BY, LIMIT, OFFSET — saralash va sahifalash

~15 daq · MySQL · DML — Ma'lumot Boshqarish

Muammodan boshlaylik

Internet do'kon katalogida 50 000 mahsulot. Foydalanuvchiga:

  • "Arzonidan qimmatiga" tartiblash kerak
  • Bir sahifada faqat 20 ta ko'rsatish kerak
  • "Eng ko'p sotilgan 10 ta" bloki kerak

50 000 qatorni ilovaga olib, PHP yoki JavaScript da saralab, 20 tasini kesib olish — juda sekin va xotirani to'ldiradi. Bu ishni baza o'zi bajarishi kerak.


ORDER BY — saralash

SELECT nom, narx FROM mahsulotlar ORDER BY narx;          -- o'sish (ASC — standart)
SELECT nom, narx FROM mahsulotlar ORDER BY narx DESC;     -- kamayish

[!WARNING] ORDER BY siz natija tartibi kafolatlanmagan. Ko'pincha id bo'yicha chiqadi, lekin bu tasodif — indeks, MySQL versiyasi yoki jadvaldagi o'zgarishlarga qarab boshqacha bo'lishi mumkin. Tartib muhim bo'lsa — doim ORDER BY yozing.

Bir nechta ustun bo'yicha

SELECT nom, toifa_id, narx FROM mahsulotlar
ORDER BY toifa_id ASC, narx DESC;

Avval toifa bo'yicha, bir toifa ichida — narx bo'yicha kamayish tartibida.

Hisoblangan qiymat va taxallus bo'yicha

SELECT nom, narx * soni AS qiymat
FROM mahsulotlar
ORDER BY qiymat DESC;

ORDER BY SELECT dan keyin bajariladi, shuning uchun taxalluslar bu yerda ishlaydi (WHERE dan farqli).

NULL lar qayerga tushadi?

MySQL da NULL — eng kichik qiymat: ASC da boshida, DESC da oxirida.

-- Telefoni borlar avval, NULL lar oxirida
SELECT ism, telefon FROM mijozlar ORDER BY telefon IS NULL, telefon;

telefon IS NULL — 0 (bor) yoki 1 (yo'q). 0 lar birinchi.

O'z tartibingiz

SELECT id, holat FROM buyurtmalar
ORDER BY FIELD(holat, 'yangi', 'tolangan', 'yolda', 'yetkazildi', 'bekor');

FIELD() — qiymatning ro'yxatdagi o'rnini qaytaradi.


LIMIT — natijani cheklash

-- Eng qimmat 3 ta mahsulot
SELECT nom, narx FROM mahsulotlar ORDER BY narx DESC LIMIT 3;
+----------------+----------+
| nom            | narx     |
+----------------+----------+
| MacBook Air M3 | 16900000 |
| iPhone 15      | 12500000 |
| Lenovo IdeaPad |  7200000 |
+----------------+----------+

LIMIT + ORDER BY — "top N" savollarining standart yechimi.

-- Eng oxirgi buyurtma
SELECT * FROM buyurtmalar ORDER BY yaratilgan DESC LIMIT 1;

OFFSET — sahifalash

SELECT nom, narx FROM mahsulotlar ORDER BY id LIMIT 20 OFFSET 0;    -- 1-sahifa
SELECT nom, narx FROM mahsulotlar ORDER BY id LIMIT 20 OFFSET 20;   -- 2-sahifa
SELECT nom, narx FROM mahsulotlar ORDER BY id LIMIT 20 OFFSET 40;   -- 3-sahifa

Formula: OFFSET = (sahifa - 1) × sahifa_hajmi.

Qisqa yozuv (eski kodda ko'p):

SELECT ... LIMIT 40, 20;   -- OFFSET 40, LIMIT 20 — tartib teskari, chalkash!

LIMIT 20 OFFSET 40 aniqroq — shuni ishlating.

Jami sahifalar soni

"1 2 3 ... 47" tugmalarini chizish uchun jami son kerak:

SELECT COUNT(*) FROM mahsulotlar WHERE soni > 0;

Ilovada: sahifalar = CEIL(jami / 20).

Saralash noyob bo'lishi kerak

-- ❌ Bir xil narxli mahsulotlar sahifalar orasida "sakrab" yurishi mumkin
SELECT nom, narx FROM mahsulotlar ORDER BY narx LIMIT 20 OFFSET 20;

-- ✅ Noyob ustun qo'shib, tartibni barqaror qiling
SELECT nom, narx FROM mahsulotlar ORDER BY narx, id LIMIT 20 OFFSET 20;

Bir xil narxli 30 ta mahsulot bo'lsa, ularning tartibi har so'rovda boshqacha bo'lishi mumkin — biri 1-sahifada ham, 2-sahifada ham chiqadi, boshqasi umuman ko'rinmaydi.


OFFSET muammosi — chuqur sahifalar

SELECT nom FROM mahsulotlar ORDER BY id LIMIT 20 OFFSET 500000;

Bu so'rov 20 ta qator qaytaradi, lekin MySQL 500 020 ta qatorni o'qib chiqadi va birinchi 500 000 tasini tashlab yuboradi. Sahifa qanchalik uzoq bo'lsa — shunchalik sekin.

Keyset (kursor) sahifalash

"500 000 tasini o'tkazib yubor" o'rniga — "oxirgi ko'rgan id dan keyingilarini ber":

-- 1-sahifa
SELECT id, nom FROM mahsulotlar ORDER BY id LIMIT 20;
-- oxirgi qatorning id si: 20

-- Keyingi sahifa
SELECT id, nom FROM mahsulotlar WHERE id > 20 ORDER BY id LIMIT 20;
-- oxirgi id: 40

SELECT id, nom FROM mahsulotlar WHERE id > 40 ORDER BY id LIMIT 20;

id da indeks bor — MySQL to'g'ridan-to'g'ri kerakli joyga "sakraydi". Millioninchi sahifa ham birinchisidek tez.

Bir nechta ustun bo'yicha saralashda:

-- Narx bo'yicha, oxirgi ko'rilgan: narx = 4800000, id = 2
SELECT id, nom, narx FROM mahsulotlar
WHERE (narx, id) > (4800000, 2)
ORDER BY narx, id
LIMIT 20;
OFFSET Keyset
"47-sahifaga o'tish" ✅ Mumkin ❌ Faqat "keyingi/oldingi"
Chuqur sahifalar tezligi Sekinlashadi Doim tez
Yangi qator qo'shilsa Qatorlar takrorlanishi/yo'qolishi mumkin Barqaror
Qayerda Admin panellar, kichik ro'yxatlar Cheksiz lenta, API, mobil ilovalar

Instagram, Twitter lentalari — keyset sahifalash.


Nima uchun shunday?

Nima uchun saralash va kesishni ilovada emas, bazada qilish kerak?

Chunki baza indekslardan foydalanadi. narx ustunida indeks bo'lsa, ma'lumot u yerda allaqachon tartiblangan holda saqlanadi — ORDER BY narx LIMIT 20 uchun MySQL indeksning boshidan 20 ta yozuvni o'qiydi va tamom. Ilova esa 50 000 qatorni tarmoq orqali olishi, xotiraga joylashi va saralashi kerak. Farq — millisekundlar va soniyalar.


Xulosa

Eslab qoling:

  • ORDER BY ustun [ASC|DESC] — tartib muhim bo'lsa doim yozing
  • Bir nechta ustun: ORDER BY a, b DESC
  • LIMIT n — top N; LIMIT n OFFSET m — sahifalash
  • Sahifalashda saralash noyob bo'lsin: ORDER BY narx, id
  • Chuqur OFFSET sekin — katta ro'yxatlarda keyset: WHERE id > oxirgi ORDER BY id LIMIT n
  • FIELD() — o'z tartibingiz bo'yicha saralash

Keyingi dars

12-dars: UPDATE va DELETE — shartlar bilan, xavfli holatlar