MySQL8中大小寫敏感與不敏感排序規(guī)則的選擇(根據(jù)字段語義)
在 MySQL 數(shù)據(jù)庫設(shè)計(jì)中,字符集(charset)和排序規(guī)則(collation)通常是在創(chuàng)建數(shù)據(jù)庫或表時(shí)確定的配置,但它們會直接影響字符串比較、排序以及查詢行為。
在 MySQL 8 中,常見的排序規(guī)則包括:
utf8mb4_binutf8mb4_unicode_ciutf8mb4_0900_ai_ci
不同排序規(guī)則會影響字符串是否區(qū)分大小寫、排序方式以及模糊查詢行為。很多項(xiàng)目在建表時(shí)沒有認(rèn)真考慮,后期才在搜索或索引使用時(shí)遇到問題。
本文總結(jié)在 MySQL 8 中如何根據(jù)字段語義選擇大小寫敏感或不敏感的排序規(guī)則。
排序規(guī)則與大小寫敏感
MySQL 排序規(guī)則決定了字符串比較方式。
常見類型可以分為兩類。
大小寫敏感(Binary Collation)
bin代表二進(jìn)制,大小寫敏感。
例如:
utf8mb4_bin
utf8mb4_bin 使用二進(jìn)制方式比較字符串,本質(zhì)上按 UTF-8 字節(jié)值進(jìn)行比較,因此字符 A 與 a 是不同的。
示例:
SELECT 'abc' = 'ABC' COLLATE utf8mb4_bin;
結(jié)果:
0
大小寫不敏感(Case Insensitive Collation)
ci代表case insensitive大小寫不敏感。 例如:
utf8mb4_unicode_ci utf8mb4_0900_ai_ci
示例:
SELECT 'abc' = 'ABC' COLLATE utf8mb4_unicode_ci;
結(jié)果:
1
這種差異會影響所有字符串操作,包括:
=LIKEORDER BY- 索引匹配
適合使用大小寫敏感排序規(guī)則的場景
大小寫敏感通常適用于技術(shù)型字段,這些字段本身具有嚴(yán)格的字符含義,不應(yīng)該因?yàn)榇笮懽兓徽J(rèn)為是相同值。
常見場景包括:
- 用戶名或登錄名(部分系統(tǒng)區(qū)分大小寫)
- 密碼哈希值
- API Key / Token
- UUID 或 Hash 字符串
- Base64 編碼
- 文件路徑
推薦使用:
COLLATE utf8mb4_bin
示例:
CREATE TABLE api_keys (
id BIGINT PRIMARY KEY,
api_key VARCHAR(128) COLLATE utf8mb4_bin,
user_id BIGINT
);這樣可以確保字符串完全精確匹配。
適合使用大小寫不敏感排序規(guī)則的場景
另一類字段屬于用戶輸入文本,例如自然語言內(nèi)容。
常見字段包括:
- 用戶昵稱
- 文章標(biāo)題
- 商品名稱
- 標(biāo)簽
- 城市或地址
- 評論內(nèi)容
例如用戶搜索 iphone 時(shí)通常希望匹配:
iphone iPhone IPHONE
因此推薦使用大小寫不敏感排序規(guī)則:
utf8mb4_unicode_ci
或在 MySQL 8 中更推薦:
utf8mb4_0900_ai_ci
示例:
CREATE TABLE articles (
id BIGINT PRIMARY KEY,
title VARCHAR(255) COLLATE utf8mb4_0900_ai_ci,
content TEXT COLLATE utf8mb4_0900_ai_ci
);這樣 LIKE 查詢和搜索體驗(yàn)會更友好。
為什么不建議全庫使用 utf8mb4_bin
有些團(tuán)隊(duì)為了避免排序規(guī)則混亂,會選擇全庫統(tǒng)一使用 utf8mb4_bin。
雖然簡單,但會帶來明顯問題。
搜索體驗(yàn)差
例如:
SELECT * FROM products WHERE name LIKE 'iphone%';
如果字段是 utf8mb4_bin,則不會匹配:
iPhone
排序不符合語言習(xí)慣
utf8mb4_bin 按字節(jié)排序,而不是按語言規(guī)則排序。
因此 ORDER BY 的結(jié)果可能不符合人類閱讀習(xí)慣。
模糊查詢命中率低
用戶輸入通常不會嚴(yán)格區(qū)分大小寫。
推薦的數(shù)據(jù)庫設(shè)計(jì)方式
比較合理的設(shè)計(jì)方式是:
數(shù)據(jù)庫默認(rèn)使用大小寫不敏感排序規(guī)則,少數(shù)需要精確匹配的字段單獨(dú)使用 _bin。
示例:
CREATE TABLE users (
id BIGINT PRIMARY KEY,
username VARCHAR(64) COLLATE utf8mb4_bin,
email VARCHAR(128) COLLATE utf8mb4_0900_ai_ci,
nickname VARCHAR(64) COLLATE utf8mb4_0900_ai_ci,
password_hash VARCHAR(255) COLLATE utf8mb4_bin,
bio TEXT COLLATE utf8mb4_0900_ai_ci
);這種設(shè)計(jì)可以兼顧:
- 安全字段精確匹配
- 用戶文本友好搜索
MySQL 8 推薦默認(rèn)排序規(guī)則
如果是新項(xiàng)目,MySQL 8 推薦使用:
utf8mb4_0900_ai_ci
特點(diǎn)包括:
- 基于 Unicode 9.0
- 支持更多語言字符
- 支持 emoji
- 排序更符合語言規(guī)則
- 忽略大小寫與重音符號
對于大多數(shù) Web 應(yīng)用,這是最合理的默認(rèn)選擇。
已有表如何修改大小寫敏感規(guī)則
在實(shí)際項(xiàng)目中,排序規(guī)則往往不是一開始就設(shè)計(jì)好的。隨著業(yè)務(wù)發(fā)展,可能會出現(xiàn)以下情況:
- 原本不區(qū)分大小寫的字段,需要改為區(qū)分大小寫
- 新增字段,需要指定為大小寫敏感
- 整個(gè)表需要統(tǒng)一調(diào)整排序規(guī)則
- 數(shù)據(jù)庫默認(rèn)排序規(guī)則需要調(diào)整
因此了解如何在 已有表結(jié)構(gòu)中調(diào)整排序規(guī)則非常重要。
修改字段的排序規(guī)則
如果只是某個(gè)字段需要調(diào)整大小寫敏感規(guī)則,可以直接修改字段的 COLLATE。
例如原字段:
username VARCHAR(64) COLLATE utf8mb4_unicode_ci
需要改為大小寫敏感:
ALTER TABLE users MODIFY username VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
需要注意:
MODIFY時(shí)必須寫完整字段定義- 字符集和排序規(guī)則通常需要一起聲明
- 該操作會重建字段索引
新增大小寫敏感字段
如果是新增字段,可以在 ADD COLUMN 時(shí)直接指定排序規(guī)則。
例如新增 API Key:
ALTER TABLE users ADD COLUMN api_key VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
這樣該字段在比較時(shí)會區(qū)分大小寫。
修改整張表的排序規(guī)則
如果希望整張表默認(rèn)使用新的排序規(guī)則,可以使用:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
該操作會:
- 修改表默認(rèn)字符集
- 修改所有未顯式指定排序規(guī)則的字段
- 重建表數(shù)據(jù)
注意:如果字段已經(jīng)顯式指定 COLLATE,則不會被覆蓋。
注意:如果從字符集A轉(zhuǎn)換成字符集B,存在無法轉(zhuǎn)換的生僻字,MYSQL轉(zhuǎn)換會報(bào)錯(cuò),比如GBK轉(zhuǎn)UTF8/utf8mb4,MYSQL會報(bào)錯(cuò),最佳實(shí)踐是先導(dǎo)出文件,對文件字符集進(jìn)行轉(zhuǎn)換,再導(dǎo)入。
修改數(shù)據(jù)庫默認(rèn)排序規(guī)則
如果希望新建表默認(rèn)使用新的排序規(guī)則,可以修改數(shù)據(jù)庫默認(rèn)設(shè)置。
ALTER DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
該操作只影響:
- 未來新建的表
- 不影響已有表
修改排序規(guī)則時(shí)需要注意的問題
唯一索引沖突
當(dāng)從 大小寫敏感改為不敏感 時(shí),可能出現(xiàn)唯一索引沖突。
例如原數(shù)據(jù):
UserA usera
在 utf8mb4_bin 下是合法的,但在 utf8mb4_unicode_ci 下會被認(rèn)為是相同值。
執(zhí)行修改時(shí)可能報(bào)錯(cuò):
Duplicate entry
因此修改前需要檢查數(shù)據(jù)。
索引可能會被重建
修改字段排序規(guī)則時(shí):
- 索引會重建
- 大表可能產(chǎn)生鎖表
- 需要評估執(zhí)行時(shí)間
對于生產(chǎn)環(huán)境大表,建議:
- 在低峰期執(zhí)行
- 或使用在線 DDL
LIKE 查詢行為會變化
例如:
SELECT * FROM users WHERE username LIKE 'abc%';
在不同排序規(guī)則下:
| 排序規(guī)則 | 是否匹配 Abc |
|---|---|
| utf8mb4_bin | 否 |
| utf8mb4_unicode_ci | 是 |
修改排序規(guī)則后,查詢結(jié)果可能會發(fā)生變化。
實(shí)際項(xiàng)目中的推薦做法
在業(yè)務(wù)系統(tǒng)中,一般采用以下策略:
數(shù)據(jù)庫默認(rèn)排序規(guī)則:
utf8mb4_0900_ai_ci
用戶文本字段:
utf8mb4_0900_ai_ci
技術(shù)標(biāo)識符字段:
utf8mb4_bin
例如:
CREATE TABLE users (
id BIGINT PRIMARY KEY,
username VARCHAR(64) COLLATE utf8mb4_bin,
email VARCHAR(128) COLLATE utf8mb4_0900_ai_ci,
nickname VARCHAR(64) COLLATE utf8mb4_0900_ai_ci,
password_hash VARCHAR(255) COLLATE utf8mb4_bin,
api_key VARCHAR(128) COLLATE utf8mb4_bin
);這種設(shè)計(jì)既能保證安全字段的精確匹配,又能保持良好的搜索體驗(yàn)。
無法修改字符集合排序規(guī)則的處理方案
在一些系統(tǒng)中,由于歷史原因或生產(chǎn)環(huán)境限制,可能無法直接修改字段或表的排序規(guī)則。例如:
- 表數(shù)據(jù)量非常大,修改
COLLATE會導(dǎo)致長時(shí)間鎖表 - 字段存在唯一索引,修改排序規(guī)則可能產(chǎn)生沖突
- 線上系統(tǒng)不允許執(zhí)行重建表結(jié)構(gòu)的操作
- 依賴系統(tǒng)較多,修改排序規(guī)則風(fēng)險(xiǎn)較高
在這種情況下,可以通過其他方式解決大小寫敏感問題。
使用函數(shù)統(tǒng)一大小寫進(jìn)行比較
一種簡單的做法是對字段值和查詢值統(tǒng)一轉(zhuǎn)換大小寫,例如轉(zhuǎn)換為小寫:
SELECT id FROM user WHERE LOWER(name) = 'peter';
或者:
SELECT id
FROM user
WHERE LOWER(name) = LOWER('Peter');這種方式可以在任何排序規(guī)則下實(shí)現(xiàn)大小寫不敏感比較。
但需要注意,這種寫法存在明顯問題。
索引會失效
當(dāng)字段使用函數(shù)處理時(shí),例如 LOWER(name),數(shù)據(jù)庫無法使用原有索引。
例如:
WHERE LOWER(name) = 'peter'
優(yōu)化器無法利用 name 字段上的索引,因此會進(jìn)行 全表掃描。
如果數(shù)據(jù)量較大(例如百萬級以上),查詢性能會明顯下降,因此不建議在高并發(fā)或大數(shù)據(jù)量場景使用。
使用生成列維護(hù)查詢字段
另一種方式是使用 生成列(Generated Column) 來維護(hù)統(tǒng)一格式的字段,例如統(tǒng)一轉(zhuǎn)換為小寫。
例如:
ALTER TABLE user ADD COLUMN name_search VARCHAR(64) GENERATED ALWAYS AS (LOWER(name)) STORED;
然后為生成列創(chuàng)建索引:
CREATE INDEX idx_user_name_search ON user(name_search);
查詢時(shí)使用生成列:
SELECT id FROM user WHERE name_search = 'peter';
這種方式的優(yōu)點(diǎn)是:
- 查詢?nèi)匀豢梢允褂盟饕?/li>
- 不需要修改原字段排序規(guī)則
- 對現(xiàn)有業(yè)務(wù)影響較小
但需要注意:
- 需要額外存儲空間
- 寫入或更新時(shí)需要維護(hù)生成列
- 需要額外維護(hù)索引
在寫入頻繁的業(yè)務(wù)中,需要評估寫入性能影響。
增加搜索中間層(Elasticsearch)
當(dāng)系統(tǒng)對搜索能力要求較高,同時(shí)又無法修改數(shù)據(jù)庫排序規(guī)則時(shí),可以引入專門的搜索引擎作為中間層,例如
Elasticsearch。
基本思路是:
- MySQL 負(fù)責(zé)事務(wù)型數(shù)據(jù)存儲
- Elasticsearch 負(fù)責(zé)搜索
- 數(shù)據(jù)通過同步機(jī)制寫入 ES
典型架構(gòu)如下:
應(yīng)用服務(wù)
│
├── 寫入 MySQL
│
└── 同步數(shù)據(jù) → Elasticsearch
│
搜索查詢在 Elasticsearch 中可以通過 normalizer 或 analyzer 實(shí)現(xiàn)統(tǒng)一大小寫,例如使用 lowercase filter。
例如字段 mapping:
{
"mappings": {
"properties": {
"name": {
"type": "keyword",
"normalizer": "lowercase"
}
}
}
}這樣在 ES 中:
Peter PETER peter
都會被統(tǒng)一為:
peter
查詢時(shí)即可實(shí)現(xiàn)大小寫不敏感搜索,同時(shí)保持高性能。
優(yōu)點(diǎn)
- 查詢性能高,適合大數(shù)據(jù)量
- 支持復(fù)雜搜索能力(模糊搜索、分詞、全文檢索)
- 不影響原有數(shù)據(jù)庫結(jié)構(gòu)
- 可以支持更多搜索需求
缺點(diǎn)
- 架構(gòu)復(fù)雜度增加
- 需要維護(hù)數(shù)據(jù)同步
- 引入新的基礎(chǔ)設(shè)施
三種方案對比
| 方案 | 是否使用索引 | 改造成本 | 適用場景 |
|---|---|---|---|
LOWER() 函數(shù)查詢 | 否 | 低 | 小數(shù)據(jù)量、臨時(shí)查詢 |
| 生成列 + 索引 | 是 | 中 | 查詢頻繁但無法修改排序規(guī)則 |
| 引入 Elasticsearch | 是 | 高 | 大規(guī)模搜索、復(fù)雜查詢 |
小結(jié)
當(dāng)無法修改數(shù)據(jù)庫排序規(guī)則時(shí),可以考慮三種解決方案:
函數(shù)轉(zhuǎn)換方案:
LOWER(column) = 'value'
實(shí)現(xiàn)簡單,但會導(dǎo)致索引失效。
生成列方案:
GENERATED COLUMN + INDEX
可以保持?jǐn)?shù)據(jù)庫索引性能,但會增加存儲和寫入成本。
搜索中間層方案:
MySQL + Elasticsearch
適合數(shù)據(jù)規(guī)模較大、搜索需求復(fù)雜的系統(tǒng),同時(shí)也能解決大小寫敏感問題。
在實(shí)際系統(tǒng)設(shè)計(jì)中,任何影響性能、推翻架構(gòu)的方法都應(yīng)該謹(jǐn)慎對待,應(yīng)根據(jù)數(shù)據(jù)規(guī)模、查詢復(fù)雜度以及系統(tǒng)架構(gòu)選擇最合適的方案。
數(shù)據(jù)庫規(guī)范與設(shè)計(jì)建議
字符集和排序規(guī)則的選擇,本質(zhì)上屬于 數(shù)據(jù)庫設(shè)計(jì)階段的重要決策。在系統(tǒng)上線并產(chǎn)生大量數(shù)據(jù)之后,再去修改這些基礎(chǔ)屬性往往成本很高,因此在建庫和建表時(shí)應(yīng)盡量提前規(guī)劃。
在數(shù)據(jù)庫設(shè)計(jì)規(guī)范中,一般建議將以下內(nèi)容作為設(shè)計(jì)階段需要確認(rèn)的事項(xiàng):
- 數(shù)據(jù)庫默認(rèn)字符集
- 數(shù)據(jù)庫默認(rèn)排序規(guī)則
- 特殊字段是否需要大小寫敏感
- 唯一索引字段是否受排序規(guī)則影響
- 是否存在跨系統(tǒng)共享數(shù)據(jù)庫的情況
這些規(guī)則一旦確定,上線后不應(yīng)輕易修改。
為什么不建議輕易修改排序規(guī)則或字符集
在生產(chǎn)環(huán)境中修改字符集或排序規(guī)則,通常會帶來以下影響。
可能導(dǎo)致鎖表
很多修改字符集或排序規(guī)則的操作,本質(zhì)上會觸發(fā)表結(jié)構(gòu)重建,例如:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
對于大表來說,該操作可能需要較長時(shí)間,在某些情況下還會導(dǎo)致表級鎖或元數(shù)據(jù)鎖(MDL),影響線上業(yè)務(wù)讀寫。
如果表數(shù)據(jù)達(dá)到百萬、千萬甚至更高規(guī)模,風(fēng)險(xiǎn)會進(jìn)一步放大。
索引需要重建
排序規(guī)則變化會影響字符串的比較方式,因此相關(guān)字段的索引通常需要重新構(gòu)建,例如:
- 普通索引
- 唯一索引
- 聯(lián)合索引
索引重建會帶來額外的 I/O 和 CPU 消耗,在高負(fù)載系統(tǒng)中可能影響整體性能。
可能引發(fā)唯一索引沖突
如果字段從 大小寫敏感 改為 大小寫不敏感,原本合法的數(shù)據(jù)可能會出現(xiàn)沖突。
例如原始數(shù)據(jù):
UserA usera
在 utf8mb4_bin 下是合法的,但在 utf8mb4_unicode_ci 下會被認(rèn)為是同一個(gè)值。
此時(shí)執(zhí)行修改可能出現(xiàn):
Duplicate entry
需要提前清理或合并數(shù)據(jù)。
查詢行為可能發(fā)生變化
排序規(guī)則不僅影響存儲,還會影響查詢結(jié)果。
例如:
SELECT * FROM users WHERE username LIKE 'abc%';
不同排序規(guī)則下結(jié)果不同:
| 排序規(guī)則 | 是否匹配 Abc |
|---|---|
| utf8mb4_bin | 否 |
| utf8mb4_unicode_ci | 是 |
如果直接修改排序規(guī)則,部分業(yè)務(wù)查詢結(jié)果可能發(fā)生變化。
可能導(dǎo)致亂碼或轉(zhuǎn)換失敗
修改字符集時(shí),如果原有數(shù)據(jù)編碼與目標(biāo)字符集不兼容,可能會出現(xiàn)亂碼或轉(zhuǎn)換失敗的問題。
例如:
- 原表使用
latin1 - 數(shù)據(jù)實(shí)際存儲的是 UTF-8 編碼
- 直接修改為
utf8mb4
可能出現(xiàn)以下問題:
- 字符被錯(cuò)誤轉(zhuǎn)換導(dǎo)致亂碼
- 轉(zhuǎn)換過程中出現(xiàn)非法字符
- 修改操作報(bào)錯(cuò)中斷
例如執(zhí)行:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4;
如果數(shù)據(jù)存在非法編碼,可能出現(xiàn)類似錯(cuò)誤:
Incorrect string value
因此在修改字符集前通常需要:
- 確認(rèn)當(dāng)前數(shù)據(jù)真實(shí)編碼
- 備份數(shù)據(jù)
- 在測試環(huán)境驗(yàn)證轉(zhuǎn)換結(jié)果
在復(fù)雜系統(tǒng)中,字符集問題往往不僅涉及數(shù)據(jù)庫,還涉及:
- 應(yīng)用程序編碼
- JDBC / 連接字符串配置
- 數(shù)據(jù)導(dǎo)入導(dǎo)出工具
如果處理不當(dāng),很容易導(dǎo)致系統(tǒng)出現(xiàn)亂碼問題。
多表關(guān)聯(lián)查詢中字符集或排序規(guī)則不同導(dǎo)致索引失效
在多表關(guān)聯(lián)查詢中,如果連接字段(Join Key)的字符集或排序規(guī)則不同,即使兩個(gè)字段都建立了索引,數(shù)據(jù)庫在執(zhí)行查詢時(shí)仍然可能無法使用索引,從而導(dǎo)致全表掃描,嚴(yán)重影響查詢性能。
例如,A 表和 B 表通過 name 字段進(jìn)行關(guān)聯(lián):
SELECT * FROM table_a a JOIN table_b b ON a.name = b.name;
如果兩個(gè)字段的定義如下:
table_a.name VARCHAR(64) COLLATE utf8mb4_bin table_b.name VARCHAR(64) COLLATE utf8mb4_unicode_ci
由于排序規(guī)則不同,數(shù)據(jù)庫在比較字段值時(shí)需要進(jìn)行字符集或排序規(guī)則轉(zhuǎn)換。這種隱式轉(zhuǎn)換會導(dǎo)致優(yōu)化器無法使用已有索引,從而可能出現(xiàn)以下執(zhí)行計(jì)劃:
- 關(guān)聯(lián)字段索引失效
- 使用全表掃描
- 使用臨時(shí)表或 filesort
- 查詢性能明顯下降
在數(shù)據(jù)量較大的系統(tǒng)中,這類問題會顯著放大,特別是在以下場景中:
- 高頻 JOIN 查詢
- 報(bào)表或統(tǒng)計(jì)類查詢
- 分頁查詢
- 多表復(fù)雜關(guān)聯(lián)查詢
在 EXPLAIN 執(zhí)行計(jì)劃中,通常會表現(xiàn)為:
type變?yōu)?ALLpossible_keys存在但key為NULLrows掃描數(shù)量顯著增大
例如:
EXPLAIN SELECT * FROM table_a a JOIN table_b b ON a.name = b.name;
可能出現(xiàn):
| type | key | rows |
|---|---|---|
| ALL | NULL | 1000000 |
說明數(shù)據(jù)庫沒有使用索引,而是執(zhí)行了全表掃描。
為了避免這種情況,數(shù)據(jù)庫設(shè)計(jì)時(shí)應(yīng)遵循以下規(guī)范:
連接字段應(yīng)保持完全一致的定義,包括:
- 字段類型一致(如
VARCHAR(64)) - 字符集一致(如
utf8mb4) - 排序規(guī)則一致(如
utf8mb4_bin) - 長度一致
例如:
table_a.name VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin table_b.name VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin
對于系統(tǒng)中的關(guān)聯(lián)字段,通常建議:
- 使用統(tǒng)一字符集(推薦
utf8mb4) - 使用大小寫敏感排序規(guī)則(如
utf8mb4_bin) - 盡量使用語義明確、結(jié)構(gòu)簡單的字段(例如 ID、編碼或 UUID)
- 避免在 JOIN 條件中進(jìn)行函數(shù)計(jì)算或類型轉(zhuǎn)換
例如以下寫法都會導(dǎo)致索引失效:
ON LOWER(a.name) = b.name
ON a.name = CAST(b.name AS CHAR)
在數(shù)據(jù)庫規(guī)范中,應(yīng)特別強(qiáng)調(diào) 連接字段的結(jié)構(gòu)統(tǒng)一性。一旦系統(tǒng)上線并積累大量數(shù)據(jù),再去修改字符集或排序規(guī)則往往成本較高,因此應(yīng)在設(shè)計(jì)階段就統(tǒng)一規(guī)范。
如果系統(tǒng)已經(jīng)存在字符集不一致的問題,通常需要通過以下方式進(jìn)行治理:
- 統(tǒng)一字段字符集和排序規(guī)則
- 重建相關(guān)索引
- 在新表設(shè)計(jì)時(shí)統(tǒng)一規(guī)范
- 盡量避免使用字符串字段作為關(guān)聯(lián)主鍵
對于高性能系統(tǒng)而言,關(guān)聯(lián)字段優(yōu)先使用數(shù)值型 ID(如 BIGINT) ,既可以避免字符集問題,也能獲得更好的索引效率。
推薦的數(shù)據(jù)庫設(shè)計(jì)規(guī)范
在實(shí)際項(xiàng)目中,可以通過制定數(shù)據(jù)庫規(guī)范來減少后期修改的風(fēng)險(xiǎn)。
推薦的實(shí)踐包括:
數(shù)據(jù)庫默認(rèn)字符集統(tǒng)一使用:
utf8mb4
數(shù)據(jù)庫默認(rèn)排序規(guī)則使用:
utf8mb4_0900_ai_ci
用戶輸入的自然語言字段使用不區(qū)分大小寫的排序規(guī)則,例如:
utf8mb4_0900_ai_ci
技術(shù)標(biāo)識符字段使用大小寫敏感規(guī)則,例如:
utf8mb4_bin
例如:
CREATE TABLE users (
id BIGINT PRIMARY KEY,
username VARCHAR(64) COLLATE utf8mb4_bin,
email VARCHAR(128) COLLATE utf8mb4_0900_ai_ci,
nickname VARCHAR(64) COLLATE utf8mb4_0900_ai_ci,
password_hash VARCHAR(255) COLLATE utf8mb4_bin,
api_key VARCHAR(128) COLLATE utf8mb4_bin
);通過在設(shè)計(jì)階段明確這些規(guī)則,可以避免在系統(tǒng)規(guī)模擴(kuò)大后再進(jìn)行高風(fēng)險(xiǎn)的結(jié)構(gòu)調(diào)整。
小結(jié)
字符集和排序規(guī)則雖然看起來只是數(shù)據(jù)庫的基礎(chǔ)配置,但它們會影響:
- 字符串比較邏輯
- 索引行為
- 查詢結(jié)果
- 系統(tǒng)性能
- 數(shù)據(jù)編碼正確性
因此在數(shù)據(jù)庫設(shè)計(jì)階段就應(yīng)確定好相關(guān)規(guī)范,并在項(xiàng)目中統(tǒng)一執(zhí)行。
一旦系統(tǒng)上線并積累大量數(shù)據(jù),再修改這些屬性往往需要付出較高成本,甚至可能影響線上業(yè)務(wù)穩(wěn)定性。因此應(yīng)盡量在設(shè)計(jì)階段完成規(guī)劃,而不是在生產(chǎn)環(huán)境中頻繁調(diào)整。
總結(jié)
在 MySQL 8 中選擇排序規(guī)則時(shí),核心原則是根據(jù)字段語義進(jìn)行設(shè)計(jì)。排序規(guī)則不僅影響字符串比較,還會影響索引、模糊查詢和唯一約束。
技術(shù)標(biāo)識符字段建議使用大小寫敏感規(guī)則,例如:
utf8mb4_bin
用戶輸入文本建議使用大小寫不敏感規(guī)則,例如:
utf8mb4_0900_ai_ci
數(shù)據(jù)庫默認(rèn)排序規(guī)則建議使用 utf8mb4_0900_ai_ci,并對特殊字段進(jìn)行單獨(dú)配置。
合理的排序規(guī)則設(shè)計(jì)不僅能避免后期遷移問題,也能提升搜索體驗(yàn)和查詢效率。
當(dāng)業(yè)務(wù)需求發(fā)生變化時(shí),可以通過以下方式調(diào)整:
- 修改字段排序規(guī)則
- 新增指定排序規(guī)則字段
- 修改表默認(rèn)排序規(guī)則
- 修改數(shù)據(jù)庫默認(rèn)排序規(guī)則
在生產(chǎn)環(huán)境執(zhí)行這些操作前,應(yīng)提前檢查數(shù)據(jù)沖突和索引影響,以避免業(yè)務(wù)異常。
附錄:不同數(shù)據(jù)規(guī)模修改字符集或排序規(guī)則的維護(hù)成本參考
在實(shí)際生產(chǎn)環(huán)境中,修改字符集或排序規(guī)則通常會觸發(fā)表結(jié)構(gòu)重建,因此會產(chǎn)生明顯的維護(hù)成本。
以下表格是基于常見業(yè)務(wù)環(huán)境(普通 SSD、常規(guī)服務(wù)器配置、在線 DDL 未啟用或不可用)的經(jīng)驗(yàn)估算,僅作為容量規(guī)劃和風(fēng)險(xiǎn)評估參考。
| 表數(shù)據(jù)規(guī)模 | 數(shù)據(jù)量級 | 典型維護(hù)耗時(shí) | 鎖表風(fēng)險(xiǎn) | 建議策略 |
|---|---|---|---|---|
| 小表 | < 10 萬行 | 幾秒 | 幾乎無影響 | 可以直接修改 |
| 中小表 | 10 萬 ~ 100 萬 | 幾秒 ~ 數(shù)十秒 | 低 | 低峰期執(zhí)行 |
| 中型表 | 100 萬 ~ 1000 萬 | 數(shù)十秒 ~ 數(shù)分鐘 | 中 | 需要評估業(yè)務(wù)窗口 |
| 大表 | 1000 萬 ~ 1 億 | 數(shù)分鐘 ~ 數(shù)十分鐘 | 較高 | 建議使用在線 DDL 或影子表遷移 |
| 超大表 | > 1 億 | 數(shù)十分鐘 ~ 數(shù)小時(shí) | 高 | 必須設(shè)計(jì)遷移方案 |
需要注意,實(shí)際耗時(shí)會受到以下因素影響:
- 行數(shù)據(jù)大?。ɡ缡欠癜?TEXT/BLOB 字段)
- 索引數(shù)量
- 磁盤性能(SSD / NVMe / 網(wǎng)絡(luò)存儲)
- MySQL 配置
- 是否使用在線 DDL
- 是否存在并發(fā)寫入
例如執(zhí)行如下操作:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
對于千萬級數(shù)據(jù)表,很可能會觸發(fā)表重建,并在執(zhí)行過程中產(chǎn)生較長時(shí)間的 I/O 壓力。
常見風(fēng)險(xiǎn)
修改字符集或排序規(guī)則時(shí),可能出現(xiàn)以下問題:
| 風(fēng)險(xiǎn)類型 | 說明 |
|---|---|
| 鎖表 | 元數(shù)據(jù)鎖可能阻塞寫入 |
| 索引重建 | 所有相關(guān)索引需要重新構(gòu)建 |
| 查詢性能波動 | 執(zhí)行期間 I/O 壓力上升 |
| 唯一索引沖突 | 大小寫敏感規(guī)則變化導(dǎo)致沖突 |
| 數(shù)據(jù)亂碼 | 原始數(shù)據(jù)編碼與目標(biāo)字符集不一致 |
生產(chǎn)環(huán)境建議
對于數(shù)據(jù)量較大的系統(tǒng),一般建議采用更安全的遷移方式,例如:
- 影子表遷移(Shadow Table)
- 在線 DDL
- 數(shù)據(jù)分批遷移
- 使用中間層同步數(shù)據(jù)
例如通過以下流程進(jìn)行遷移:
1. 創(chuàng)建新表(目標(biāo)字符集) 2. 同步歷史數(shù)據(jù) 3. 同步增量數(shù)據(jù) 4. 切換業(yè)務(wù)讀寫 5. 下線舊表
這種方式雖然步驟較多,但可以顯著降低生產(chǎn)環(huán)境風(fēng)險(xiǎn)。
總體建議
字符集和排序規(guī)則屬于數(shù)據(jù)庫底層設(shè)計(jì),一旦系統(tǒng)進(jìn)入穩(wěn)定運(yùn)行階段,大規(guī)模修改會帶來較高維護(hù)成本。因此在系統(tǒng)設(shè)計(jì)階段,應(yīng)盡量提前規(guī)劃好:
- 默認(rèn)字符集
- 默認(rèn)排序規(guī)則
- 是否需要大小寫敏感字段
通過前期規(guī)范化設(shè)計(jì),可以避免后期在高數(shù)據(jù)量環(huán)境下進(jìn)行高風(fēng)險(xiǎn)的結(jié)構(gòu)調(diào)整。
到此這篇關(guān)于MySQL8中大小寫敏感與不敏感排序規(guī)則的選擇的文章就介紹到這了,更多相關(guān)MySQL8大小寫敏感與不敏感排序規(guī)則內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MYSQL設(shè)置觸發(fā)器權(quán)限問題的解決方法
這篇文章主要介紹了MYSQL設(shè)置觸發(fā)器權(quán)限問題的解決方法,需要的朋友可以參考下2014-09-09
允許遠(yuǎn)程訪問MySQL的實(shí)現(xiàn)方式
這篇文章主要介紹了允許遠(yuǎn)程訪問MySQL的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
MYSQL?Binlog恢復(fù)誤刪數(shù)據(jù)庫詳解
MySQL一旦誤刪數(shù)據(jù)庫之后恢復(fù)數(shù)據(jù)很麻煩,這里記錄一下艱辛的恢復(fù)過程,這篇文章主要給大家介紹了關(guān)于如何利用MySQL的binlog恢復(fù)誤刪數(shù)據(jù)庫的相關(guān)資料,需要的朋友可以參考下2022-11-11
如何使用mysqladmin獲取一個(gè)mysql實(shí)例當(dāng)前的TPS和QPS
這篇文章主要介紹了如何使用mysqladmin這個(gè)工具來獲取一個(gè)mysql實(shí)例當(dāng)前的TPS和QPS,幫助大家更好的管理數(shù)據(jù)庫,感興趣的朋友可以了解下2020-11-11
mysql Community Server 5.7.19安裝指南(詳細(xì))
這篇文章主要介紹了mysql Community Server 5.7.19安裝指南(詳細(xì)),需要的朋友可以參考下2017-10-10
Mysql數(shù)據(jù)庫雙機(jī)熱備難點(diǎn)分析
本文主要給大家介紹了在Mysql數(shù)據(jù)庫雙機(jī)熱備其中的難點(diǎn)分析以及重要環(huán)節(jié)的經(jīng)驗(yàn)心得,需要的朋友收藏分享下吧。2017-12-12

