在MySQL中,不要使用「utf8」。使用「utf8mb4」

今天的錯誤:我試圖將一個UTF-8字符串存儲在MariaDB「utf8」編碼的數據庫中,而且引起了一個奇怪的錯誤:
Incorrect string value: ‘\xF0\x9F\x98\x83 <…’ for column ‘summary’ at row 1複製代碼
這是UTF-8客戶端和UTF-8服務器,位於UTF-8數據庫中,具備UTF-8編碼規則。字符串「😃」是有效的UTF-8。
但問題是:MySQL的「 utf8 」 不是UTF-8。
「utf8」編碼僅支持每一個字符三個字節。真正的UTF-8編碼 - 每一個人都使用,包括你 - 每一個字符最多須要四個字節。
MySQL開發人員從未修復過這個bug。他們在 2010年發佈了一個解決方法:一個名爲「 utf8mb4 」 的新字符集。
固然,他們從未公佈過這個(多是由於這個bug太尷尬了)。如今,Web上的指南建議用戶使用「utf8」。全部這些指南都是錯誤的。
簡而言之:
· MySQL的「utf8mb4」表示「UTF-8」。
· MySQL的「utf8」意味着「專有字符編碼」。此編碼不能編碼許多Unicode字符。
我將在這裏作一個完全的陳述:目前使用「utf8」的全部 MySQL和MariaDB用戶實際上應該使用「utf8mb4」。沒有人應該使用「utf8」。

什麼是編碼?什麼是UTF-8?

)。我會縮減它。
Computer(計算機)將文本存儲爲1和0。本段中的第一個字母存儲爲「01000011」,你的計算機顯示爲「C」。你的計算機分兩步選擇「C」:
1. 你的計算機讀取「01000011」並肯定它是數字67.這是由於67被編碼爲「01000011」。
2. 你的計算機在 Unicode 字符集中查找字符編號67 ,而且發現67表示「C」。
當我鍵入「C」時,個人結果發生了一樣的事情:
1. 個人計算機將Unicode字符集中的「C」映射到67。
2. 個人計算機編碼爲 67,向此Web服務器發送「01000011」。
字符集是一個解決的問題。幾乎互聯網上的每一個程序都使用Unicode字符集,由於沒有動機使用另外一個。
但編碼更像是一種判斷。Unicode具備超過一百萬個字符的插槽。(C和「💩」是兩個字符)
最簡單的編碼(utf-32)使每一個字符佔用32位。這很簡單,由於計算機已經把32位的組看成數字處理了不少年,並且他們真的很擅長。但它沒用:這是浪費空間。
UTF-8節省空間。在UTF-8中,像「C」這樣的常見字符佔8位,而像「其餘字符須要16或24位。像這樣的博客文章在UTF-8中佔用的空間比在UTF-32中少四倍。因此加載速度快四倍。
你可能沒有意識到,但咱們的計算機在幕後贊成了UTF-8。若是他們沒有,而後當我輸入
「💩」時,你會看到一堆隨機數據。
MySQL的「utf8」字符集與其餘程序不一致。當他們說「💩」時,它會猶豫。

一點MySQL的歷史

爲何MySQL開發人員使「utf8」無效?咱們能夠經過查看提交日誌來猜想。
MySQL從版本4.1開始支持UTF-8 。那是2003年 - 在今天的UTF-8標準以前,RFC 3629。
之前的UTF-8標準RFC 2279每一個字符最多支持6個字節。MySQL開發人員在2002年3月28日的MySQL 4.1的第一個預發行版本中編寫了RFC 2279 。
而後在9月對MySQL的源代碼進行了一次神祕的,一字節的調整:「UTF8如今只能處理3個字節的序列。」
是誰提交了這個?爲何?我說不出來。MySQL的代碼庫在採用Git時彷佛丟失了舊的做者名稱。(MySQL過去經常使用BitKeeper,就像Linux內核同樣。)2003年9月左右的郵件列表中沒有任何內容能夠解釋這一變化。
但我能夠猜到。
早在2002年,若是用戶能夠保證表中的每一行具備相同的字節數,MySQL就會爲用戶提供速度提高。爲此,用戶會將文本列聲明爲「CHAR」。「CHAR」列始終具備相同的字符數。若是你輸入的字符太少,它會在末尾添加空格; 若是你輸入太多的字符,它會截斷最後的字符。
當MySQL開發人員第一次嘗試使用UTF-8時,每一個字符的後六個字節,他們可能會猶豫不決:一個CHAR(1)列須要六個字節; CHAR(2)列須要12個字節; 等等。
讓咱們明確一點:從未發佈的初始行爲是正確的。它獲得了很好的記錄和普遍採用,任何理解UTF-8的人都會贊成這是正確的。
但顯然,MySQL開發人員(或商人)擔憂一兩個用戶會作兩件事:
1.選擇CHAR列。(CHAR格式如今是遺物。當時,使用CHAR列,MySQL速度更快。直到2005年,它不是。)
2.選擇將這些CHAR列編碼爲「utf8」。
個人猜想是MySQL開發人員打破了他們的「utf8」編碼來幫助這些用戶:1)試圖優化空間和速度的用戶; 2)未能優化速度和空間。
沒人贏。想要速度和空間的用戶使用「utf8」CHAR列仍然是錯誤的,由於那些列仍然比它們原來更大更慢。想要正確性的開發人員使用「utf8」是錯誤的,由於它沒法存儲
「💩」
一旦MySQL發佈了這個無效的字符集,它就永遠沒法解決它:這將迫使每一個用戶重建每一個數據庫。MySQL最終在2010年發佈了UTF-8支持,名稱不一樣:「utf8mb4」。

爲何這麼使人沮喪

很明顯,本週我很沮喪。個人bug很難找到,由於我被「utf8」這個名字所迷惑。並且我不是惟一一個 - 我在網上發現的幾乎全部文章都將「utf8」稱爲UTF-8。
名稱「utf8」始終是錯誤的。這是一個專有的字符集。它創造了新問題,並無解決它要解決的問題。
這是虛假的廣告。
My take-away lessons
1.Database systems have subtle bugs and oddities, and you can avoid a lot of bugs by avoiding database systems.
2.If you need a database, don’t use MySQL or MariaDB. Use PostgreSQL.
3.If you need to use MySQL or MariaDB, never use 「utf8」. Always use 「utf8mb4」 when you want UTF-8. Convert your database now to avoid headaches later.
更多文章歡迎訪問: http://www.apexyun.com
公衆號:銀河系1號
聯繫郵箱:public@space-explore.com
(未經贊成,請勿轉載)
相關文章
相關標籤/搜索