1. 程式人生 > 實用技巧 >MySQL Charset & Collation 初步學習總結

MySQL Charset & Collation 初步學習總結

寫在前面: 本文——mysql字符集(character set)和排序規則(collation)的初步總結,源於學習過程中對select length('漢字');的好奇,由於學習階段及時間問題,部分疑問最終沒有很好的解決.暫時不再探究。總結粗糙,理解不精,主要為個人學習過程記錄,方便後期複習,僅供網友參考,歡迎提出見解。

MySQL中字符集(character set )指的是由一對對symbol和encoding的對應關係組成的集合(粗略理解為編碼方式),排序規則(collation )主要用於指明字元間的比較方式。( MySQL includes character set support that enables you to store data
using a variety of character sets and perform comparisons according to a variety of collations. )詳見8.0手冊第10章總述及10.1節。(本文參考手冊皆指官方mysql 8.0手冊)

  1. MySQL 8.0 預設character set(字符集) and collation(排序規則) 是 utf8mb4utf8mb4_0900_ai_ci, 具體來講可以分別指定 :伺服器(server),資料庫(database),表(table),列(column)以及原義字串(character string literal )的character set 和對應的 collation

    • 1.1 檢視MySQL支援的[所有的]character set 和collation
      • show character set ; show collation ; 兩者都可新增限定條件語句:like或where clause
        #character set 可以簡寫為charset;
        手冊10.3.1 節詳細介紹了character set 和 collation 的命名規則
      • 在MySQL中,全部的charset 與collation的資訊都存放在information_schema庫中。除上述方法外,還可進入information_schema庫中檢視CHARACTER_SETS
        與COLLATIONS表
        use information_schema;
        select * from character_sets,collations [where clause];
    • 1.2檢視系統當前設定的各種字符集/排序規則
      show [session ]variables like 'char%'/'collation%';
      select * from performance_schema.session_variables where variable_name like 'character_set_%';
    表1
    • 1.4 collation 的命名規則參見手冊10.3.1節。
  • 1.5可解如下困惑:

    • 1.4.1 select length('張'); mysql > 2
      在此查詢中,漢字'張' 即原義(或譯為常量?)字串(見手冊10.3.6節/下文2),因在查詢時沒有特別指定character set 以及collation ,故為預設值。由表1:character_set_connection | gbk可知,編碼方式為GBK,而GBK編碼使用兩個位元組來標識漢字字元碼,所以上述執行結果為 2 。
      • 1.4.2 use pra ;select legnth(stu_name) from stuinfo where stuid = 1; mysql> 6

        字串' 張三 ' 佔用6個位元組,故單個漢字(字元)佔用3個位元組。可以解釋為:
        • ① 因:建立pra表中的各欄位時,未特意指定編碼型別,故根據手冊10.3.5可知編碼方式應為其所屬的table的編碼型別,使用3.2命令檢視,為預設的utf8b4
        • ② 手冊10.9.1節詳細介紹了utf8b4字符集型別,指明瞭:
          • 在編碼 BMP字元時utf8mb4與utf8/utf8mb3 可以大致等同,每個字元編碼儲存都佔用相同的位元組數(英文字元1個位元組,漢字3個位元組);走出了各種論壇中的不精確表達" utf8mb4儲存漢字佔用4個位元組,utf8mb3佔用3個位元組 " 的思維定勢。
          • 在編碼SMP字元時,utf8mb4才佔用4個位元組(當然,utf8/utf8mb3 不支援儲存SMP字元,這中字符集型別很快會被官方棄用)
          • 兩種型別同時存在時,一般會自動轉化為utf4mb4型別。
          • BMP字元可以粗略理解為常用字元,SMP理解為不常用字元,比如emoj符號。
        • ③ 詳細的各種型別的字元編碼,可參見部落格園:字串,那些事
  1. Character string literal 譯為原義字串,指的是在Query clause 中的字串,脫離於表,與表無關。手冊10.3.6節。

    • 2.1 形式為 [_charset_name]'string' [COLLATE collation_name];

    • 2.2 解釋:The _charset_name expression is formally called an introducer. It tells the parser, “the string that follows uses character set charset_name.”

    • 2.3

    • 2.4 困惑 在系統CMD視窗
      select length('你') ; mysql>2
      select length(_utf8mb4 '你') ; mysql>2
      執行結果不變,通過命令1.3(表1)可看到character_set_connection = gbk ,①可理解,那麼②呢?
      字串'你'之前的 introducer 無效嗎?2.2解釋It tells the parser, “the string that follows   uses character set charset_name.到底什麼意思,中間還涉及什麼過程。

      • 2.4.1 換用了MySQL Client CMD 執行,連線字符集同樣為gbk,執行結果也都為 2 。換用navicat命令列執行,連線字符集變為utf8mb4 (client ,results字符集也都變為utf8mb4),兩條select語句執行結果都變為 3 (第二條的introducer 修改為 _gbk)。
        結論:introducer 對於字串本身沒有影響,還是受character_set_connection或其他變數 影響 (說法不準確)

      • 2.4.2 查閱手冊10.3.8 introducer相關知識:

      An introducer does not change the string to the introducer character set like CONVERT() would do. It does not change the string value, although padding may occur. The introducer is just a signal. (不太理解)
      

      ​ ① 查閱12.11節 Cast Functions and operators 的 convert(expr using transcoding_name)函式 :converts data between different character sets. ,貌似是真正的轉換。

      ​ ② 這不同於introducer中的表述:It does not change the string value, although padding may occur. The introducer is just a signal(它到底是幹嘛的)

      ​ ③ 執行 select length(convert('你' using utf8mb4)); mysql> 3 ,而此時character_set_connection 仍然為gbk
      那麼結合①,到底introducer 到底發揮什麼樣的作用,character_set_connection 發揮什麼樣的作用, ?

      • 2.4.3 檢視手冊10.4節 Connection character set and collation ,該部分涉及到了客戶端與伺服器的互動過程中的編碼轉換過程。

          1. 客戶端與伺服器的互動大致涉及三個變數:character_set_client , character_set_conneciton , character_set_results.
          1. 整體過程可粗略解釋如下,更詳細可參考七把刀簡書博文

          ① 伺服器從客戶端接收以character_set_client 編碼的語句(statements);
          ② 伺服器將接收到的statements 從character_set_client 轉譯(translate/convert)為character_set _connection.
          此處提到:For string literals that have an introducer such as _utf8mb4 or _latin2, the introducer determines the character set. (怎麼determine呢,上面沒感覺determine呀)

          ​ 又提及:collation_connection 對於literal strings 的比較是重要的,對於表列中的字串的比 較無關緊要 。
          ③ server 將執行結果以character_set_results 的編碼形式傳回client

          ④:在七把刀簡書博文中的介紹部分不能理解:指定introducer 後的解釋。

          1. 無法類比當前所糾結的查詢的實際過程。直接的一個函式到達伺服器後是如何執行的。過程中的編碼是如何轉換的。考慮檢視原始碼?
      • 2.4.4 總: 與當下學習任務關聯度不大,在該問題上耗時過長,不再花費時間糾結。粗略結論:①introducer 在整個過程中沒有起到多大作用 ;
        ② convert函式可以實實在在的看到效果;
        ③單獨或一同修改(client,connection,results)並結合三者(無introducer ,有introducer, convert轉換)試驗後,效果迷離,心累,不再探究;
        ④問題關鍵還是沒有理解introducer, 各字符集,以及客戶端與伺服器互動時的編碼轉換過程。日後涉及,在經驗積累的基礎上再行探究。

  2. 分類

    • 3.1 欄位級別

      • 檢視某一 table 所有欄位的詳細資訊(含排序規則collation一列(根據10.3.1中的collation命名規則易知對應的character set))
        show full columns from table_name;
      • 檢視當前選中的資料庫中所有表的資訊(含table_name , Engine, version , create_time , update_time, collation 等)
        show table status [ from databse_name / where name like '%name%'];
      • 修改欄位的charset 和 collation
        alter table table_name modify filed_name field_type field_charset_name;
    • 3.2 表級別

      • 檢視建表語句(最新的,含修改過的 )( 其中包含當前表設定的預設的character set ,collation資訊)
        show create table table_name;

      • 修改表的charset和collation
        alter table table_name charset charset_name;

    • 3.3 資料庫級別

      • 檢視當前資料庫預設的字符集,以及排序規則

        • show variables where variable_name = 'character_set_database'
        • use database_name;
          select @@character_set_database,@@collation_database;
        • select default_character_set_name,default_collation_name
          from information_shema.schemata
          where shcema_name = 'db_name';
          (可能這種方法涉及當前使用者的許可權問題,未查證)
      • 檢視建資料庫語句,從而瞭解當前資料庫預設的字符集,以及排序規則。
        show create database database_name

      • 修改資料庫的character set 和collation
        alter database database_name charset utf8mb4

    • 3.4 伺服器級別

      • 檢視伺服器字符集配置
        show variables where variable_name = 'character_set_server ;'
        也可以簡單使用 show variables like 'char%';
      • 配置 server 的預設charset 和collation (詳細參見10.3.2節)
        • 永久性配置:修改my.ini檔案中的mysqld --character-set-server=utf8mb4 ,重啟MySQL服務。(my.ini檔案一般位於C盤 Program Files或者Programdata Files資料夾下的mysql目錄下)
        • 暫時配置:命令列輸入:set character_set_server= utf8mb4;
        • 手冊中還介紹了cmke 命令。
    • 3.5 檢視**connection , client , results ** 字符集,排序規則
      例如 : select @@character_set_connection,@@collation_connetcion;
      或者: show variables like 'char%' ;

    4.其他

    • 函式 length(),char_length(),character_length() 區別參見手冊12 章 Functions and operators 。

    • 手冊13.7節Database Adminstration Statement 的13.7.6.3 介紹了Set Names Statements.

      • set names('charset_name' [collate 'collation_name'] | default);
      • 該語句將三個session 系統變數 character_set_client , character_set_connection , character_set_results 同時設定為了指定的字符集 charset_name ,collate 語句可選。執行後可使用1.3命令檢視效果。(該設定僅當次會話中有效)
      • 可以使用default值恢復預設對映。預設值取決於伺服器配置
        The default mapping can be restored by using a value of DEFAULT. The default depends on the server configuration
    • 細節及注意點,檢視手冊。部落格set name statements總結詳細,可參考。

總結粗糙,理解不精,日後更新完善。歡迎提出見解。