3-bo‘lim
Kalitlar
Birlamchi, nomzod va kompozit kalitlar, tabiiy va sun'iy kalit tanlovi, AUTO_INCREMENT va UUID.
Ushbu bo‘lim mundarijasi
Kalit - qatorni bir ma'noli aniqlaydigan ustun yoki ustunlar to'plami. Uni to'g'ri tanlash - loyihalashning eng muhim qarorlaridan.
Kalit turlari #
Nomzod kalitlarni topish #
CREATE TABLE xodimlar (
id INT PRIMARY KEY AUTO_INCREMENT,
pasport CHAR(9) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL UNIQUE,
ism VARCHAR(100) NOT NULL,
familiya VARCHAR(100) NOT NULL,
bolim VARCHAR(50) NOT NULL,
ish_boshlagan DATE NOT NULL
);
INSERT INTO xodimlar (pasport, email, ism, familiya, bolim, ish_boshlagan) VALUES
('AA1234567', '[email protected]', 'Husanboy', 'Qodirov', 'IT', '2024-01-15'),
('AB7654321', '[email protected]', 'Malika', 'Yusupova', 'Hisobot', '2024-03-01'),
('AC1112223', '[email protected]', 'Nodira', 'Karimova', 'IT', '2025-06-10');
-- Uchta nomzod kalit bor: id, pasport, email
SELECT CONSTRAINT_NAME AS cheklov, COLUMN_NAME AS ustun
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'xodimlar'
ORDER BY BINARY CONSTRAINT_NAME;
+---------+---------+
| cheklov | ustun |
+---------+---------+
| PRIMARY | id |
| email | email |
| pasport | pasport |
+---------+---------+
Ustun (yoki ustunlar to'plami) nomzod kalit bo'lishi uchun ikki shart kerak:
- Yagonalik - hech ikki qatorda takrorlanmaydi;
- Qisqarmaslik - undan istalgan ustunni olib tashlasangiz, yagonalik yo'qoladi.
Misol: (ism, familiya) yagona bo'lishi mumkin, lekin bu
biznes kafolati emas - ikkita "Husanboy Qodirov" bo'lishi
mumkin.
Nomzod kalit haqiqiy dunyodagi qoidaga tayanishi kerak, sizning ma'lumotingizdagi tasodifga emas:
| Ustun | Nomzod kalitmi | Nima uchun |
|---|---|---|
pasport | Ha | Davlat kafolatlaydi |
email | Ha | Tizim kafolatlaydi |
(ism, familiya) | Yo'q | Takrorlanishi mumkin |
telefon | Ehtimol | Oilaviy raqam bo'lishi mumkin |
"Hozircha takrorlanmayapti" - kalit tanlash uchun yetarli asos emas.
Tabiiy va sun'iy kalit #
-- Tabiiy kalit: haqiqiy dunyodan keladi (pasport)
SELECT pasport, ism FROM xodimlar WHERE pasport = 'AA1234567';
+-----------+----------+
| pasport | ism |
+-----------+----------+
| AA1234567 | Husanboy |
+-----------+----------+
-- Sun'iy kalit: tizim o'zi yaratadi, ma'nosi yo'q
SELECT id, ism FROM xodimlar ORDER BY id;
+----+----------+
| id | ism |
+----+----------+
| 1 | Husanboy |
| 2 | Malika |
| 3 | Nodira |
+----+----------+
Aytaylik pasport ni birlamchi kalit qilib oldingiz. Undan
o'nlab jadval FOREIGN KEY orqali foydalanadi.
Endi xodim pasportini almashtirdi (muddati tugadi, familiya o'zgardi). Nima qilish kerak?
- Barcha bog'liq jadvallardagi qiymatni yangilash;
ON UPDATE CASCADEyordam beradi, lekin million qatorda bu soatlab ishlaydi va jadvallarni qulflaydi;- Tarixiy hisobotlar eski qiymatga ishora qilib qolgan bo'lishi mumkin.
Sun'iy kalitda esa bu muammo umuman yo'q - id hech
qachon o'zgarmaydi, pasport esa oddiy ustun bo'lib qoladi:
UPDATE xodimlar SET pasport = 'AD9998887' WHERE id = 1;
Bitta qator, hech qanday zanjirli ta'sir.
Amaliy tavsiya: birlamchi kalit uchun sun'iy kalit oling,
tabiiy kalitni esa UNIQUE cheklov sifatida saqlang. Shunda
ikkala foydani ham olasiz.
AUTO_INCREMENT xatti-harakati #
INSERT INTO xodimlar (pasport, email, ism, familiya, bolim, ish_boshlagan)
VALUES ('AD5556667', '[email protected]', 'Aziza', 'Tosheva', 'IT', '2026-01-05');
SELECT LAST_INSERT_ID() AS oxirgi_id;
+-----------+
| oxirgi_id |
+-----------+
| 4 |
+-----------+
-- To'rtinchi xodimni qo'shamiz, keyin o'chiramiz
INSERT INTO xodimlar (pasport, email, ism, familiya, bolim, ish_boshlagan)
VALUES ('AD5556667', '[email protected]', 'Aziza', 'Tosheva', 'IT', '2026-01-05');
DELETE FROM xodimlar WHERE id = 4;
-- Yangi qator 4 ni EMAS, 5 ni oladi
INSERT INTO xodimlar (pasport, email, ism, familiya, bolim, ish_boshlagan)
VALUES ('AE1112223', '[email protected]', 'Kamola', 'Rasulova', 'Hisobot', '2026-02-01');
SELECT id, ism FROM xodimlar ORDER BY id;
+----+----------+
| id | ism |
+----+----------+
| 1 | Husanboy |
| 2 | Malika |
| 3 | Nodira |
| 5 | Kamola |
+----+----------+
id da bo'shliq bo'lishi normal4 raqami yo'qolib qoldi va bu muammo emas.
AUTO_INCREMENT qiymatlari ketma-ket bo'lishini kafolatlamaydi.
Bo'shliq quyidagi hollarda paydo bo'ladi:
| Sabab | Izoh |
|---|---|
| Qator o'chirildi | Raqam qaytarilmaydi |
| Tranzaksiya bekor qilindi | Raqam allaqachon "band" |
INSERT xato berdi | Raqam sarflandi |
| Server qayta yuklandi | Ba'zi versiyalarda sakrash |
Hech qachon id ni "qatorlar soni" yoki "tartib raqami"
sifatida ishlatmang:
-- NOTO'G'RI - bo'shliq bo'lsa xato natija
SELECT MAX(id) AS xodimlar_soni FROM xodimlar;
-- TO'G'RI
SELECT COUNT(*) AS xodimlar_soni FROM xodimlar;
Foydalanuvchiga ko'rsatiladigan tartib raqami kerak bo'lsa,
uni alohida ustunda saqlang yoki ROW_NUMBER() bilan
hisoblang.
Kompozit kalit #
CREATE TABLE dars_jadvali (
sinf_id INT NOT NULL,
kun TINYINT NOT NULL,
juftlik TINYINT NOT NULL,
fan VARCHAR(50) NOT NULL,
PRIMARY KEY (sinf_id, kun, juftlik)
);
INSERT INTO dars_jadvali VALUES
(1, 1, 1, 'Matematika'),
(1, 1, 2, 'Fizika'),
(2, 1, 1, 'Ingliz tili');
SELECT sinf_id, kun, juftlik, fan FROM dars_jadvali ORDER BY sinf_id, kun, juftlik;
+---------+-----+---------+-------------+
| sinf_id | kun | juftlik | fan |
+---------+-----+---------+-------------+
| 1 | 1 | 1 | Matematika |
| 1 | 1 | 2 | Fizika |
| 2 | 1 | 1 | Ingliz tili |
+---------+-----+---------+-------------+
-- Bir sinfda bir vaqtda ikki dars bo'la olmaydi
INSERT INTO dars_jadvali VALUES (1, 1, 1, 'Tarix');
ERROR 1062 (23000): Duplicate entry '1-1-1' for key 'PRIMARY'
Kompozit birlamchi kalit bog'lovchi jadvallarda va tabiiy ravishda ko'p ustunli ma'lumotda o'rinli:
PRIMARY KEY (buyurtma_id, mahsulot_id) -- bog'lovchi jadval
PRIMARY KEY (sinf_id, kun, juftlik) -- jadval kataklari
Afzalligi - biznes qoidasi sxemada mustahkamlangan. "Bir sinfda bir vaqtda bitta dars" qoidasini kod buzolmaydi.
Kamchiliklari:
| Muammo | Izoh |
|---|---|
| Uchinchi jadvaldan murojaat | Uchala ustunni ko'chirish kerak |
| Indeks kattaligi | Ko'proq joy egallaydi |
| ORM lar bilan ishlash | Ba'zilari qo'llab-quvvatlamaydi |
| So'rovlar uzunroq | ON a.x=b.x AND a.y=b.y AND ... |
Agar shu jadvalga boshqa jadval murojaat qiladigan bo'lsa,
sun'iy id qo'shib, kompozitni UNIQUE ga aylantiring:
id INT PRIMARY KEY AUTO_INCREMENT,
UNIQUE (sinf_id, kun, juftlik)
Bu ikkala foydani beradi: qisqa murojaat va mustahkamlangan qoida.
UUID - taqsimlangan tizimlar uchun #
CREATE TABLE hujjatlar (
id BINARY(16) PRIMARY KEY,
sarlavha VARCHAR(200) NOT NULL
);
-- UNHEX bilan 36 belgilik matnni 16 baytga siqamiz
INSERT INTO hujjatlar VALUES
(UNHEX(REPLACE('11111111-2222-3333-4444-555555555555', '-', '')), 'Shartnoma'),
(UNHEX(REPLACE('66666666-7777-8888-9999-000000000000', '-', '')), 'Hisobot');
SELECT LOWER(HEX(id)) AS saqlangan, sarlavha, LENGTH(id) AS bayt
FROM hujjatlar
ORDER BY sarlavha;
+----------------------------------+-----------+------+
| saqlangan | sarlavha | bayt |
+----------------------------------+-----------+------+
| 66666666777788889999000000000000 | Hisobot | 16 |
| 11111111222233334444555555555555 | Shartnoma | 16 |
+----------------------------------+-----------+------+
CHAR(36) da saqlamangUUID ni matn sifatida saqlash keng tarqalgan, lekin qimmat xato:
| Saqlash usuli | Hajmi | Izoh |
|---|---|---|
CHAR(36) | 36 bayt | O'qish oson, lekin isrof |
BINARY(16) | 16 bayt | Ikki barobardan ko'p tejash |
Birlamchi kalit har bir ikkilamchi indeksga ham kiritiladi, shuning uchun farq ko'payadi. Million qatorli, 5 ta indeksli jadvalda bu 100 MB dan ortiq farq beradi.
Ikkinchi muammo tasodifiylik: klassik UUID v4 butunlay
tasodifiy. InnoDB esa qatorlarni birlamchi kalit tartibida
saqlaydi - tasodifiy kalit har INSERT da indeksni o'rtasidan
buzadi (page split).
Yechim - vaqt bo'yicha tartiblangan UUID:
- UUID v7 - zamonaviy standart, vaqt prefiksli;
- MySQL 8 va MariaDB 10.10+ da
UUID_TO_BIN(uuid, 1)- bo'laklarni almashtirib, vaqt qismini boshiga chiqaradi.
Eski versiyalarda yuqoridagi UNHEX(REPLACE(...)) usuli ishlaydi -
u hamma joyda mavjud.
Ehtiyoj bo'lmasa esa oddiy AUTO_INCREMENT eng tez va
eng ixchamdir. UUID faqat quyidagi hollarda kerak:
- Bir necha server mustaqil
idyaratsa; idni URL da ko'rsatib, sonini yashirish kerak bo'lsa;- Ma'lumot bazalar orasida birlashtirilsa.
Kalit tanlash qoidalari #
| Qoida | Sabab |
|---|---|
| Har jadvalda birlamchi kalit bo'lsin | Qatorni aniqlash, replikatsiya |
| Sun'iy kalitni birlamchi qiling | O'zgarmaydi |
Tabiiy kalitni UNIQUE qiling | Qoida saqlanadi |
| Kalit qisqa bo'lsin | Indekslarga ko'chiriladi |
| Kalitni o'zgartirmang | Zanjirli yangilanish qimmat |
| Maxfiy ma'lumotni kalit qilmang | Pasport URL da ko'rinmasin |
id ni tartib raqami deb bilmang | Bo'shliqlar bor |
Birlamchi kalitsiz jadval InnoDB da baribir yashirin kalit oladi, lekin siz undan foydalana olmaysiz - va replikatsiya sekinlashadi.
- Jadvaldagi barcha nomzod kalitlarni toping.
(ism, familiya)nima uchun kalit bo'la olmasligini ayting.- Tabiiy va sun'iy kalitning uchtadan afzalligini sanang.
- Tabiiy kalit o'zgarganda nima bo'lishini tushuntiring.
- Qator o'chirib,
idda bo'shliq hosil qiling. MAX(id)vaCOUNT(*)farqini ko'rsating.- Uch ustunli kompozit kalit yarating.
- Kompozit kalitni buzuvchi
INSERTyozing. - UUID ni
BINARY(16)da saqlang. - UUID v4 ning InnoDB dagi muammosini tushuntiring.
Xulosa #
- Super kalit → nomzod kalit → birlamchi kalit.
- Nomzod kalit yagona va qisqarmas bo'lishi kerak.
- "Hozircha takrorlanmayapti" - kalit uchun asos emas.
- Sun'iy kalitni birlamchi, tabiiyni
UNIQUEqiling. - Tabiiy kalit o'zgarsa zanjirli yangilanish kerak bo'ladi.
AUTO_INCREMENTda bo'shliq normal -idtartib raqami emas.- Qatorlar sonini
COUNT(*)bilan oling,MAX(id)bilan emas. - Kompozit kalit bog'lovchi jadvallarda o'rinli.
- Boshqa jadval murojaat qilsa - sun'iy
idqo'shing. - UUID ni
BINARY(16)da saqlang,CHAR(36)da emas. - Tasodifiy UUID InnoDB indeksini buzadi - v7 ishlating.
Keyingi bo'limda bir-ga-ko'p bog'lanishni batafsil ko'ramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.