一個 MySQL 隱式轉換的坑,差點把服務器整崩潰了( 二 )

order_code字段進行了字符串到整數類型的轉換,而轉換后的結果正好是 1 。
通過 cast函數轉換驗證一下結果 。
select cast('1d90530e-6ada-47c1-b2fa-adba4545aabd' as unsigned);【一個 MySQL 隱式轉換的坑,差點把服務器整崩潰了】

一個 MySQL 隱式轉換的坑,差點把服務器整崩潰了

文章插圖
再用兩條 SQL 看一下字符串到整數類型轉換的規則 。
select cast('223kkk' as unsigned);select cast('k223kkk' as unsigned);
一個 MySQL 隱式轉換的坑,差點把服務器整崩潰了

文章插圖
223kkk轉換后的結果是 223,而k223kkk轉換后的結果是0 ??偨Y一下 , 轉換的規則是:
1、從字符串的左側開始向右轉換,遇到非數字就停止;
2、如果第一個就是非數字,最后的結果就是0;
隱式轉換的規則當操作符與不同類型的操作數一起使用的時候 , 就會發生隱式轉換 。
例如算數運算符的前后是不同類型時,會將非數字類型轉換為數字,比如 '5a'+2,就會將5a轉換為數字類型,然后和2相加,最后的結果就是 7。
一個 MySQL 隱式轉換的坑,差點把服務器整崩潰了

文章插圖
再比如 concat函數是連接兩個字符串的 , 當此函數的參數出現非字符串類型時,就會將其轉換為字符串,例如concat(88,'就是發'),最后的結果就是 88就是發 。
一個 MySQL 隱式轉換的坑,差點把服務器整崩潰了

文章插圖
MySQL 官方文檔有以下幾條關于隱式轉換的規則:
1、兩個參數至少有一個是 NULL 時,比較的結果也是 NULL,例外是使用 <=> 對兩個 NULL 做比較時會返回 1,這兩種情況都不需要做類型轉換;
也就是兩個參數中如果只有一個是NULL,則不管怎么比較結果都是 NULL,而兩個 NULL 的值不管是判斷大于、小于或等于 , 其結果都是1 。
2、兩個參數都是字符串,會按照字符串來比較,不做類型轉換;
3、兩個參數都是整數,按照整數來比較,不做類型轉換;
4、十六進制的值和非數字做比較時,會被當做二進制字符串;
例如下面這條語句,查詢 user 表中name字段是 0x61 的記錄,0x是16進制寫法,其對應的字符串是英文的 'a',也就是它對應的 ASCII 碼 。
select * from user where name = 0x61;所以,上面這條語句其實等同于下面這條
select * from user where name = 'a';可以用 select 0x61;驗證一下 。
5、有一個參數是 TIMESTAMP 或 DATETIME,并且另外一個參數是常量,常量會被轉換為 時間戳;
例如下面這兩條SQL,都是將條件后面的值轉換為時間戳再比較了,只不過
一個 MySQL 隱式轉換的坑,差點把服務器整崩潰了

文章插圖
6、有一個參數是 decimal 類型,如果另外一個參數是 decimal 或者整數,會將整數轉換為 decimal 后進行比較,如果另外一個參數是浮點數(一般默認是 double) , 則會把 decimal 轉換為浮點數進行比較;
在不同的數值類型之間,總是會向精度要求更高的那一個類型轉換,但是有一點要注意,在MySQL 中浮點數的精度只有53 bit , 超過53bit之后的話,如果后面1位是1就進位,如果是0就直接舍棄 。所以超大浮點數在比較的時候其實只是取的近似值 。
7、所有其他情況下,兩個參數都會被轉換為浮點數再進行比較;
如果不符合上面6點規則,則統一轉成浮點數再進行運算
避免進行隱式轉換我們在平時的開發過程中,盡量要避免隱式轉換,因為一旦發生隱式轉換除了會降低性能外,還有很大可能會出現不期望的結果,就像我最開始遇到的那個問題一樣 。
之所以性能會降低,還有一個原因就是讓本來有的索引失效 。
select * from `order` where order_code = 1;order_code 是 varchar 類型,假設我已經在 order_code 上建立了索引,如果是用“=”做查詢條件的話,應該直接命中索引才對 , 查詢速度會很快 。但是,當查詢條件后面的值類型不是 varchar,而是數值類型的話 , MySQL 首先要對 order_code 字段做類型轉換,轉換為數值類型,這時候,之前建的索引也就不會命中,只能走全表掃描,查詢性能指數級下降,搞不好,數據庫直接查崩了 。
這位英俊瀟灑的少年 , 如果覺得還不錯的話,給個推薦可好!

推薦閱讀