訪問字典is.columns出現(xiàn)大量的警告(字符集相關(guān))

一佣盒、問題描述

最近遇到問題肺樟,版本5.7線上訪問is.columns出現(xiàn)大量的警告,我們進行了模擬逻淌,當然模擬只模擬了一個警告么伯,如下,

image.png

二卡儒、問題分析

從報錯來看其中有字節(jié) \xBA\xC3 也就是0XBAC3無法被解析(這個碼點實際上是GBK的'好'字)田柔,而對于 information_schema.columns的字段COLUMN_COMMENT字符集為UTF8類型,因此實際上就是0XBAC3無法被解析為UTF8字符骨望,下面我將網(wǎng)上找到的UTF8編碼的范圍放出來如下硬爆,


image.png

可以看到不管是任何字節(jié)的UTF8編碼中第一個字節(jié),0xBA都不是其中任何字節(jié)編碼的第一個字節(jié)擎鸠,因此導(dǎo)致了這種報錯缀磕,這個檢測的代碼在函數(shù)field_well_formed_copy_nchars中。報錯的時候?qū)o法解析為UTF8編碼的二進制按照單個字節(jié)進行了輸出劣光,函數(shù)convert_to_printable負責完成這個輸出動作袜蚕,如下,


image.png

也就是我們看到的16進制的(\xBA\xC3 ) 绢涡。當然如果這里的GBK編碼能夠正常的解析為UTF8編碼牲剃,但是實際上它并不是UTF8的編碼的時候就會出現(xiàn)顯示亂碼,而不是報錯雄可。

但是這個報錯一般是在插入數(shù)據(jù)的時候報錯的凿傅,而這里并沒有插入操作,那么我們需要簡單看看在5.7中information_schema.columns到底是什么操作数苫,實際上這個視圖是一個memory表聪舒,當進行查詢的時候其中的數(shù)據(jù)會進行填充,而不是一直保存在那里面的虐急,其可能從frm文件和table share中讀取信息过椎,如果沒有table share就需要打開frm文件獲取了,既然要進行填充就有一個插入的過程戏仓,具體可以參考填充 information_schema.columns表的回調(diào)函數(shù)get_schema_column_record疚宇,也就是在這個插入的過程中進行了字符集編碼的檢測,導(dǎo)致了這個警告赏殃。當然這里我可以猜測當建表的時候?qū)τ赾omment 在5.7中并沒有進行嚴格的編碼檢測敷待,而是直接寫入到了frm文件中。
其次訪問直接information_schema.columns可能伴隨著大量的打開表的過程仁热,可能會對當前的table cache/table share cache等緩存造成沖擊榜揖,我們可以使用where語句過濾掉不需要訪問的表勾哩,減少沖擊的可能。

三举哟、測試方法和可能的原因

這里我們簡單用一個C代碼思劳,輸出以下就可以生成語句了,我們在comment中加入兩個二進制的字符妨猩,并且這兩個字符就是0xBAC3潜叛,實際上是'好'字的GBK編碼,并且這是不能被UTF8直接解析的編碼壶硅,


image.png

image.png

這種情況可能發(fā)生在注釋的編碼不正確威兜,比如注釋給的GBK的編碼,并且set names 為UTF8庐椒,這樣注釋在沒有任何轉(zhuǎn)換的情況下進行了存儲椒舵,也就是GBK編碼當做UTF8編碼進行了存儲,剛好UTF8編碼無法解析這個GBK的編碼约谈,如果這里我們使用GBK 顯示就是發(fā)現(xiàn)這是0xBAC3 實際上是一個好字笔宿。

image.png

四、insert中的類似報錯和8.0的測試

當然這個錯誤并不一定完全在這個場景下棱诱,更多可能是插入場景措伐,比如我們?nèi)缦聹y試,

mysql>  CREATE TABLE `ttname` (
    ->   `name` varchar(20) DEFAULT NULL
    -> ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.11 sec)

mysql> insert into ttname values('去');
ERROR 1366 (HY000): Incorrect string value: '\xE5\x8E\xBB' for column 'name' at row 1

而這里我輸入的是UTF8的去字军俊,其編碼就是0XE58EBB侥加,但是這種漢字是不可能轉(zhuǎn)換為latin1字符集的,雖然latin1為單字節(jié)粪躬,但是在校驗的時候會使用unicode編碼進行校驗担败,這樣就會出現(xiàn)報錯,因為latin1無法解析unicode編碼21435(去字的unicode碼點)镰官,


image.png

上面的案例 8.0中測試提前,發(fā)現(xiàn)有了變化,當建立的時候就會拋出錯誤警告泳唠,并且出現(xiàn)亂碼狈网,代表無法識別comment的字符集。如下笨腥,


image.png

image.png

因此我們在建表等操作的時候一定要注意到comment的字符集是否正確拓哺,建議輸入源的字符集無腦UTF8即可,并且set names中的3個字符集都選用UTF8(UTF8MB4)脖母。

其他

