日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql 各表charset不同_MySQL表字段字符集不同导致的索引失效问题

發布時間:2024/8/5 数据库 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 各表charset不同_MySQL表字段字符集不同导致的索引失效问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 概述

昨天在一位同學的MySQL機器上面發現了這樣一個問題,MySQL兩張表做left join時,執行計劃里面顯示有一張表使用了全表掃描,掃描全表近100萬行記錄,大并發的這樣的SQL過來數據庫變得幾乎不可用了,今天和大家一起分享下這個問題的原因及解決辦法,希望可以幫助大家更好的學習MySQL數據庫,一起來看看吧。MySQL版本為官方5.7.13。

2. 問題重現

首先創建表:

插入測試數據:

2張表left join的執行計劃如下:

可以明顯地看到,t2.name = 'dddd'使用了索引,而t1.code = t2.code這個關聯條件沒有使用到t1.code上面的索引,一開始Scott也百思不得其解,但是機器不會騙人。Scott用show warnings查看改寫后的執行計劃如下:

在發現了convert(testdb.t1.code using utf8mb4)之后,Scott發現2個表的字符集不一樣。t1為utf8,t2為utf8mb4。但是為什么表字符集不一樣(實際是字段字符集不一樣)就會導致t1全表掃描呢?下面來做分析。

(1)首先t2 left join t1決定了t2是驅動表,這一步相當于執行了select * from t2 where t2.name = ‘dddd’,取出code字段的值,這里為’8a77a32a7e0825f7c8634226105c42e5’;

(2)然后拿t2查到的code的值根據join條件去t1里面查找,這一步就相當于執行了select * from t1 where t1.code = ‘8a77a32a7e0825f7c8634226105c42e5’;

(3)但是由于第(1)步里面t2表取出的code字段是utf8mb4字符集,而t1表里面的code是utf8字符集,這里需要做字符集轉換,字符集轉換遵循由小到大的原則,因為utf8mb4是utf8的超集,所以這里把utf8轉換成utf8mb4,即把t1.code轉換成utf8mb4字符集,轉換了之后,由于t1.code上面的索引仍然是utf8字符集,所以這個索引就被執行計劃忽略了,然后t1表只能選擇全表掃描。更糟糕的是,如果t2篩選出來的記錄不止1條,那么t1就會被全表掃描多次,性能之差可想而知。

3. 問題解決

既然原因已經清楚了,如何解決呢?當然是改字符集了,把t1改成和t2一樣或者把t2改成t1都可以,這里選擇把t1轉成utf8mb4。那怎么轉字符集呢?

有的同學會說用alter table t1 charset utf8mb4;但這是錯的,這只是改了表的默認字符集,即新的字段才會使用utf8mb4,已經存在的字段仍然是utf8。

只有用alter table t1 convert to charset utf8mb4;才是正確的。

但是還要注意一點,alter table 改字符集的操作是阻塞寫的(用lock = node會報錯)所以業務高峰時請不要操作,即使在業務低峰時期,大表的操作仍然建議使用pt-online-schema-change在線修改字符集。

mysql> alter table t1 convert to charset utf8mb4, lock=none;

ERROR 1846 (0A000): LOCK=NONE is not supported. Reason: Cannot change column type INPLACE. Try LOCK=SHARED.

現在再來查看執行計劃,可以看到已經沒問題了。

4. 注意點

(1)表字符集不同時,可能導致join的SQL使用不到索引,引起嚴重的性能問題;

(2)SQL上線前要做好SQL Review工作,盡量在和生產環境一樣的環境下Review;

(3)改字符集的alter table操作會阻塞寫,盡量在業務低峰操作,建議用pt-online-schema-change;

(4)表結構字符集要保持一致,發布時要做好審核工作;

(5)如果要大批量修改表的字符集,同樣做好SQL的Review工作,關聯的表的字符集一起做修改。

5. 問題討論

最后問一個問題,假設現在t1和t2表的字符集還未修改,如果上面那個問題SQL換成如下(即把t2 left join t1換成t1 left join t2),還會出現索引失效問題嗎?為什么?

select * from t1 join t2 on t1.code = t2.code where t1.name = 'dddd'

參考文章:InsideMySQL

總結

以上是生活随笔為你收集整理的mysql 各表charset不同_MySQL表字段字符集不同导致的索引失效问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。