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.

🕑 25 daqiqa o‘qish 📄 1 365 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Butun sonlar
  2. Kasr sonlar va pul
  3. Matn turlari
  4. Sana va vaqt
  5. ENUM va mantiqiy qiymat
  6. Turlarning disk hajmiga ta'siri
  7. Kodlash va solishtirish
  8. Tur tanlash tartibi
  9. Xulosa

Tur tanlash - "shunchaki VARCHAR(255) qo'yaman" degan qaror emas. U to'g'rilikni, tezlikni va disk hajmini belgilaydi.

Butun sonlar #

SQL
CREATE TABLE butun_turlar (
    kichik    TINYINT,
    qisqa     SMALLINT,
    orta      MEDIUMINT,
    oddiy     INT,
    katta     BIGINT,
    ishorasiz TINYINT UNSIGNED
);
SQL
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;
Natija
+-----------+---------------------+
| ustun     | turi                |
+-----------+---------------------+
| kichik    | tinyint(4)          |
| qisqa     | smallint(6)         |
| orta      | mediumint(9)        |
| oddiy     | int(11)             |
| katta     | bigint(20)          |
| ishorasiz | tinyint(3) unsigned |
+-----------+---------------------+
TurBaytlarIshorali chegara
TINYINT1-128 ... 127
SMALLINT2-32 768 ... 32 767
MEDIUMINT3±8.3 million
INT4±2.1 milliard
BIGINT8±9.2 kvintillion
SQL
-- Chegaradan chiqishga urinish
INSERT INTO butun_turlar (kichik) VALUES (200);
Natija
ERROR 1264 (22003): Out of range value for column 'kichik' at row 1
SQL
-- UNSIGNED bilan chegara ikki barobar kengayadi
INSERT INTO butun_turlar (ishorasiz) VALUES (200);

SELECT ishorasiz FROM butun_turlar WHERE ishorasiz IS NOT NULL;
Natija
+-----------+
| ishorasiz |
+-----------+
|       200 |
+-----------+
INT(11) dagi 11 - kenglik emas

Ko'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:

SQL
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:

SQL
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 #

SQL
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);
SQL
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;
Natija
+---------------------+--------------+-----------------+-------------+
| suzuvchi_yigindi    | aniq_yigindi | suzuvchi_tengmi | aniq_tengmi |
+---------------------+--------------+-----------------+-------------+
| 0.30000000000000004 |         0.30 |               0 |           1 |
+---------------------+--------------+-----------------+-------------+
Pulni hech qachon FLOAT yoki DOUBLE da saqlamang

Yuqoridagi 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:

MuammoNatija
Yig'indi mos kelmaydiHisobot 1 tiyinga farq qiladi
= bilan taqqoslash ishlamaydiTo'lov "topilmadi"
Yaxlitlash to'planadiMillion tranzaksiyada katta farq

To'g'ri turlar:

SQL
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 #

SQL
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;
Natija
+----------+---------+-------------+------------+----------------+---------------+
| belgilar | baytlar | uz_belgilar | uz_baytlar | emoji_belgilar | emoji_baytlar |
+----------+---------+-------------+------------+----------------+---------------+
|        5 |       5 |          11 |         11 |              1 |             4 |
+----------+---------+-------------+------------+----------------+---------------+
TurMaksimalQachon
CHAR(n)255 belgiDoim bir xil uzunlik: kod, valyuta
VARCHAR(n)65 535 baytO'zgaruvchan uzunlik - eng ko'p ishlatiladi
TINYTEXT255 baytKamdan-kam
TEXT64 KBMaqola, izoh
MEDIUMTEXT16 MBKatta hujjat
LONGTEXT4 GBJuda kam kerak
CHAR va VARCHAR farqi
SQL
kod   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:

SQL
CHAR(5) ga 'ab' yozsangiz -> 'ab   ' saqlanadi, 'ab' qaytadi

Qachon CHAR:

UstunNima uchun
CHAR(2) mamlakat kodiHar doim aynan 2
CHAR(3) valyutaISO kod
CHAR(60) bcrypt xeshHar doim 60
CHAR(9) pasportFormat 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:

SQL
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 #

