mysql 数值 字符 优化,教你如何进行Mysql数据类型优化
1. 版本
1)操作系統(tǒng)版本
cat /proc/version
Linux version 3.10.0-957.5.1.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) ) #1
2)數(shù)據(jù)庫版本
mysql --version
mysql? Ver 14.14 Distrib 5.7.22, for linux-glibc2.12 (x86_64) using? EditLine wrapper
2. 問題描述
2.1 問題發(fā)現(xiàn)
這是一個朋友跟我咨詢的問題,幫他分析解決這個問題中,我發(fā)現(xiàn)這個問題也正好有效的印證了我們常說的mysql 數(shù)據(jù)類型優(yōu)化原則,既選擇更小的數(shù)據(jù)類型(在滿足業(yè)務(wù)使用的情況下)。在此拿出來跟大家分享一下。他的問題如下:
他在兩張表上進行關(guān)聯(lián)查詢,如果兩張表都是utf8 字符集那么查詢會很快。如果兩張表是utf8mb4字符集那么查詢就比較慢。
下面建兩張測試表,來重現(xiàn)朋友當(dāng)時的現(xiàn)象
1. 創(chuàng)建兩張字符集為 utf8 的表
create table test_join_1(id int,name varchar(250)) default character set utf8;
create table test_join_2(id int,name varchar(250)) default character set utf8;
2. 查看sql 的執(zhí)行計劃
#這里該sql寫的是否有優(yōu)化空間,不在我們本次討論范圍
explain select a.* ,b.id from `test_join_1` a left join(SELECT name, min(id) id from `test_join_2` b? group by name) b? on a.name=b.name;
explain select a.* ,b.id from `test_join_1` a left join(SELECT name, min(id) id from `test_join_2` b? group by name) b? on a.name=b.name;
| id | select_type | table? ? ? | partitions | type | possible_keys | key? ? ? ? ?| key_len | ref? ? ? ? ? ? ? | rows | filtered | Extra? ? ? ? ? ? ? ? ? ? ? ? ? ?|
|? 1 | PRIMARY? ? ?| a? ? ? ? ? | NULL? ? ? ?| ALL? | NULL? ? ? ? ? | NULL? ? ? ? | NULL? ? | NULL? ? ? ? ? ? ?|? ? 1 |? ?100.00 | NULL? ? ? ? ? ? ? ? ? ? ? ? ? ? |
|? 1 | PRIMARY? ? ?| | NULL? ? ? ?| ref? | ? ?| | 753? ? ?| test_chen.a.name |? ? 2 |? ?100.00 | NULL? ? ? ? ? ? ? ? ? ? ? ? ? ? |
|? 2 | DERIVED? ? ?| b? ? ? ? ? | NULL? ? ? ?| ALL? | NULL? ? ? ? ? | NULL? ? ? ? | NULL? ? | NULL? ? ? ? ? ? ?|? ? 1 |? ?100.00 | Using temporary; Using filesort |
3 rows in set, 1 warning (0.00 sec)
3. 轉(zhuǎn)換表的字符集為 utf8mb4
#注意 utf8 字符集轉(zhuǎn)換成 utf8mb4不會有問題,當(dāng)時 utf8mb4 向 utf8 轉(zhuǎn)換不能保證沒有問題
ALTER TABLE test_join_1 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
ALTER TABLE test_join_2 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
4. 轉(zhuǎn)換字符集后再次查看sql 的執(zhí)行計劃
explain select a.* ,b.id from `test_join_1` a left join?(SELECT name, min(id) id from `test_join_2` b? group by name) b? on a.name=b.name;
| id | select_type | table? ? ? | partitions | type | possible_keys | key? | key_len | ref? | rows | filtered | Extra? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
|? 1 | PRIMARY? ? ?| a? ? ? ? ? | NULL? ? ? ?| ALL? | NULL? ? ? ? ? | NULL | NULL? ? | NULL |? ? 1 |? ?100.00 | NULL? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
|? 1 | PRIMARY? ? ?| | NULL? ? ? ?| ALL? | NULL? ? ? ? ? | NULL | NULL? ? | NULL |? ? 2 |? ?100.00 | Using where; Using join buffer (Block Nested Loop) |
|? 2 | DERIVED? ? ?| b? ? ? ? ? | NULL? ? ? ?| ALL? | NULL? ? ? ? ? | NULL | NULL? ? | NULL |? ? 1 |? ?100.00 | Using temporary; Using filesort? ? ? ? ? ? ? ? ? ? |
3 rows in set, 1 warning (0.00 sec)
##在使用 utf8 字符集時,mysql 為派生表創(chuàng)建了一個索引(auto_key0),這樣a表和派生表之間使用 index Nested-Loop Join(NLJ) 方式關(guān)聯(lián)。在使用 utf8mb4 字符集時 Mysql 使用 Block Nested-Loop Join(BNL) 方式進行關(guān)聯(lián)。NLJ 比 BNL 訪問方式更高效。
通過分析執(zhí)行計劃,相同數(shù)據(jù)的情況下,第一次執(zhí)行會比第二次執(zhí)行更高效,這也符合朋友生產(chǎn)中產(chǎn)生的現(xiàn)象。但是問題是為什么使用 utf8字符集時,會給派生表創(chuàng)建索引,使用utf8mb4時就不會呢?
其實原因很簡單,代價,mysql 會計算給派生表name列索引的長度(派生表name列長度使用b表中name列長度),b表name列 為 varchar(250),在utf8和utf8mb4 字符集下計算出的索引長度分別為 753(utf8 字符集最多使用3個字節(jié)表示一個字符,同時 name 列允許為 null,并且是可變長度類型,所以key_len=250*3+1+2=753) 和 1003(utf8mb4 字符集最多使用4個字節(jié)表示一個字符,同時name列允許為null,并且是可變長度類型,所以key_len=250*4+1+2=1003)
對于 key_len 超過 1000 的列mysql不會為派生表創(chuàng)建 ,這也告訴我們,不要隨意設(shè)置列的長度,在滿足業(yè)務(wù)的情況下,列的長度是越小越好。
2.2 問題原因
在不同的字符集下,mysql 對同一個列創(chuàng)建創(chuàng)建索引的長度是不一樣的,當(dāng)mysql計算在該列上創(chuàng)建索引的長度超過1000的話,就不會對派生表創(chuàng)建索引。
關(guān)于索引長度具體怎么計算下次會分享。
2.3 問題處理
按照規(guī)范設(shè)計和使用數(shù)據(jù)庫。
MySQL 應(yīng)該使用更小的數(shù)據(jù)類型(在滿足業(yè)務(wù)的情況下),理由如下:
1)更小的數(shù)據(jù)類型可能占用的磁盤空間更小,相同的內(nèi)存空間可以緩存更多的記錄,減少IO操作,減少磁盤空間占用
2)更小的數(shù)據(jù)類型意味著CPU可以更快的進行計算。
3)最主要的是,在數(shù)據(jù)庫執(zhí)行過程中MySQL有時會建立一些臨時表進行連接排序或去重操作,在這些臨時表中列的長度跟源表中列的長度一致,列的長度越大,性能也就越不好。所以列的類型盡可能的小。
總結(jié)
以上是生活随笔為你收集整理的mysql 数值 字符 优化,教你如何进行Mysql数据类型优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java中哪个是main函数的合法参数,
- 下一篇: php发送sql,php发送Sql语句遇