10-bo‘lim
Ma'lumot turlarini tanlash
Butun va kasr sonlar, matn turlari, sana va vaqt, ENUM va mantiqiy qiymatlar, pul bilan ishlash va tur tanlash narxi.
Ushbu bo‘lim mundarijasi
Tur tanlash - "shunchaki VARCHAR(255) qo'yaman" degan qaror emas.
U to'g'rilikni, tezlikni va disk hajmini belgilaydi.
Butun sonlar #
CREATE TABLE butun_turlar (
kichik TINYINT,
qisqa SMALLINT,
orta MEDIUMINT,
oddiy INT,
katta BIGINT,
ishorasiz TINYINT UNSIGNED
);
SELECT COLUMN_NAME AS ustun, COLUMN_TYPE AS turi
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'butun_turlar'
ORDER BY ORDINAL_POSITION;
+-----------+---------------------+
| ustun | turi |
+-----------+---------------------+
| kichik | tinyint(4) |
| qisqa | smallint(6) |
| orta | mediumint(9) |
| oddiy | int(11) |
| katta | bigint(20) |
| ishorasiz | tinyint(3) unsigned |
+-----------+---------------------+
| Tur | Baytlar | Ishorali chegara |
|---|---|---|
TINYINT | 1 | -128 ... 127 |
SMALLINT | 2 | -32 768 ... 32 767 |
MEDIUMINT | 3 | ±8.3 million |
INT | 4 | ±2.1 milliard |
BIGINT | 8 | ±9.2 kvintillion |
-- Chegaradan chiqishga urinish
INSERT INTO butun_turlar (kichik) VALUES (200);
ERROR 1264 (22003): Out of range value for column 'kichik' at row 1
-- UNSIGNED bilan chegara ikki barobar kengayadi
INSERT INTO butun_turlar (ishorasiz) VALUES (200);
SELECT ishorasiz FROM butun_turlar WHERE ishorasiz IS NOT NULL;
+-----------+
| ishorasiz |
+-----------+
| 200 |
+-----------+
INT(11) dagi 11 - kenglik emasKo'p dasturchi INT(11) ni "11 xonali son" deb o'ylaydi. Bu
noto'g'ri.
Qavsdagi son - faqat ko'rsatish kengligi (display width) va
u ZEROFILL bilan birga ishlatilganda ma'noga ega:
son INT(5) ZEROFILL -- 42 -> "00042"
ZEROFILL bo'lmasa, INT(1) va INT(11) bir xil - ikkalasi
ham 4 bayt va bir xil chegaraga ega.
MySQL 8.0.17 dan boshlab bu xususiyat eskirgan deb belgilangan.
Chegarani belgilash uchun turni tanlang:
yosh TINYINT UNSIGNED -- 0-255, yetarli
ball SMALLINT -- -32768...32767
foydalanuvchi_id INT UNSIGNED -- 4 milliardgacha
UNSIGNED manfiy bo'lmaydigan qiymatlar uchun ikki foyda
beradi: chegara ikki barobar kengayadi va manfiy qiymat
xato beradi - ya'ni cheklov vazifasini ham bajaradi.
Kasr sonlar va pul #
CREATE TABLE narxlar (
id INT PRIMARY KEY AUTO_INCREMENT,
suzuvchi DOUBLE,
aniq DECIMAL(12,2)
);
INSERT INTO narxlar (suzuvchi, aniq) VALUES
(0.1, 0.1), (0.2, 0.2);
SELECT
SUM(suzuvchi) AS suzuvchi_yigindi,
SUM(aniq) AS aniq_yigindi,
SUM(suzuvchi) = 0.3 AS suzuvchi_tengmi,
SUM(aniq) = 0.3 AS aniq_tengmi
FROM narxlar;
+---------------------+--------------+-----------------+-------------+
| suzuvchi_yigindi | aniq_yigindi | suzuvchi_tengmi | aniq_tengmi |
+---------------------+--------------+-----------------+-------------+
| 0.30000000000000004 | 0.30 | 0 | 1 |
+---------------------+--------------+-----------------+-------------+
FLOAT yoki DOUBLE da saqlamangYuqoridagi natija hamma narsani ko'rsatadi: 0.1 + 0.2 suzuvchi
nuqtada 0.3 emas.
Sabab - 0.1 ni ikkilik sanoqda aniq ifodalab bo'lmaydi.
Bu MariaDB ning kamchiligi emas, IEEE 754 standartining
tabiati.
Moliyaviy hisobda bu halokatli:
| Muammo | Natija |
|---|---|
| Yig'indi mos kelmaydi | Hisobot 1 tiyinga farq qiladi |
= bilan taqqoslash ishlamaydi | To'lov "topilmadi" |
| Yaxlitlash to'planadi | Million tranzaksiyada katta farq |
To'g'ri turlar:
narx DECIMAL(12,2) -- 10 butun + 2 kasr xona, ANIQ
tiyin BIGINT -- butun sonda tiyin sifatida
DECIMAL ichkarida o'nlik sifatida saqlanadi, shuning uchun
yaxlitlash xatosi yo'q.
FLOAT/DOUBLE qayerda o'rinli:
- O'lchov natijalari (harorat, og'irlik);
- Geografik koordinatalar;
- Ilmiy hisoblar;
- Aniqlik muhim bo'lmagan statistika.
Ya'ni: taxminiy qiymatlar uchun suzuvchi nuqta, aniq
qiymatlar uchun DECIMAL.
Matn turlari #
SELECT
CHAR_LENGTH('Salom') AS belgilar,
LENGTH('Salom') AS baytlar,
CHAR_LENGTH('O''zbekiston') AS uz_belgilar,
LENGTH('O''zbekiston') AS uz_baytlar,
CHAR_LENGTH(_utf8mb4 '😀') AS emoji_belgilar,
LENGTH(_utf8mb4 '😀') AS emoji_baytlar;
+----------+---------+-------------+------------+----------------+---------------+
| belgilar | baytlar | uz_belgilar | uz_baytlar | emoji_belgilar | emoji_baytlar |
+----------+---------+-------------+------------+----------------+---------------+
| 5 | 5 | 11 | 11 | 1 | 4 |
+----------+---------+-------------+------------+----------------+---------------+
| Tur | Maksimal | Qachon |
|---|---|---|
CHAR(n) | 255 belgi | Doim bir xil uzunlik: kod, valyuta |
VARCHAR(n) | 65 535 bayt | O'zgaruvchan uzunlik - eng ko'p ishlatiladi |
TINYTEXT | 255 bayt | Kamdan-kam |
TEXT | 64 KB | Maqola, izoh |
MEDIUMTEXT | 16 MB | Katta hujjat |
LONGTEXT | 4 GB | Juda kam kerak |
CHAR va VARCHAR farqikod CHAR(3) -- 'UZS' - har doim 3 bayt
ism VARCHAR(100) -- 'Ali' - 3 bayt + 1 bayt uzunlik
CHAR bo'sh joy bilan to'ldiriladi va o'qishda bo'shliqlar
kesiladi:
CHAR(5) ga 'ab' yozsangiz -> 'ab ' saqlanadi, 'ab' qaytadi
Qachon CHAR:
| Ustun | Nima uchun |
|---|---|
CHAR(2) mamlakat kodi | Har doim aynan 2 |
CHAR(3) valyuta | ISO kod |
CHAR(60) bcrypt xesh | Har doim 60 |
CHAR(9) pasport | Format qat'iy |
Qolgan hamma joyda VARCHAR.
VARCHAR(255) ni o'ylamasdan qo'ymang. U tarixiy odat:
eski MySQL da 255 gacha bo'lgan uzunlik 1 bayt bilan
saqlanardi. Hozir bu ahamiyatsiz, lekin uzunlik hujjat
vazifasini bajaradi:
telefon VARCHAR(20) -- "bu telefon, maqola emas"
email VARCHAR(254) -- RFC chegarasi
ism VARCHAR(100)
Chegara cheklov hamdir - VARCHAR(20) ga 5000 belgi
yozib bo'lmaydi.
Sana va vaqt #
CREATE TABLE vaqtlar (
id INT PRIMARY KEY AUTO_INCREMENT,
faqat_sana DATE,
sana_vaqt DATETIME,
vaqt_belgisi TIMESTAMP NULL,
faqat_vaqt TIME,
faqat_yil YEAR
);
INSERT INTO vaqtlar (faqat_sana, sana_vaqt, vaqt_belgisi, faqat_vaqt, faqat_yil)
VALUES ('2026-09-10', '2026-09-10 14:30:00', '2026-09-10 14:30:00', '14:30:00', 2026);
SELECT faqat_sana, sana_vaqt, faqat_vaqt, faqat_yil FROM vaqtlar;
+------------+---------------------+------------+-----------+
| faqat_sana | sana_vaqt | faqat_vaqt | faqat_yil |
+------------+---------------------+------------+-----------+
| 2026-09-10 | 2026-09-10 14:30:00 | 14:30:00 | 2026 |
+------------+---------------------+------------+-----------+
SELECT
DATE_FORMAT(sana_vaqt, '%d.%m.%Y') AS uzbekcha,
YEAR(sana_vaqt) AS yil,
MONTH(sana_vaqt) AS oy,
DAYOFWEEK(sana_vaqt) AS hafta_kuni,
DATEDIFF('2026-12-31', faqat_sana) AS yil_oxirigacha
FROM vaqtlar;
+------------+------+------+------------+----------------+
| uzbekcha | yil | oy | hafta_kuni | yil_oxirigacha |
+------------+------+------+------------+----------------+
| 10.09.2026 | 2026 | 9 | 5 | 112 |
+------------+------+------+------------+----------------+
DATETIME va TIMESTAMP - muhim farqDATETIME | TIMESTAMP | |
|---|---|---|
| Hajmi | 8 bayt (5 bayt 5.6+) | 4 bayt |
| Diapazon | 1000 ... 9999-yil | 1970 ... 2038 |
| Vaqt mintaqasi | Saqlanmaydi | UTC da saqlanadi, o'qishda o'giriladi |
| Server zonasi o'zgarsa | Qiymat o'zgarmaydi | Qiymat o'zgaradi |
Bu farq muhim:
-- Tug'ilgan sana - vaqt mintaqasidan mustaqil
tugilgan_sana DATE
-- Voqea vaqti - mintaqaga bog'liq
yaratilgan TIMESTAMP
2038 muammosi: TIMESTAMP 32 bitli sanoqqa asoslangan va
2038-yil 19-yanvarda to'ladi. Kelajakdagi sanalar uchun
(shartnoma tugashi, rejalar) DATETIME ishlating.
Ko'p loyihada eng xavfsiz tanlov:
yaratilgan DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
yangilangan DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
va vaqtni UTC da saqlab, ko'rsatishda foydalanuvchi mintaqasiga o'girish.
Sanani hech qachon VARCHAR da saqlamang - saralash,
taqqoslash va sana funksiyalari ishlamay qoladi.
ENUM va mantiqiy qiymat #
CREATE TABLE buyurtmalar (
id INT PRIMARY KEY AUTO_INCREMENT,
holat ENUM('yangi', 'tolangan', 'yuborilgan', 'bekor') NOT NULL DEFAULT 'yangi',
faolmi BOOLEAN NOT NULL DEFAULT TRUE
);
INSERT INTO buyurtmalar (holat, faolmi) VALUES
('yangi', TRUE), ('tolangan', TRUE), ('bekor', FALSE);
SELECT id, holat, faolmi FROM buyurtmalar ORDER BY id;
+----+----------+--------+
| id | holat | faolmi |
+----+----------+--------+
| 1 | yangi | 1 |
| 2 | tolangan | 1 |
| 3 | bekor | 0 |
+----+----------+--------+
-- Ro'yxatda yo'q qiymat rad etiladi
INSERT INTO buyurtmalar (holat) VALUES ('nomalum');
ERROR 1265 (01000): Data truncated for column 'holat' at row 1
-- BOOLEAN aslida TINYINT(1)
SELECT COLUMN_NAME AS ustun, COLUMN_TYPE AS turi
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'buyurtmalar'
ORDER BY ORDINAL_POSITION;
+--------+-----------------------------------------------+
| ustun | turi |
+--------+-----------------------------------------------+
| id | int(11) |
| holat | enum('yangi','tolangan','yuborilgan','bekor') |
| faolmi | tinyint(1) |
+--------+-----------------------------------------------+
ENUM - qulay, lekin qat'iyENUM afzalliklari:
- Noto'g'ri qiymat kiritib bo'lmaydi;
- Ichkarida son sifatida saqlanadi - ixcham;
- O'qilishi oson.
Kamchiliklari:
| Muammo | Izoh |
|---|---|
| Yangi qiymat qo'shish | ALTER TABLE kerak - katta jadvalda qimmat |
| Tartib | Alifbo emas, e'lon tartibi bo'yicha saralanadi |
| Portativlik | PostgreSQL da boshqacha, SQLite da yo'q |
| Qo'shimcha ma'lumot | Holatga tavsif yoki rang qo'sha olmaysiz |
Qachon ENUM: qiymatlar to'plami deyarli hech qachon
o'zgarmaydi va ular ustida qo'shimcha ma'lumot kerak emas
(jins, ha/yoq, kichik/orta/katta).
Qachon jadval: qiymatlar o'zgarishi mumkin yoki ularning o'z xossalari bor:
CREATE TABLE holatlar (
kod VARCHAR(20) PRIMARY KEY,
nomi VARCHAR(50) NOT NULL,
rangi CHAR(7) NOT NULL,
tartib TINYINT NOT NULL
);
Endi yangi holat qo'shish - oddiy INSERT.
Diqqat: BOOLEAN MariaDB da TINYINT(1) ning taxallusi.
Unga 2 ham yozish mumkin - haqiqiy mantiqiy tur emas.
Turlarning disk hajmiga ta'siri #
SELECT
'INT' AS turi, 4 AS baytlar,
4 * 10000000 / 1024 / 1024 AS mb_10mln
UNION ALL SELECT 'BIGINT', 8, 8 * 10000000 / 1024 / 1024
UNION ALL SELECT 'CHAR(36)', 36, 36 * 10000000 / 1024 / 1024
UNION ALL SELECT 'BINARY(16)', 16, 16 * 10000000 / 1024 / 1024
UNION ALL SELECT 'DATETIME', 8, 8 * 10000000 / 1024 / 1024
UNION ALL SELECT 'TIMESTAMP', 4, 4 * 10000000 / 1024 / 1024;
+------------+---------+--------------+
| turi | baytlar | mb_10mln |
+------------+---------+--------------+
| INT | 4 | 38.14697266 |
| BIGINT | 8 | 76.29394531 |
| CHAR(36) | 36 | 343.32275391 |
| BINARY(16) | 16 | 152.58789063 |
| DATETIME | 8 | 76.29394531 |
| TIMESTAMP | 4 | 38.14697266 |
+------------+---------+--------------+
10 million qatorli jadvalda BIGINT o'rniga INT ishlatish
38 MB tejaydi. Bu ko'p emasdek tuyuladi.
Lekin:
- Bu har bir indeksga ham qo'llanadi - 5 indeks bo'lsa ~190 MB;
- Kamroq joy = ko'proq qator keshda = kamroq disk o'qish;
- Zaxira nusxa va replikatsiya tezroq.
Amaliy tavsiya - haddan tashqari optimallashtirmang, lekin ochiq isrofdan qoching:
| Isrof | O'rniga |
|---|---|
BIGINT har joyda | INT UNSIGNED yetarli bo'lsa |
CHAR(36) UUID | BINARY(16) |
VARCHAR(255) telefon uchun | VARCHAR(20) |
DATETIME faqat sana uchun | DATE |
TEXT qisqa matn uchun | VARCHAR(n) |
Oxirgisi ayniqsa muhim: TEXT ustunlar InnoDB da ba'zan
alohida sahifada saqlanadi va qo'shimcha o'qish talab
qiladi.
Kodlash va solishtirish #
SELECT
@@character_set_database AS kodlash,
@@collation_database AS solishtirish;
+---------+--------------------+
| kodlash | solishtirish |
+---------+--------------------+
| utf8mb4 | utf8mb4_unicode_ci |
+---------+--------------------+
SELECT
'Salom' = 'salom' COLLATE utf8mb4_unicode_ci AS registrsiz,
'Salom' = 'salom' COLLATE utf8mb4_bin AS registrli;
+------------+-----------+
| registrsiz | registrli |
+------------+-----------+
| 1 | 0 |
+------------+-----------+
utf8 MySQL da to'liq Unicode emasMySQL va MariaDB da tarixiy tuzoq bor:
| Nom | Belgi uchun baytlar | Emoji ishlaydimi |
|---|---|---|
utf8 (= utf8mb3) | 3 | Yo'q |
utf8mb4 | 4 | Ha |
utf8 nomi chalg'ituvchi - u haqiqiy UTF-8 emas, uning
qisqartirilgan varianti. Emoji va ba'zi belgilar
saqlanmaydi:
ERROR 1366: Incorrect string value: '\xF0\x9F\x98\x80'
Har doim utf8mb4 ishlating - jadval, ustun va ulanish
darajasida:
CREATE DATABASE bazam
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
Solishtirish (collation) tanlovi:
| Collation | Xususiyati |
|---|---|
utf8mb4_unicode_ci | Registrsiz, tilga xos qoidalar |
utf8mb4_general_ci | Tezroq, lekin kamroq to'g'ri |
utf8mb4_bin | Bayt bo'yicha - registr muhim |
utf8mb4_uca1400_* | Eng yangi Unicode qoidalari |
Ko'p loyiha uchun utf8mb4_unicode_ci to'g'ri tanlov.
Parol xeshi yoki token uchun esa utf8mb4_bin - u yerda
registr ahamiyatli.
Tur tanlash tartibi #
| Ma'lumot | Tur |
|---|---|
| Identifikator | INT UNSIGNED yoki BIGINT UNSIGNED |
| Yosh, ball (0-255) | TINYINT UNSIGNED |
| Pul | DECIMAL(12,2) yoki BIGINT (tiyin) |
| Foiz, koeffitsient | DECIMAL(5,2) |
| O'lchov, koordinata | DOUBLE |
| Qisqa matn | VARCHAR(n) - n mazmunga qarab |
| Qat'iy uzunlikdagi kod | CHAR(n) |
| Maqola, izoh | TEXT |
| Tug'ilgan sana | DATE |
| Voqea vaqti | DATETIME (UTC da) |
| Ha/yo'q | BOOLEAN (= TINYINT(1)) |
| Cheklangan ro'yxat | ENUM yoki alohida jadval |
| Fayl | Fayl tizimida, bazada faqat yo'l |
Oxirgisi muhim: rasm va faylni bazada BLOB sifatida saqlash
mumkin, lekin bu deyarli har doim yomon g'oya - zaxira
nusxa kattalashadi, kesh buziladi, uzatish sekinlashadi.
Faylni obyekt omborida saqlab, bazada yo'lini yozing.
- Butun son turlarini yaratib, chegaralarini sinang.
TINYINTchegarasidan chiqishga urinib ko'ring.INT(11)dagi 11 nimani anglatishini tushuntiring.DOUBLEvaDECIMALda0.1 + 0.2ni taqqoslang.- Pul uchun qaysi tur to'g'ri ekanini asoslang.
CHARvaVARCHARfarqini misolda ko'rsating.DATETIMEvaTIMESTAMPfarqini sanang.ENUMga ro'yxatda yo'q qiymat kiritishga urinib ko'ring.ENUMo'rniga jadval qachon kerakligini ayting.utf8vautf8mb4farqini tushuntiring.
Xulosa #
INT(11)dagi 11 - ko'rsatish kengligi, chegara emas.UNSIGNEDchegarani kengaytiradi va cheklov vazifasini bajaradi.- Pulni hech qachon
FLOAT/DOUBLEda saqlamang. DECIMALaniq, suzuvchi nuqta taxminiy.CHARqat'iy uzunlik uchun, qolgan joydaVARCHAR.VARCHARuzunligi hujjat va cheklov vazifasini bajaradi.TIMESTAMP2038-yilda to'ladi va mintaqaga bog'liq.- Kelajak sanalar uchun
DATETIME. - Sanani hech qachon
VARCHARda saqlamang. ENUMo'zgarmas ro'yxat uchun; o'zgaruvchan bo'lsa - jadval.utf8emas,utf8mb4- aks holda emoji saqlanmaydi.- Faylni bazada emas, fayl tizimida saqlang.
Keyingi bo'limda NULL semantikasini 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.