SQL
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);
SQL
SELECT faqat_sana, sana_vaqt, faqat_vaqt, faqat_yil FROM vaqtlar;
Natija
+------------+---------------------+------------+-----------+
| faqat_sana | sana_vaqt           | faqat_vaqt | faqat_yil |
+------------+---------------------+------------+-----------+
| 2026-09-10 | 2026-09-10 14:30:00 | 14:30:00   |      2026 |
+------------+---------------------+------------+-----------+
SQL
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;
Natija
+------------+------+------+------------+----------------+
| uzbekcha   | yil  | oy   | hafta_kuni | yil_oxirigacha |
+------------+------+------+------------+----------------+
| 10.09.2026 | 2026 |    9 |          5 |            112 |
+------------+------+------+------------+----------------+
DATETIME va TIMESTAMP - muhim farq
DATETIMETIMESTAMP
Hajmi8 bayt (5 bayt 5.6+)4 bayt
Diapazon1000 ... 9999-yil1970 ... 2038
Vaqt mintaqasiSaqlanmaydiUTC da saqlanadi, o'qishda o'giriladi
Server zonasi o'zgarsaQiymat o'zgarmaydiQiymat o'zgaradi

Bu farq muhim:

SQL
-- 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:

SQL
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 #

SQL
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);
SQL
SELECT id, holat, faolmi FROM buyurtmalar ORDER BY id;
Natija
+----+----------+--------+
| id | holat    | faolmi |
+----+----------+--------+
|  1 | yangi    |      1 |
|  2 | tolangan |      1 |
|  3 | bekor    |      0 |
+----+----------+--------+
SQL
-- Ro'yxatda yo'q qiymat rad etiladi
INSERT INTO buyurtmalar (holat) VALUES ('nomalum');
Natija
ERROR 1265 (01000): Data truncated for column 'holat' at row 1
SQL
-- 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;
Natija
+--------+-----------------------------------------------+
| ustun  | turi                                          |
+--------+-----------------------------------------------+
| id     | int(11)                                       |
| holat  | enum('yangi','tolangan','yuborilgan','bekor') |
| faolmi | tinyint(1)                                    |
+--------+-----------------------------------------------+
ENUM - qulay, lekin qat'iy

ENUM afzalliklari:

  • Noto'g'ri qiymat kiritib bo'lmaydi;
  • Ichkarida son sifatida saqlanadi - ixcham;
  • O'qilishi oson.

Kamchiliklari:

MuammoIzoh
Yangi qiymat qo'shishALTER TABLE kerak - katta jadvalda qimmat
TartibAlifbo emas, e'lon tartibi bo'yicha saralanadi
PortativlikPostgreSQL da boshqacha, SQLite da yo'q
Qo'shimcha ma'lumotHolatga 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:

SQL
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 #

SQL
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;
Natija
+------------+---------+--------------+
| 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 |
+------------+---------+--------------+
Kichik farq katta jadvalda sezilarli

10 million qatorli jadvalda BIGINT o'rniga INT ishlatish 38 MB tejaydi. Bu ko'p emasdek tuyuladi.

Lekin:

  1. Bu har bir indeksga ham qo'llanadi - 5 indeks bo'lsa ~190 MB;
  2. Kamroq joy = ko'proq qator keshda = kamroq disk o'qish;
  3. Zaxira nusxa va replikatsiya tezroq.

Amaliy tavsiya - haddan tashqari optimallashtirmang, lekin ochiq isrofdan qoching:

IsrofO'rniga
BIGINT har joydaINT UNSIGNED yetarli bo'lsa
CHAR(36) UUIDBINARY(16)
VARCHAR(255) telefon uchunVARCHAR(20)
DATETIME faqat sana uchunDATE
TEXT qisqa matn uchunVARCHAR(n)

Oxirgisi ayniqsa muhim: TEXT ustunlar InnoDB da ba'zan alohida sahifada saqlanadi va qo'shimcha o'qish talab qiladi.

Kodlash va solishtirish #

SQL
SELECT
    @@character_set_database AS kodlash,
    @@collation_database     AS solishtirish;
Natija
+---------+--------------------+
| kodlash | solishtirish       |
+---------+--------------------+
| utf8mb4 | utf8mb4_unicode_ci |
+---------+--------------------+
SQL
SELECT
    'Salom' = 'salom' COLLATE utf8mb4_unicode_ci AS registrsiz,
    'Salom' = 'salom' COLLATE utf8mb4_bin        AS registrli;
Natija
+------------+-----------+
| registrsiz | registrli |
+------------+-----------+
|          1 |         0 |
+------------+-----------+
utf8 MySQL da to'liq Unicode emas