字典信息始終使用utf8進行存儲士鸥,受到set names的影響,比如comment為gbk編碼谆级,那么set names也要使用gbk編碼烤礁,否則會出現(xiàn)不能識別的情況讼积。
同字符集檢測字符是否符合字符集標準,也就是set names和字段的字符集相同
不同字符集轉(zhuǎn)換為unicode然后進行轉(zhuǎn)換脚仔,轉(zhuǎn)換的時候檢測字符集是否符合標準勤众,也就是set names和字段的字符集不同。


set names 更改接口
set_var_collation_client::update
     thd->variables.character_set_client= character_set_client;
     thd->variables.character_set_results= character_set_results;
     thd->variables.collation_connection= collation_connection;
     ->charset_is_system_charset
       分別和
        charset_is_system_charset = String::needs_conversion(0, variables.character_set_client, system_charset_info,&not_used);
        charset_is_collation_connection = !String::needs_conversion(0,variables.character_set_client, variables.collation_connection,&not_used);
        charset_is_character_set_filesystem = !String::needs_conversion(0,variables.character_set_client,variables.character_set_filesystem,&not_used);
     ->

轉(zhuǎn)換關(guān)鍵函數(shù)


field_well_formed_copy_nchars  to_cs  from_cs
   ->well_formed_copy_nchars     to_cs  from_cs
      重點進行轉(zhuǎn)換

my_mb_wc_utf8mb4
my_wc_mb_utf8mb4
my_mb_wc_gbk           就是用來實現(xiàn)講gbk字符轉(zhuǎn)換成unicode字符的函數(shù)
my_wc_mb_gbk           函數(shù)則是用來講unicode字符轉(zhuǎn)換成gbk字符的函數(shù)鲤脏。
push_warning_printf
存儲過程们颜,Default_object_creation_ctx::change_env

----- 其他案例 1

[root@gdb5722 tmp]# more sql2.sql
insert into  testooo1  values('t); //gbk 編碼 好 UTF8顯示錯誤無法復(fù)制

這里是一個好字的GBK編碼。't好t'凑兰。

mysql> set names utf8;
Query OK, 0 rows affected (0.00 sec)

mysql> source /tmp/sql2.sql
ERROR 1366 (HY000): Incorrect string value: '\xBA\xC3t' for column 'name' at row 1
mysql> show create table testooo1 \G
*************************** 1. row ***************************
       Table: testooo1
Create Table: CREATE TABLE `testooo1` (
  `name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> set names gbk
    -> ;
Query OK, 0 rows affected (0.00 sec)

mysql> source /tmp/sql2.sql
Query OK, 1 row affected (0.00 sec)

可以看到當以GBK 當做UTF8 插入到UTF8表中的時候還是要做UTF8編碼的檢測的掌桩,但是‘去’ 字的GBK 卻能插入边锁,因為他是UTF8編碼的姑食,檢測通過


mysql> insert into test.testooo1 values('去');  
Query OK, 1 row affected (0.00 sec)

mysql> select hex(name) from test.testooo1;
+------------+
| hex(name)  |
+------------+
| C8A5       |
+------------+
6 rows in set (0.01 sec)

----- 其他案例 2

comment 如果是GBK編碼那么set names 要設(shè)置為GBK 這樣 轉(zhuǎn)碼能夠成功,
寫入
GBK -> GBK -> UTF8 
輸出
UTF8->GBK ->GBK
或者輸出
UTF8->GBK ->GBK

mysql>  select hex(COLUMN_COMMENT) from information_schema.columns where table_schema='t1' and table_name='test1' \G
*************************** 1. row ***************************
hex(COLUMN_COMMENT): 74E5A5BD74
1 row in set (0.00 sec)

mysql> select COLUMN_COMMENT from information_schema.columns where table_schema='t1' and table_name='test1' \G      
*************************** 1. row ***************************
COLUMN_COMMENT: t好t
1 row in set (0.00 sec)


----- TODO:另外一個案例

5.7/8.0

mysql> show create table tm1123 \G
*************************** 1. row ***************************
       Table: tm1123
Create Table: CREATE TABLE `tm1123` (
  `name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

set names gbk茅坛;

mysql> insert into tm1123(name) values('去');
ERROR 1406 (22001): Data too long for column 'name' at row 1
mysql> show variables like '%char%';
+--------------------------+----------------------------------------+
| Variable_name            | Value                                  |
+--------------------------+----------------------------------------+
| character_set_client     | gbk                                    |
| character_set_connection | gbk                                    |
| character_set_database   | utf8mb4                                |
| character_set_filesystem | binary                                 |
| character_set_results    | gbk                                    |
| character_set_server     | utf8mb4                                |
| character_set_system     | utf8                                   |
| character_sets_dir       | /opt/mysql5740/install/share/charsets/ |
+--------------------------+----------------------------------------+

可能原因音半,講UTF8 當做GBK去解析,UTF8中文3個字節(jié)贡蓖,GBK解析2個字節(jié)后發(fā)現(xiàn)還存在一個字節(jié)曹鸠,因此這個字符過長。

UTF8->GBK->UTF8


#0  my_wc_mb_gbk (cs=0x2c47940 <my_charset_gbk_chinese_ci>, wc=21435, s=0x7fff4c01b071 "def\002t1\006tm1123\006tm1123\004name\004name\f\034", 
    e=0x7fff4c01b077 "\006tm1123\006tm1123\004name\004name\f\034") at /opt/mysql-5.7.40/strings/ctype-gbk.c:10695
#1  0x0000000001da7542 in my_convert_internal (to=0x7fff4c01b071 "def\002t1\006tm1123\006tm1123\004name\004name\f\034", to_length=6, to_cs=0x2c47940 <my_charset_gbk_chinese_ci>, 
    from=0x7fff4c3d581d "", from_length=3, from_cs=0x2cb0ba0 <my_charset_utf8mb4_general_ci>, errors=0x7fff705d7684) at /opt/mysql-5.7.40/strings/ctype.c:1006
