Real loyiha — to'liq DB schema loyihalash va yozish
Maqsad
Kurs davomida o'rganganlarning hammasini bitta loyihada qo'llaymiz: talablardan boshlab — ER diagramma, normallashtirilgan sxema, cheklovlar, indekslar, tranzaksiyalar, VIEW, trigger, hisobot so'rovlari va xavfsizlik.
Loyiha — onlayn kurs platformasi (masalan, shu DevDocs saytining kengaytirilgan versiyasi):
- O'qituvchilar kurs yaratadi; kurs bo'limlar va darslardan iborat
- Talabalar kursni sotib oladi (yoki bepul kursga yoziladi)
- Talaba darslarni ko'radi — progress saqlanadi
- Kursni tugatgach — sertifikat
- Talabalar kursga baho va sharh qoldiradi
- Kurslar toifalarga bo'linadi va teglarga ega
Har bir bosqichni avval o'zingiz bajarib ko'ring, keyin yechim bilan solishtiring.
1-bosqich: Ob'ektlar va munosabatlar
Talablardagi otlar (48-dars): foydalanuvchi (talaba, o'qituvchi), kurs, bo'lim, dars, toifa, teg, yozilish (xarid), to'lov, progress, sertifikat, sharh.
Munosabatlar (har bir juftlik uchun ikki savol, 20-dars):
| Juftlik | Munosabat | Qanday |
|---|---|---|
| O'qituvchi → kurs | One-to-Many | kurslar.oqituvchi_id |
| Toifa → kurs | One-to-Many | kurslar.toifa_id |
| Kurs ↔ teg | Many-to-Many | kurs_teglar |
| Kurs → bo'lim → dars | One-to-Many (ikki daraja) | bolimlar.kurs_id, darslar.bolim_id |
| Talaba ↔ kurs | Many-to-Many, o'z ma'lumoti bilan | yozilishlar |
| Yozilish → to'lov | One-to-Many (qayta urinishlar) | tolovlar.yozilish_id |
| Talaba ↔ dars (progress) | Many-to-Many, o'z ma'lumoti bilan | dars_progress |
| Yozilish → sertifikat | One-to-One | sertifikatlar.yozilish_id UNIQUE |
| Talaba ↔ kurs (sharh) | Bir talaba — bir kursga bitta sharh | sharhlar + UNIQUE |
erDiagram
FOYDALANUVCHILAR ||--o{ KURSLAR : "o'qitadi"
TOIFALAR ||--o{ KURSLAR : ""
KURSLAR ||--o{ KURS_TEGLAR : ""
TEGLAR ||--o{ KURS_TEGLAR : ""
KURSLAR ||--|{ BOLIMLAR : ""
BOLIMLAR ||--|{ DARSLAR : ""
FOYDALANUVCHILAR ||--o{ YOZILISHLAR : "yoziladi"
KURSLAR ||--o{ YOZILISHLAR : ""
YOZILISHLAR ||--o{ TOLOVLAR : ""
YOZILISHLAR ||--o| SERTIFIKATLAR : ""
FOYDALANUVCHILAR ||--o{ DARS_PROGRESS : ""
DARSLAR ||--o{ DARS_PROGRESS : ""
FOYDALANUVCHILAR ||--o{ SHARHLAR : ""
KURSLAR ||--o{ SHARHLAR : ""
2-bosqich: Sxema
CREATE DATABASE akademiya CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
USE akademiya;
-- ===== Foydalanuvchilar =====
CREATE TABLE foydalanuvchilar (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
ism VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL,
parol_hash VARCHAR(255) NOT NULL,
rol ENUM('talaba', 'oqituvchi', 'admin') NOT NULL DEFAULT 'talaba',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
deleted_at DATETIME NULL,
CONSTRAINT uq_foydalanuvchilar_email UNIQUE (email),
CONSTRAINT chk_foydalanuvchilar_ism CHECK (CHAR_LENGTH(TRIM(ism)) >= 2)
);
-- ===== Katalog =====
CREATE TABLE toifalar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
slug VARCHAR(100) NOT NULL,
CONSTRAINT uq_toifalar_slug UNIQUE (slug)
);
CREATE TABLE teglar (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(50) NOT NULL,
CONSTRAINT uq_teglar_nom UNIQUE (nom)
);
CREATE TABLE kurslar (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
oqituvchi_id BIGINT UNSIGNED NOT NULL,
toifa_id INT UNSIGNED NULL,
nom VARCHAR(200) NOT NULL,
slug VARCHAR(220) NOT NULL,
tavsif TEXT NULL,
narx_som INT UNSIGNED NOT NULL DEFAULT 0, -- 0 = bepul
daraja ENUM('boshlangich', 'orta', 'yuqori') NOT NULL DEFAULT 'boshlangich',
holat ENUM('qoralama', 'nashr', 'arxiv') NOT NULL DEFAULT 'qoralama',
-- denormalizatsiya (47-dars): katalog uchun tez o'qish
reyting DECIMAL(2,1) NULL,
sharhlar_soni INT UNSIGNED NOT NULL DEFAULT 0,
talabalar_soni INT UNSIGNED NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT uq_kurslar_slug UNIQUE (slug),
CONSTRAINT fk_kurslar_oqituvchi FOREIGN KEY (oqituvchi_id) REFERENCES foydalanuvchilar(id) ON DELETE RESTRICT,
CONSTRAINT fk_kurslar_toifa FOREIGN KEY (toifa_id) REFERENCES toifalar(id) ON DELETE SET NULL,
INDEX idx_kurslar_katalog (holat, toifa_id, reyting),
FULLTEXT INDEX ft_kurslar (nom, tavsif)
);
CREATE TABLE kurs_teglar (
kurs_id BIGINT UNSIGNED NOT NULL,
teg_id INT UNSIGNED NOT NULL,
PRIMARY KEY (kurs_id, teg_id),
CONSTRAINT fk_kurs_teglar_kurs FOREIGN KEY (kurs_id) REFERENCES kurslar(id) ON DELETE CASCADE,
CONSTRAINT fk_kurs_teglar_teg FOREIGN KEY (teg_id) REFERENCES teglar(id) ON DELETE CASCADE
);
-- ===== Kontent =====
CREATE TABLE bolimlar (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
kurs_id BIGINT UNSIGNED NOT NULL,
nom VARCHAR(200) NOT NULL,
tartib SMALLINT UNSIGNED NOT NULL,
CONSTRAINT uq_bolimlar_tartib UNIQUE (kurs_id, tartib),
CONSTRAINT fk_bolimlar_kurs FOREIGN KEY (kurs_id) REFERENCES kurslar(id) ON DELETE CASCADE
);
CREATE TABLE darslar (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
bolim_id BIGINT UNSIGNED NOT NULL,
nom VARCHAR(200) NOT NULL,
tartib SMALLINT UNSIGNED NOT NULL,
davomiylik_sek INT UNSIGNED NOT NULL DEFAULT 0,
bepul_korish BOOLEAN NOT NULL DEFAULT FALSE,
CONSTRAINT uq_darslar_tartib UNIQUE (bolim_id, tartib),
CONSTRAINT fk_darslar_bolim FOREIGN KEY (bolim_id) REFERENCES bolimlar(id) ON DELETE CASCADE
);
-- ===== Yozilish va to'lov =====
CREATE TABLE yozilishlar (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
talaba_id BIGINT UNSIGNED NOT NULL,
kurs_id BIGINT UNSIGNED NOT NULL,
narx_som INT UNSIGNED NOT NULL, -- sotilgan paytdagi narx (18-dars)
holat ENUM('kutilmoqda', 'faol', 'qaytarildi') NOT NULL DEFAULT 'kutilmoqda',
tugatilgan_at DATETIME NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_yozilishlar UNIQUE (talaba_id, kurs_id),
CONSTRAINT fk_yozilishlar_talaba FOREIGN KEY (talaba_id) REFERENCES foydalanuvchilar(id) ON DELETE RESTRICT,
CONSTRAINT fk_yozilishlar_kurs FOREIGN KEY (kurs_id) REFERENCES kurslar(id) ON DELETE RESTRICT,
INDEX idx_yozilishlar_kurs (kurs_id, holat)
);
CREATE TABLE tolovlar (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
yozilish_id BIGINT UNSIGNED NOT NULL,
summa_som INT UNSIGNED NOT NULL,
provayder ENUM('payme', 'click', 'uzum') NOT NULL,
tashqi_id VARCHAR(100) NULL,
holat ENUM('yaratildi', 'muvaffaqiyatli', 'xato', 'qaytarildi') NOT NULL DEFAULT 'yaratildi',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT uq_tolovlar_tashqi UNIQUE (provayder, tashqi_id),
CONSTRAINT fk_tolovlar_yozilish FOREIGN KEY (yozilish_id) REFERENCES yozilishlar(id) ON DELETE RESTRICT,
INDEX idx_tolovlar_vaqt (holat, created_at)
);
-- ===== O'qish jarayoni =====
CREATE TABLE dars_progress (
talaba_id BIGINT UNSIGNED NOT NULL,
dars_id BIGINT UNSIGNED NOT NULL,
korilgan_sek INT UNSIGNED NOT NULL DEFAULT 0,
tugatildi BOOLEAN NOT NULL DEFAULT FALSE,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (talaba_id, dars_id),
CONSTRAINT fk_progress_talaba FOREIGN KEY (talaba_id) REFERENCES foydalanuvchilar(id) ON DELETE CASCADE,
CONSTRAINT fk_progress_dars FOREIGN KEY (dars_id) REFERENCES darslar(id) ON DELETE CASCADE
);
CREATE TABLE sertifikatlar (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
yozilish_id BIGINT UNSIGNED NOT NULL,
kod CHAR(12) NOT NULL,
berilgan_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_sertifikatlar_yozilish UNIQUE (yozilish_id), -- One-to-One
CONSTRAINT uq_sertifikatlar_kod UNIQUE (kod),
CONSTRAINT fk_sertifikatlar_yozilish FOREIGN KEY (yozilish_id) REFERENCES yozilishlar(id) ON DELETE RESTRICT
);
CREATE TABLE sharhlar (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
talaba_id BIGINT UNSIGNED NOT NULL,
kurs_id BIGINT UNSIGNED NOT NULL,
baho TINYINT UNSIGNED NOT NULL,
matn TEXT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_sharhlar UNIQUE (talaba_id, kurs_id),
CONSTRAINT chk_sharhlar_baho CHECK (baho BETWEEN 1 AND 5),
CONSTRAINT fk_sharhlar_talaba FOREIGN KEY (talaba_id) REFERENCES foydalanuvchilar(id) ON DELETE CASCADE,
CONSTRAINT fk_sharhlar_kurs FOREIGN KEY (kurs_id) REFERENCES kurslar(id) ON DELETE CASCADE,
INDEX idx_sharhlar_kurs (kurs_id, created_at)
);
Qarorlar va sabablari
| Qaror | Sabab | Dars |
|---|---|---|
BIGINT id lar |
Progress va to'lovlar millionlab bo'ladi | 4 |
narx_som yozilishda ham |
Kurs narxi o'zgarsa, eski xaridlar o'zgarmaydi | 18 |
UNIQUE (talaba_id, kurs_id) |
Bitta kursga ikki marta yozilib bo'lmaydi | 6 |
UNIQUE (kurs_id, tartib) |
Bir bo'limda ikkita "3-dars" bo'lmaydi | 6 |
UNIQUE (provayder, tashqi_id) |
To'lov tizimi callback ni ikki marta yuborsa — dublikat yo'q | 9 |
ON DELETE RESTRICT yozilish/to'lovda |
Moliyaviy tarix o'chirilmaydi | 7 |
ON DELETE CASCADE bo'lim/dars/teg |
Ota bo'lmasa — ma'nosiz | 7 |
reyting, talabalar_soni kursda |
Katalog sahifasi har safar millionlab qatorni guruhlamasin | 47 |
idx_kurslar_katalog (holat, toifa_id, reyting) |
"Nashr qilingan, shu toifadagi, reyting bo'yicha" — asosiy so'rov | 31 |
FULLTEXT (nom, tavsif) |
Kurs qidiruvi | 31 |
deleted_at |
Foydalanuvchini soft delete | 12 |
3-bosqich: Biznes jarayonlari
Kursga yozilish va to'lov — tranzaksiya
To'lov tizimidan muvaffaqiyatli callback keldi:
DELIMITER //
CREATE PROCEDURE tolov_tasdiqlandi(IN p_provayder VARCHAR(10), IN p_tashqi_id VARCHAR(100))
BEGIN
DECLARE v_tolov_id, v_yozilish_id, v_kurs_id BIGINT UNSIGNED;
DECLARE v_holat VARCHAR(20);
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END;
START TRANSACTION;
SELECT t.id, t.yozilish_id, t.holat INTO v_tolov_id, v_yozilish_id, v_holat
FROM tolovlar t
WHERE t.provayder = p_provayder AND t.tashqi_id = p_tashqi_id
FOR UPDATE; -- 38-dars
IF v_tolov_id IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'To''lov topilmadi';
END IF;
-- Idempotentlik: callback ikkinchi marta kelsa — hech narsa qilmaymiz
IF v_holat <> 'muvaffaqiyatli' THEN
UPDATE tolovlar SET holat = 'muvaffaqiyatli' WHERE id = v_tolov_id;
UPDATE yozilishlar SET holat = 'faol' WHERE id = v_yozilish_id;
SELECT kurs_id INTO v_kurs_id FROM yozilishlar WHERE id = v_yozilish_id;
UPDATE kurslar SET talabalar_soni = talabalar_soni + 1 WHERE id = v_kurs_id;
END IF;
COMMIT;
END //
DELIMITER ;
Idempotentlik — to'lov tizimlari callback ni tarmoq xatolarida bir necha marta yuboradi. Ikkinchi chaqiruv birinchisi bilan bir xil natija berishi kerak — talabalar soni ikki marta oshmasligi kerak.
Progress — upsert
Talaba videoni ko'ryapti, har 30 soniyada:
INSERT INTO dars_progress (talaba_id, dars_id, korilgan_sek, tugatildi)
VALUES (?, ?, ?, ?)
AS yangi
ON DUPLICATE KEY UPDATE
korilgan_sek = GREATEST(dars_progress.korilgan_sek, yangi.korilgan_sek),
tugatildi = dars_progress.tugatildi OR yangi.tugatildi;
GREATEST — talaba videoni orqaga qaytarsa, progress kamaymaydi (26-dars). OR — bir marta tugatilgan dars "tugatilmagan" ga qaytmaydi.
Reyting — trigger
DELIMITER //
CREATE TRIGGER trg_sharh_qoshildi AFTER INSERT ON sharhlar
FOR EACH ROW
BEGIN
UPDATE kurslar k
SET k.sharhlar_soni = k.sharhlar_soni + 1,
k.reyting = (SELECT ROUND(AVG(baho), 1) FROM sharhlar WHERE kurs_id = NEW.kurs_id)
WHERE k.id = NEW.kurs_id;
END //
DELIMITER ;
Va har kecha — Event bilan to'liq qayta hisoblash, to'plangan xatolarni tuzatish uchun (44, 47-darslar).
4-bosqich: So'rovlar
Katalog — indeks bilan
SELECT k.id, k.nom, k.slug, k.narx_som, k.reyting, k.talabalar_soni, f.ism AS oqituvchi
FROM kurslar k
JOIN foydalanuvchilar f ON f.id = k.oqituvchi_id
WHERE k.holat = 'nashr' AND k.toifa_id = ?
ORDER BY k.reyting DESC
LIMIT 20;
EXPLAIN: key: idx_kurslar_katalog, Extra da Using filesort yo'q (32-dars).
Talabaning kurs bo'yicha progressi
SELECT
k.nom,
COUNT(d.id) AS jami_darslar,
COUNT(CASE WHEN p.tugatildi THEN 1 END) AS tugatilgan,
ROUND(COUNT(CASE WHEN p.tugatildi THEN 1 END) * 100 / NULLIF(COUNT(d.id), 0)) AS foiz
FROM yozilishlar y
JOIN kurslar k ON k.id = y.kurs_id
JOIN bolimlar b ON b.kurs_id = k.id
JOIN darslar d ON d.bolim_id = b.id
LEFT JOIN dars_progress p ON p.dars_id = d.id AND p.talaba_id = y.talaba_id
WHERE y.talaba_id = ? AND y.holat = 'faol'
GROUP BY k.id, k.nom;
LEFT JOIN va shart ON da — ko'rilmagan darslar ham sanaladi (16-dars). NULLIF — darssiz kursda nolga bo'lish yo'q (28-dars).
"Davom ettirish" — keyingi ko'rilmagan dars
SELECT d.id, d.nom, b.nom AS bolim
FROM darslar d
JOIN bolimlar b ON b.id = d.bolim_id
WHERE b.kurs_id = ?
AND NOT EXISTS (
SELECT 1 FROM dars_progress p
WHERE p.dars_id = d.id AND p.talaba_id = ? AND p.tugatildi
)
ORDER BY b.tartib, d.tartib
LIMIT 1;
O'qituvchi uchun oylik daromad — window funksiyalar bilan
WITH oylik AS (
SELECT
DATE_FORMAT(t.created_at, '%Y-%m') AS oy,
SUM(t.summa_som) AS daromad
FROM tolovlar t
JOIN yozilishlar y ON y.id = t.yozilish_id
JOIN kurslar k ON k.id = y.kurs_id
WHERE k.oqituvchi_id = ? AND t.holat = 'muvaffaqiyatli'
GROUP BY oy
)
SELECT
oy,
daromad,
SUM(daromad) OVER (ORDER BY oy) AS yil_boshidan,
ROUND((daromad - LAG(daromad) OVER (ORDER BY oy)) * 100
/ LAG(daromad) OVER (ORDER BY oy), 1) AS osish_foiz
FROM oylik
ORDER BY oy;
(23, 29-darslar.)
Har bir toifadagi top-3 kurs
WITH t AS (
SELECT k.*, ROW_NUMBER() OVER (PARTITION BY toifa_id ORDER BY talabalar_soni DESC) AS rn
FROM kurslar k
WHERE holat = 'nashr'
)
SELECT toifa_id, nom, talabalar_soni FROM t WHERE rn <= 3;
Kurs qidiruvi
SELECT id, nom, MATCH(nom, tavsif) AGAINST (? IN NATURAL LANGUAGE MODE) AS muvofiqlik
FROM kurslar
WHERE holat = 'nashr' AND MATCH(nom, tavsif) AGAINST (? IN NATURAL LANGUAGE MODE)
ORDER BY muvofiqlik DESC
LIMIT 20;
5-bosqich: Xavfsizlik va ekspluatatsiya
-- Ilova foydalanuvchisi (50-dars)
CREATE USER 'akademiya_app'@'10.0.0.%' IDENTIFIED BY '...';
GRANT SELECT, INSERT, UPDATE, DELETE ON akademiya.* TO 'akademiya_app'@'10.0.0.%';
GRANT EXECUTE ON PROCEDURE akademiya.tolov_tasdiqlandi TO 'akademiya_app'@'10.0.0.%';
-- Analitika — shaxsiy ma'lumotsiz VIEW (40-dars)
CREATE VIEW analitika_yozilishlar AS
SELECT y.id, y.kurs_id, y.narx_som, y.holat, y.created_at, k.toifa_id
FROM yozilishlar y JOIN kurslar k ON k.id = y.kurs_id;
CREATE USER 'analitik'@'%' IDENTIFIED BY '...';
GRANT SELECT ON akademiya.analitika_yozilishlar TO 'analitik'@'%';
Tekshiruv ro'yxati:
| ☐ | Ilovadagi barcha so'rovlar — prepared statements (51) |
| ☐ | Parollar — password_hash / bcrypt |
| ☐ | Kunlik backup --routines --triggers --events bilan, oylik tiklash testi (52) |
| ☐ | Slow query log yoqilgan, long_query_time = 1 (33) |
| ☐ | innodb_buffer_pool_size sozlangan (34) |
| ☐ | Asosiy so'rovlar EXPLAIN bilan tekshirilgan (32) |
| ☐ | Ilovada connection pool, release() finally da (54) |
| ☐ | Migratsiyalar Git da, production da sync yo'q (57-59) |
| ☐ | Sxema README.md da Mermaid diagramma bilan (48) |
Mustaqil vazifalar
- ⭐ Seed ma'lumotlar: 5 ta toifa, 20 ta kurs, 200 ta dars, 1000 ta talaba va ularning yozilishlari. Rekursiv CTE bilan ketma-ketlik yasang (23-dars)
- ⭐⭐ Promokodlar:
promokodlarjadvali (foiz yoki summa, muddat, ishlatish chegarasi). Yozilishda promokod qo'llash — poygasiz (38-dars,FOR UPDATE) - ⭐⭐ Sertifikat avtomatik: kursdagi barcha darslar tugatilganda sertifikat berish — trigger yoki procedure? Qarorni asoslang
- ⭐⭐ Partitioning:
dars_progresstarixini oylar bo'yicha partition qilish kerakmi? Nima uchun? (35-dars) - ⭐⭐⭐ ORM ga ko'chirish: sxemani Prisma yoki TypeORM ga o'tkazing (58-59),
tolov_tasdiqlandini ilova kodidagi tranzaksiyaga aylantiring va ikkala yondashuvni solishtiring - ⭐⭐⭐ Yuklama testi: 1 million
dars_progressqatori bilan "talabaning progressi" so'roviniEXPLAIN ANALYZEqiling va tezlashtiring
Tabriklaymiz! 🎉
Siz MySQL kursini tugatdingiz. Endi siz:
- Relational model va SQL ning barcha asosiy buyruqlarini bilasiz
- JOIN, subquery, CTE, window funksiyalar bilan murakkab savollarga javob yozasiz
- Indekslarni tushunasiz va so'rovlarni
EXPLAINbilan optimizatsiya qilasiz - Tranzaksiyalar, isolation va qulflar bilan to'g'ri ishlaysiz
- Normallashtirilgan sxema loyihalaysiz va qachon denormallashtirishni bilasiz
- Bazani himoyalaysiz, backup olasiz va replication ni tushunasiz
- MySQL ni Node.js va ORM lar bilan ishlatasiz
Keyingi qadamlar:
- Saytdagi PostgreSQL kursi — boshqa kuchli relational baza: JSONB, kengaytmalar, MVCC ning boshqacha amalga oshirilishi
- PHP kursining PDO darslari yoki Node.js / NestJS kurslari — MySQL ni haqiqiy ilovada
- O'z loyihangiz — real ma'lumot, real yuklama, real muammolar. Eng yaxshi o'qituvchi aynan shu
Ma'lumot — har qanday ilovaning yuragi. Endi siz uni to'g'ri saqlashni bilasiz.