MySQL va MariaDB da tarixiy tuzoq bor:

NomBelgi uchun baytlarEmoji ishlaydimi
utf8 (= utf8mb3)3Yo'q
utf8mb44Ha

utf8 nomi chalg'ituvchi - u haqiqiy UTF-8 emas, uning qisqartirilgan varianti. Emoji va ba'zi belgilar saqlanmaydi:

Natija
ERROR 1366: Incorrect string value: '\xF0\x9F\x98\x80'

Har doim utf8mb4 ishlating - jadval, ustun va ulanish darajasida:

SQL
CREATE DATABASE bazam
    CHARACTER SET utf8mb4
    COLLATE utf8mb4_unicode_ci;

Solishtirish (collation) tanlovi:

CollationXususiyati
utf8mb4_unicode_ciRegistrsiz, tilga xos qoidalar
utf8mb4_general_ciTezroq, lekin kamroq to'g'ri
utf8mb4_binBayt 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 #

Tur tanlash daraxti Qanday qiymat? Son Matn Vaqt / holat butun kasr chegarali uzun sana bayroq TINYINT / INT 1-8 bayt DECIMAL pul - aniq VARCHAR(n) indekslanadi TEXT alohida saqlanadi DATE / DATETIME UTC da BOOLEAN TINYINT(1) Uchta qoida 1. Qiymat sig'adigan eng kichik turni tanlang - kichik tur = kichik indeks. 2. Pulda hech qachon FLOAT/DOUBLE ishlatmang - yaxlitlash xatosi to'planadi. 3. Manfiy bo'lmaydigan qiymatga UNSIGNED - chegara ikki barobar oshadi.
Turni tanlash - qiymat mazmunidan boshlanadi, hajmdan emas
Amaliy qo'llanma
Ma'lumotTur
IdentifikatorINT UNSIGNED yoki BIGINT UNSIGNED
Yosh, ball (0-255)TINYINT UNSIGNED
PulDECIMAL(12,2) yoki BIGINT (tiyin)
Foiz, koeffitsientDECIMAL(5,2)
O'lchov, koordinataDOUBLE
Qisqa matnVARCHAR(n) - n mazmunga qarab
Qat'iy uzunlikdagi kodCHAR(n)
Maqola, izohTEXT
Tug'ilgan sanaDATE
Voqea vaqtiDATETIME (UTC da)
Ha/yo'qBOOLEAN (= TINYINT(1))
Cheklangan ro'yxatENUM yoki alohida jadval
FaylFayl 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.

Amaliy topshiriq
  1. Butun son turlarini yaratib, chegaralarini sinang.
  2. TINYINT chegarasidan chiqishga urinib ko'ring.
  3. INT(11) dagi 11 nimani anglatishini tushuntiring.
  4. DOUBLE va DECIMAL da 0.1 + 0.2 ni taqqoslang.
  5. Pul uchun qaysi tur to'g'ri ekanini asoslang.
  6. CHAR va VARCHAR farqini misolda ko'rsating.
  7. DATETIME va TIMESTAMP farqini sanang.
  8. ENUM ga ro'yxatda yo'q qiymat kiritishga urinib ko'ring.
  9. ENUM o'rniga jadval qachon kerakligini ayting.
  10. utf8 va utf8mb4 farqini tushuntiring.

Xulosa #

  • INT(11) dagi 11 - ko'rsatish kengligi, chegara emas.
  • UNSIGNED chegarani kengaytiradi va cheklov vazifasini bajaradi.
  • Pulni hech qachon FLOAT/DOUBLE da saqlamang.
  • DECIMAL aniq, suzuvchi nuqta taxminiy.
  • CHAR qat'iy uzunlik uchun, qolgan joyda VARCHAR.
  • VARCHAR uzunligi hujjat va cheklov vazifasini bajaradi.
  • TIMESTAMP 2038-yilda to'ladi va mintaqaga bog'liq.
  • Kelajak sanalar uchun DATETIME.
  • Sanani hech qachon VARCHAR da saqlamang.
  • ENUM o'zgarmas ro'yxat uchun; o'zgaruvchan bo'lsa - jadval.
  • utf8 emas, utf8mb4 - aks holda emoji saqlanmaydi.
  • Faylni bazada emas, fayl tizimida saqlang.

Keyingi bo'limda NULL semantikasini batafsil ko'ramiz.

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.