#2  0x0000000001da7680 in my_convert (to=0x7fff4c01b071 "def\002t1\006tm1123\006tm1123\004name\004name\f\034", to_length=6, to_cs=0x2c47940 <my_charset_gbk_chinese_ci>, from=0x7fff4c3d581a "去", 
    from_length=3, from_cs=0x2cb0ba0 <my_charset_utf8mb4_general_ci>, errors=0x7fff705d7684) at /opt/mysql-5.7.40/strings/ctype.c:1082
#3  0x0000000000ead792 in copy_and_convert (to=0x7fff4c01b071 "def\002t1\006tm1123\006tm1123\004name\004name\f\034", to_length=6, to_cs=0x2c47940 <my_charset_gbk_chinese_ci>, 
    from=0x7fff4c3d581a "去", from_length=3, from_cs=0x2cb0ba0 <my_charset_utf8mb4_general_ci>, errors=0x7fff705d7684) at /opt/mysql-5.7.40/include/sql_string.h:135
#4  0x000000000143ff1f in Protocol_classic::net_store_data (this=0x7fff4c012c68, from=0x7fff4c3d581a "去", length=3, from_cs=0x2cb0ba0 <my_charset_utf8mb4_general_ci>, 
    to_cs=0x2c47940 <my_charset_gbk_chinese_ci>) at /opt/mysql-5.7.40/sql/protocol_classic.cc:116
#5  0x00000000014425f0 in Protocol_classic::store_string_aux (this=0x7fff4c012c68, from=0x7fff4c3d581a "去", length=3, fromcs=0x2cb0ba0 <my_charset_utf8mb4_general_ci>, 
    tocs=0x2c47940 <my_charset_gbk_chinese_ci>) at /opt/mysql-5.7.40/sql/protocol_classic.cc:1285
#6  0x00000000014427f2 in Protocol_text::store (this=0x7fff4c012c68, from=0x7fff4c3d581a "去", length=3, fromcs=0x2cb0ba0 <my_charset_utf8mb4_general_ci>, 
    tocs=0x2c47940 <my_charset_gbk_chinese_ci>) at /opt/mysql-5.7.40/sql/protocol_classic.cc:1314
#7  0x000000000144482e in Protocol_text::store (this=0x7fff4c012c68, from=0x7fff4c3d581a "去", length=3, cs=0x2cb0ba0 <my_charset_utf8mb4_general_ci>)
    at /opt/mysql-5.7.40/sql/protocol_classic.h:229




最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斥铺,一起剝皮案震驚了整個濱河市彻桃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晾蜘,老刑警劉巖邻眷,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異剔交,居然都是意外死亡肆饶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門岖常,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驯镊,“玉大人,你說我怎么就攤上這事竭鞍“寤螅” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵偎快,是天一觀的道長洒放。 經(jīng)常有香客問我,道長滨砍,這世上最難降的妖魔是什么往湿? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任妖异,我火速辦了婚禮,結(jié)果婚禮上领追,老公的妹妹穿的比我還像新娘他膳。我一直安慰自己,他們只是感情好绒窑,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布棕孙。 她就那樣靜靜地躺著,像睡著了一般些膨。 火紅的嫁衣襯著肌膚如雪蟀俊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天订雾,我揣著相機與錄音肢预,去河邊找鬼。 笑死洼哎,一個胖子當著我的面吹牛烫映,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播噩峦,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼锭沟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了识补?” 一聲冷哼從身側(cè)響起族淮,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凭涂,沒想到半個月后祝辣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡导盅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年较幌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片白翻。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡乍炉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滤馍,到底是詐尸還是另有隱情岛琼,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布巢株,位于F島的核電站槐瑞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏阁苞。R本人自食惡果不足惜困檩,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一祠挫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧悼沿,春花似錦等舔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至义郑,卻和暖如春蝶柿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背非驮。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工交汤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人院尔。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓蜻展,卻偏偏與公主長得像喉誊,于是被迫代替她去往敵國和親邀摆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容