One-to-One munosabat — qachon kerak
Muammodan boshlaylik
foydalanuvchilar jadvali o'sib ketdi:
id | email | parol_hash | ism | avatar | bio | tugilgan_kun | manzil | telegram |
| instagram | sayt | ish_joyi | lavozim | til | mavzu | xabar_sozlamalari | ...
40 ta ustun. Login paytida faqat email va parol_hash kerak, lekin har bir qator diskda katta joy egallaydi va MySQL ko'proq o'qiydi. Ko'pchilik foydalanuvchi profilni to'ldirmagan — 30 ta ustun NULL. Va har bir ustun qo'shilishi bilan jadval yanada og'irlashadi.
Bitta foydalanuvchiga — bitta profil. Bu ma'lumotni alohida jadvalga ajratsa bo'ladimi? Ha — bu One-to-One munosabat.
One-to-One nima?
Bir jadvaldagi bitta qatorga ikkinchi jadvalda ko'pi bilan bitta qator mos keladi.
CREATE TABLE foydalanuvchilar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
parol_hash VARCHAR(255) NOT NULL,
yaratilgan DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE profillar (
foydalanuvchi_id INT UNSIGNED PRIMARY KEY, -- ← ham PK, ham FK
ism VARCHAR(100),
avatar VARCHAR(255),
bio TEXT,
tugilgan_kun DATE,
telegram VARCHAR(50),
FOREIGN KEY (foydalanuvchi_id) REFERENCES foydalanuvchilar(id) ON DELETE CASCADE
);
Asosiy hiyla: foydalanuvchi_id — ham primary key, ham foreign key. Primary key takrorlanmaydi — demak bitta foydalanuvchiga ikkinchi profil yaratib bo'lmaydi. One-to-One ni baza o'zi kafolatlaydi.
Muqobil usul — alohida id + UNIQUE foreign key:
CREATE TABLE profillar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
foydalanuvchi_id INT UNSIGNED NOT NULL UNIQUE, -- UNIQUE — bitta foydalanuvchiga bitta
...
);
Ikkalasi ham to'g'ri. Birinchisi ixchamroq.
[!INFO]
UNIQUEsiz bu oddiy One-to-Many bo'lib qoladi — bitta foydalanuvchiga ko'p profil. One-to-One va One-to-Many o'rtasidagi yagona farq — shuUNIQUE(yoki PRIMARY KEY).
So'rovlar
-- Login — faqat kichik jadval
SELECT id, parol_hash FROM foydalanuvchilar WHERE email = 'ali@mail.uz';
-- Profil sahifasi — ikkalasi birga
SELECT f.email, p.ism, p.avatar, p.bio
FROM foydalanuvchilar f
LEFT JOIN profillar p ON p.foydalanuvchi_id = f.id
WHERE f.id = 42;
LEFT JOIN — profilini hali to'ldirmagan foydalanuvchi ham ko'rinsin.
Profil yaratish yoki yangilash — upsert (9-dars):
INSERT INTO profillar (foydalanuvchi_id, ism, bio)
VALUES (42, 'Ali', 'PHP dasturchi')
AS yangi
ON DUPLICATE KEY UPDATE ism = yangi.ism, bio = yangi.bio;
Qachon One-to-One kerak?
One-to-One kam ishlatiladi. Ko'pincha shunchaki bitta jadval to'g'ri tanlov. Ajratishga faqat aniq sabab bo'lsa:
1. Ixtiyoriy ma'lumot
Faqat ba'zi qatorlarda bo'ladigan ko'p ustunlar:
-- Faqat yuridik shaxs mijozlar uchun
CREATE TABLE mijoz_kompaniyalari (
mijoz_id INT UNSIGNED PRIMARY KEY,
kompaniya VARCHAR(200) NOT NULL,
inn CHAR(9) NOT NULL UNIQUE,
bank_hisobi VARCHAR(30),
direktor VARCHAR(100),
FOREIGN KEY (mijoz_id) REFERENCES mijozlar(id) ON DELETE CASCADE
);
Mijozlarning 95% i jismoniy shaxs. Bu 5 ta ustunni asosiy jadvalda saqlasak — 95% qatorda bo'sh. Alohida jadvalda esa ular NOT NULL bo'la oladi: kompaniya yozuvi bor bo'lsa — INN albatta bor.
2. Katta, kam o'qiladigan ma'lumot
CREATE TABLE maqola_matnlari (
maqola_id INT UNSIGNED PRIMARY KEY,
matn MEDIUMTEXT NOT NULL,
FOREIGN KEY (maqola_id) REFERENCES maqolalar(id) ON DELETE CASCADE
);
Maqolalar ro'yxatida faqat sarlavha va sana kerak — 100 KB lik matnni har safar o'qish shart emas. Asosiy jadval kichik va tez qoladi.
3. Xavfsizlik va huquqlar
CREATE TABLE foydalanuvchi_maxfiy (
foydalanuvchi_id INT UNSIGNED PRIMARY KEY,
pasport_seriya VARCHAR(20),
pinfl CHAR(14),
FOREIGN KEY (foydalanuvchi_id) REFERENCES foydalanuvchilar(id)
);
Maxfiy ma'lumotni alohida jadvalga qo'yib, unga faqat ma'lum MySQL foydalanuvchilariga ruxsat berish mumkin (50-dars). Analitika jamoasi asosiy jadvalni ko'radi, pasport ma'lumotlarini — yo'q.
4. Turli jamoalar / modullar
foydalanuvchilar — autentifikatsiya moduli, mijoz_sodiqlik (ballar, daraja) — marketing moduli. Har bir modul o'z jadvaliga egalik qiladi.
Qachon kerak emas
- Ustunlar ko'p, lekin hammasi deyarli har doim to'ldiriladi va birga o'qiladi → bitta jadval
- "Tartibli ko'rinsin" deb ajratish → keraksiz JOIN, murakkabroq kod
- MySQL bir qatorda 4000 dan ortiq ustunni ko'taradi — 40 ta ustun o'z-o'zidan muammo emas
Qoida: default — bitta jadval. One-to-One — yuqoridagi sabablardan biri haqiqatan bo'lganda.
Uchta munosabat — xulosa
| Munosabat | Misol | Qanday yasaladi |
|---|---|---|
| One-to-One | Foydalanuvchi ↔ profil | FK bola jadvalda + UNIQUE (yoki FK = PK) |
| One-to-Many | Mijoz → buyurtmalar | FK "ko'p" tomonda |
| Many-to-Many | Mahsulot ↔ teglar | Oraliq jadval, ikki FK, composite PK |
Munosabatni aniqlash uchun ikki savol bering:
- "Bitta A nechta B ga ega bo'lishi mumkin?"
- "Bitta B nechta A ga ega bo'lishi mumkin?"
| 1-javob | 2-javob | Munosabat |
|---|---|---|
| Bitta | Bitta | One-to-One |
| Ko'p | Bitta | One-to-Many |
| Ko'p | Ko'p | Many-to-Many |
Nima uchun shunday?
Nima uchun One-to-One da bola jadvalning primary key ini otaning id si qilish tavsiya etiladi?
Ikki sabab. Birinchidan, kafolat: primary key bo'lgani uchun takrorlanmaydi — kodda xato bo'lsa ham bitta foydalanuvchiga ikkita profil yaratib bo'lmaydi. Ikkinchidan, samaradorlik: InnoDB jadvallarni primary key bo'yicha tartiblab saqlaydi (clustered index, 30-dars). Profilni foydalanuvchi_id bo'yicha qidirish — to'g'ridan-to'g'ri primary key qidiruvi, eng tez yo'l. Alohida id va alohida UNIQUE indeks esa ikki qadamli qidiruv bo'lardi.
Xulosa
Eslab qoling:
- One-to-One — bitta qatorga ko'pi bilan bitta qator
- Yasash: bola jadvalda
ota_idham PRIMARY KEY, ham FOREIGN KEY UNIQUE/ PK siz bu One-to-Many bo'lib qoladi- Qachon: ixtiyoriy ustunlar guruhi, katta kam o'qiladigan ma'lumot, maxfiy ma'lumot
- Default — bitta jadval; aniq sababsiz ajratmang
- O'qishda —
LEFT JOIN, yozishda — upsert
Keyingi dars
21-dars: Subquery — WHERE, FROM, SELECT ichida