نوع داده یک قرارداد است، نه فقط یک ظرف
نوع درست ستون سه کار میکند: جلوی دادهی غلط را میگیرد، فضای دیسک و حافظه را کم میکند (ایندکسها کوچکتر و سریعتر میشوند) و مقایسهها را درست انجام میدهد. تغییر نوع ستون روی جدول چندمیلیونی بعداً یعنی بازسازی کل جدول؛ پس از اول درست انتخاب کنید.
اعداد صحیح
| نوع | بایت | بازهی UNSIGNED | مثال کاربرد |
|---|---|---|---|
| TINYINT | 1 | 0 تا 255 | وضعیت، پرچم بولی |
| SMALLINT | 2 | 0 تا 65,535 | ابعاد به سانتیمتر، تراکم شانه |
| MEDIUMINT | 3 | 0 تا 16.7 میلیون | جدولهای مرجع متوسط |
| INT | 4 | 0 تا 4.29 میلیارد | شناسهی اغلب جدولها |
| BIGINT | 8 | 0 تا 1.8×10^19 | شناسهی لاگ و رویداد، مبلغ ریالی بهصورت عدد صحیح |
عدد داخل پرانتز در INT(11) «عرض نمایش» است، نه محدودیت؛ در MySQL 8 منسوخ شده و بیاثر است. BOOLEAN هم فقط نام دیگر TINYINT(1) است و مقدار 7 را هم میپذیرد.
پول: DECIMAL، هرگز FLOAT
SELECT 0.1 + 0.2 = 0.3; -- 1 (لیترالها DECIMAL هستند)
SELECT CAST(0.1 AS DOUBLE) + CAST(0.2 AS DOUBLE) = 0.3; -- 0 !
CREATE TABLE invoices (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
amount DECIMAL(15,0) NOT NULL, -- ریال؛ تا 999 تریلیون
tax_rate DECIMAL(5,2) NOT NULL DEFAULT 10.00,
usd_rate DECIMAL(12,2) NULL, -- نرخ ارز با دو رقم اعشار
weight_kg FLOAT NULL -- اندازهگیری فیزیکی؛ خطای کوچک مهم نیست
);
FLOAT و DOUBLE اعداد را بهصورت تقریبی دودویی نگه میدارند؛ جمع هزاران ردیف، اختلاف چندریالی میسازد که حسابدار هرگز نمیبخشد. DECIMAL(M,D) دقیق است: M کل ارقام و D ارقام اعشار. برای ریال D=0 کافی است؛ اگر سیستم تومان با اعشار (مثل ۱۲٬۵۰۰٫۵) لازم دارد، ریال ذخیره کنید و در نمایش تبدیل کنید.
متن: CHAR، VARCHAR و TEXT
VARCHAR(n): n به کاراکتر است، نه بایت. در utf8mb4 هر کاراکتر تا ۴ بایت جا میگیرد.CHAR(n): طول ثابت؛ برای کدهای همطول مثل کد کشور. در utf8mb4 مزیت فضایی ندارد.TEXT(64KB)،MEDIUMTEXT(16MB)،LONGTEXT(4GB): برای متن بلند؛ بیرون از ردیف اصلی ذخیره میشوند، پیشفرض ثابت (جز عبارت در پرانتز در 8.0.13 به بعد) ندارند و فقط با پیشوند ایندکس میشوند.
CREATE TABLE customers (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
full_name VARCHAR(120) NOT NULL,
mobile CHAR(11) NOT NULL, -- 09121234567 ؛ رشته، نه عدد!
national_id CHAR(10) NULL, -- صفر ابتدایی حفظ میشود
notes TEXT NULL,
UNIQUE KEY uq_mobile (mobile)
);
نکتههایی که کمتر کسی میداند
- مجموع طول همهی ستونهای VARCHAR یک ردیف (بر حسب بایت بیشینه) نباید از 65,535 بایت بگذرد؛ در utf8mb4 یعنی حدود 16,000 کاراکتر برای کل ردیف. به همین دلیل VARCHAR(20000) خطای Row size too large میدهد.
- کلید ایندکس در InnoDB حداکثر 3072 بایت است؛ یعنی VARCHAR(768) در utf8mb4. ایندکس ترکیبی هم مجموع بایتها را حساب میکند.
- شمارهی موبایل، کد ملی و کد پستی را هرگز INT نکنید؛ صفر ابتدایی کد ملی حذف میشود و روی آن محاسبهی ریاضی هم انجام نمیدهید.
UNSIGNEDروی DECIMAL و FLOAT در 8.0.17 منسوخ شده؛ برای جلوگیری از مبلغ منفی ازCHECK (amount >= 0)استفاده کنید.- تفریق دو ستون UNSIGNED که نتیجهاش منفی شود، خطای
BIGINT UNSIGNED value is out of rangeمیدهد؛ مثلاًstock - reserved. یکی را CAST به SIGNED کنید.