談談MySQL隱式類型轉換

本文首發於我的微信公衆號《andyqian》, 期待你的關注!

前言

  今天咱們繼續回到MySQL系列文章中,談一談MySQL中隱式類型轉換。(其實我最先知道是在慢SQL優化中知道隱式類型轉換概念的),在說隱式類型轉換以前,首先咱們經過一個實例來看看是怎麼回事。mysql

數據結構

本文中全部的操做,都是基於該數據結構(有興趣的童鞋,能夠實驗):sql

create table t_base_user(   
oid bigint(20) not null primary key auto_increment,  
name varchar(30) null comment "name",  
email varchar(30) null comment "email",  
age int null comment "age",  
telephone varchar(30) null comment "telephone",  
status tinyint(4) null comment "0 無效 1 有效",  
created_at datetime null default now() comment "建立時間",  
updated_at datetime null default now() comment "修改時間"  )

### 新建索引alter table t_base_user add index idx_email(email);
alter table t_base_user add index idx_name(name);
alter table t_base_user add index idx_telephone(telephone);

### 新增記錄: 
INSERT INTO `andyqian`.`t_base_user` (`name`, `email`, `age`, `telephone`, `status`, `created_at`, `updated_at`) 
VALUES ('111111', 'andytohome@gmail.com', '111', '12345678901', '1', now(),now());

引子

  首先咱們基於上述數據結構中,咱們來看看下面這個執行計劃:數據庫

explain select * from t_base_user where telephone=12345678901;安全

執行計劃結果:服務器

細心的童鞋應該已經看出來了,爲何數據結構中已經在telephone字段上新建了idx_telephone索引,而上述語句並無走索引,而是全表掃描。這是爲何呢?帶着這疑問,咱們來看看今天的主角------MySQL隱式類型轉換微信

什麼是隱式類型轉換?

  在MySQL中:數據結構

當操做符與不一樣類型的操做數一塊兒使用時,會發生類型轉換以使操做數兼容。則會發生轉換隱式函數

也就是說,MySQL會根據須要自動將數字轉換爲字符串,將字符串轉換數字。看到這個概念以後,是否是有一種茅塞頓開的感受。哦... 原來在數據結構中telephone字段爲字符串(varchar)類型,而咱們傳的手機號是數字類型。如今咱們將SQL修改下:優化

select * from t_base_user where telephone='12345678901';spa

再看看上述語句的執行計劃:

explain select * from t_base_user where telephone='12345678901';

結果:

從這裏看,如今語句已經走索引了。爲了加深咱們對隱式類型轉換的印象,咱們再多看看幾個隱式類型轉換案例:

案例一: 字符串轉換爲數字

mysql > SELECT 1+'1';

結果:

mysql > 2

案例二: 數字轉換爲字符串

mysql -> SELECT CONCAT(1024,' andyqian');

結果:

'1024,' andyqian';

此時CONCAT(字符拼接)函數就將1024進行了隱式類型轉換。

如何避免隱式類型轉換?

  只有當清楚的知道隱式類型轉換的規則,才能從根本上避免產生隱式類型轉換。MySQL也在官網描述了進行隱式類型轉換的一些規則以下:

1. 隱式類型轉換規則:

  • 若是一個或兩個參數都是NULL,比較的結果是NULL,除了NULL安全的<=>相等比較運算符。對於NULL <=> NULL,結果爲true。不須要轉換

  • 若是比較操做中的兩個參數都是字符串,則將它們做爲字符串進行比較。

  • 若是兩個參數都是整數,則將它們做爲整數進行比較。

  • 若是不與數字進行比較,則將十六進制值視爲二進制字符串

  • 若是其中一個參數是十進制值,則比較取決於另外一個參數。 若是另外一個參數是十進制或整數值,則將參數與十進制值進行比較,若是另外一個參數是浮點值,則將參數與浮點值進行比較

  • 若是其中一個參數是TIMESTAMP或DATETIME列,另外一個參數是常量,則在執行比較以前將常量轉換爲時間戳。

  • 在全部其餘狀況下,參數都是做爲浮點數(實數)比較的。

2. 使用CAST函數顯示轉換
咱們可使用CAST顯示的將類型進行轉換,以下所示:

mysql> SELECT 38.8, CAST(38.8 AS CHAR);

結果:

mysql > 38.8, '38.8'

如上述中:

select * from t_base_user where telephone=cast(12345678901 as char);

查看執行計劃,咱們也能夠看出 

你看,這個時候也走索引了。

3. 類型一致
  這裏說的類型一致,指的是在寫SQL時,參數類型必定要與數據庫中的類型一致,避免產生隱式類型轉換,就如剛纔在文首時,若是多檢查,寫的SQL的參數類型與數據庫中字段類型一致,也就不會不走索引了,你說是否是?

當心隱式類型轉換

  這裏再重申一次,寫SQL時必定要檢查參數類型與數據庫字段類型一致,(若是參數不一致,也要使用CAST函數顯示轉換成一致)不然形成隱式類型轉換,不走索引,後果簡直不堪設想, 在前面《寫會MySQL索引》這篇文章中提到過,不走索引,輕則形成慢查詢,重則形成數據庫服務器CPU100%。唉,說到這裏,不瞞你說,我就吃過很多MySQL隱式類型轉換的虧 ! (如慢查詢) !

小結

  看到這裏,是否是有一種,數據表設計還真不是件容易的事情。須要考慮的因素太多太多了,須要考慮字段類型,索引設計,還有各類約束條件等等。也必定要謹慎謹慎再謹慎!其實換個角度就更容易理解了,你們都知道高樓大廈都是須要一個好的地基的,在數據庫表設計中,前期的表結構設計就是這個地基,其重要性可想而知。

  從後續開始,每篇MySQL文章最後,都推薦一個經常使用且實用的MySQL命令:

今天的命令是:

show full columns from table_name;

做用: 顯示指定表全部列信息

例如:

show full columns from t_base_user;

返回結果以下圖所示:

其中:
Field: 字段名
Type: 該字段類型
Collation: 描述瞭如何對查詢出來的數據進行比較和排序
Null: 是否容許爲空, NO: 不容許,YES 容許
Key: 鍵,例如: 主鍵(PRI), 惟一鍵(UNI) 等
Default: 該字段默認值 Extra: 附加信息如自增主鍵上的(auto_increment)
Privileges: 權限,有select,update等
Comment: 字段註釋

注意: 經過該命令顯示都是建表時的信息,這裏着重強調一下,在數據庫建表時,在每一個字段上, 必定要加註釋,加註釋,加註釋!

最後:  你們今天剁手了嗎? 祝你們晚安!

相關閱讀:

寫會MySQL索引

讀懂MySQL執行計劃

   掃碼關注,一塊兒進步

我的博客: http://www.andyqian.com

相關文章
相關標籤/搜索