معروفترین دام MySQL برای متن فارسی
Character set تعیین میکند هر کاراکتر با چه بایتهایی ذخیره شود و Collation تعیین میکند مقایسه و مرتبسازی چطور انجام شود (بزرگ و کوچکی حروف، اعراب، ترتیب الفبا). دام تاریخی این است: در MySQL نام utf8 در واقع یعنی utf8mb3، یعنی حداکثر ۳ بایت برای هر کاراکتر. متن فارسی معمولی در ۲ بایت جا میشود، پس سالها همهچیز درست کار میکرد — تا روزی که کاربری در نظرات ایموجی گذاشت یا نامی با یک کاراکتر نادر وارد کرد و خطای زیر آمد:
ERROR 1366 (HY000): Incorrect string value: '\xF0\x9F\x8C\xB9' for column 'comment' at row 1
utf8mb4 یونیکد کامل (تا ۴ بایت) است. در MySQL 8 پیشفرض سرور همین است، اما دیتابیسها و جدولهایی که از 5.7 مهاجرت کردهاند هنوز ممکن است utf8mb3 یا حتی latin1 باشند. utf8mb3 منسوخ شده و در نسخههای آینده حذف میشود.
چهار سطح، و سطح پنجم که همه فراموش میکنند
charset در سطح سرور، دیتابیس، جدول و ستون تعریف میشود و هر سطح پیشفرض سطح پایینتر است. اما سطح پنجم اتصال است: کلاینت باید بگوید بایتهایی که میفرستد با چه charsetای است. اگر اتصال latin1 باشد و ستون utf8mb4، فارسیها «؟؟؟؟» یا «Ø³Ù„ام» ذخیره میشوند.
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
SET NAMES utf8mb4 COLLATE utf8mb4_0900_ai_ci; -- تنظیم charset اتصال
-- کدام ستونها هنوز utf8mb4 نیستند؟
SELECT table_name, column_name, character_set_name, collation_name
FROM information_schema.columns
WHERE table_schema = 'carpet_shop'
AND character_set_name IS NOT NULL
AND character_set_name <> 'utf8mb4';
-- تبدیل یک جدول (کل جدول بازسازی میشود؛ روی جدول بزرگ در ساعت کمبار)
ALTER TABLE customers CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
کدام collation؟
| Collation | رفتار | کاربرد |
|---|---|---|
utf8mb4_0900_ai_ci | UCA 9.0، بیحساس به اعراب و بزرگی حروف، NO PAD، سریع | پیشفرض MySQL 8؛ انتخاب عمومی خوب |
utf8mb4_0900_as_cs | حساس به اعراب و بزرگی حروف | کد محصول، نام کاربری حساس |
utf8mb4_persian_ci | UCA قدیمیتر با تنظیم مخصوص الفبای فارسی، PAD SPACE | وقتی ترتیب الفبایی دقیق فارسی مهم است |
utf8mb4_unicode_ci | UCA 4.0، قدیمی | سازگاری با MariaDB و پروژههای قدیمی |
utf8mb4_bin | مقایسهی بایتبهبایت | توکن، هش، شناسههای دقیق |
قبل از انتخاب نهایی، روی دادهی واقعی خودتان مرتبسازی را ببینید:
SELECT name FROM (
SELECT 'گلیم' AS name UNION ALL SELECT 'پشتی' UNION ALL SELECT 'ژاکت'
UNION ALL SELECT 'کناره' UNION ALL SELECT 'چله' UNION ALL SELECT 'بافت'
) t ORDER BY name COLLATE utf8mb4_persian_ci;
نکتههایی که کمتر کسی میداند
- collationهای
0900از نوع NO PAD هستند:'فرش' = 'فرش '(با فاصلهی انتهایی) در آنها نادرست است، اما درutf8mb4_unicode_ciدرست. مهاجرت collation میتواند رفتار UNIQUE را عوض کند. - در collationهای UCA نیمفاصله کاراکتری «قابل چشمپوشی» است؛ بنابراین معمولاً
'میشود' = 'میشود'درست است. برای جستوجو خوب است، برای UNIQUE ممکن است غافلگیرتان کند. - JOIN بین دو ستون با collation متفاوت یا خطای
Illegal mix of collationsمیدهد یا ایندکس را بیاستفاده میکند؛ کل دیتابیس را یکدست نگه دارید. - ستون
VARCHAR(255)در utf8mb4 تا 1020 بایت جا میگیرد؛ محدودیت قدیمی 767 بایت ایندکس در 5.6 دلیل آنVARCHAR(191)های معروف لاراول بود که در MySQL 8 دیگر لازم نیست. - برای یک ستون خاص میتوانید collation جدا بگذارید:
sku VARCHAR(30) COLLATE utf8mb4_bin؛ بقیهی جدول دست نمیخورد.