談?wù)凪ySQL中的隱式轉(zhuǎn)換
工作過程中會遇到比較多關(guān)于隱式轉(zhuǎn)換的案例,隱式轉(zhuǎn)換除了會導(dǎo)致慢查詢,還會導(dǎo)致數(shù)據(jù)不準(zhǔn)。本文通過幾個生產(chǎn)中遇到的案例來。
基礎(chǔ)知識
關(guān)于比較運算的原則,MySQL官方文檔的描述: https://dev.mysql.com/doc/refman/5.6/en/type-conversion.html
如果 判斷符號左右兩邊有一個為NULL,結(jié)果就是null,除非使用安全的等值判斷 <=>
(none) 05:17:16 >select null = null; +-------------+ | null = null | +-------------+ | NULL | +-------------+ 1 row in set (0.00 sec) (none) 05:34:59 >select null <=> null; +---------------+ | null <=> null | +---------------+ | 1 | +---------------+ 1 row in set (0.00 sec) (none) 05:35:51 >select null != 1; +-----------+ | null != 1 | +-----------+ | NULL | +-----------+ 1 row in set (0.00 sec)
如何判斷左右兩邊都是相同類型的,比如都是字符串,則以字符串進行對比。如果是數(shù)字,則以數(shù)字進行比較。
注意 對于比較常見的 字符串與數(shù)字類型的比較的情況,如果字符串字段是索引字段,那么MySQL 無法通過索引進行查找數(shù)據(jù),比如以下例子:
(none) 05:39:42 >select 1='1'; +-------+ | 1='1' | +-------+ | 1 | +-------+ 1 row in set (0.00 sec) (none) 05:39:44 >select 1='1A'; +--------+ | 1='1A' | +--------+ | 1 | +--------+ 1 row in set, 1 warning (0.00 sec) (none) 05:39:47 >select 1='1 '; ##1后有空格 +--------+ | 1='1 ' | +--------+ | 1 | +--------+ 1 row in set (0.00 sec)
MySQL 認(rèn)為數(shù)字1 與'1','1_','1A' 相等,故無法通過索引二分查找準(zhǔn)確定位到具體的值。
Hexadecimal(十六進制)以二進制字符串的方式進行比較。
如何判斷符號左邊是 timestamp 或者datetime類型的,右邊是常量,在比較之前,常量會被轉(zhuǎn)換為時間類型。
隱式轉(zhuǎn)換
字段類型不一樣
In all other cases, the arguments are compared as floating-point (real) numbers.
除了以上的其他類型的比較,系統(tǒng)將字段和參數(shù)轉(zhuǎn)換為浮點型進行比較。使用浮點數(shù)(或轉(zhuǎn)換為浮點數(shù)的值)的比較是近似的,因為這樣的數(shù)字是不精確的??聪旅?個例子
>select '190325171202362933' = 190325171202362931; +-------------------------------------------+ | '190325171202362933' = 190325171202362931 | +-------------------------------------------+ | 1 | +-------------------------------------------+ 1 row in set (0.00 sec) >select '190325171202362936' = 190325171202362931; +-------------------------------------------+ | '190325171202362936' = 190325171202362931 | +-------------------------------------------+ | 1 | +-------------------------------------------+ 1 row in set (0.00 sec)
直觀上不相等的值,做等值判斷之后竟然返回為1。這樣帶來2個問題不能利用索引且結(jié)果數(shù)據(jù)不準(zhǔn)
>select '190325171202362931'+0.0; +--------------------------+ | '190325171202362931'+0.0 | +--------------------------+ | 1.9032517120236294e17 | +--------------------------+ 1 row in set (0.00 sec) >select '190325171202362936'+0.0; +--------------------------+ | '190325171202362936'+0.0 | +--------------------------+ | 1.9032517120236294e17 | +--------------------------+ 1 row in set (0.00 sec)
將上面的值轉(zhuǎn)換為浮點數(shù),都是 1.9032517120236294e17,所以判斷相等時為真,返回True。
in 參數(shù)包含多個類型
具體的案例參考之前的一篇文章MySQL優(yōu)化案例一則 ,where 條件 in 集合里面的數(shù)據(jù)類型不一樣,執(zhí)行計劃未利用到索引
淘寶MySQL月報(http://mysql.taobao.org/monthly/2017/12/06/ )里面有一篇正好和這個一樣的案例,推薦給大家 簡單說,就是在IN的入口有一個判斷, 如果in中的字段類型不兼容, 則認(rèn)為不可使用索引.
而這個arg_types_compatible 的賦值邏輯是:
if (type_cnt == 1) arg_types_compatible = TRUE;
也就是說,當(dāng)IN列表中出現(xiàn)超過一個字段類型時, 就認(rèn)為類型不兼容,從而不能利用索引。
字符集類型不一致
環(huán)境準(zhǔn)備:
CREATE TABLE `t1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `c1` varchar(20) DEFAULT NULL, `c2` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_c1` (`c1`), KEY `idx_c2` (`c2`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; CREATE TABLE `t2` ( `id` int(11) NOT NULL AUTO_INCREMENT, `c1` varchar(20) DEFAULT NULL, `c2` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_c1` (`c1`), KEY `idx_c2` (`c2`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; insert into t1(c1,c2) values('a','a'),('b','b'),('c','c'), ('d','d'),('e','e'); insert into t2(c1,c2) values('a','a'),('b','b'),('c','c'), ('d','d'),('e','e');
測試結(jié)果
小結(jié)
希望通過以上案例,基礎(chǔ)知識介紹,開發(fā)同學(xué)能少走彎路,在開發(fā)編寫sql的階段一定要明確字段的類型,尤其是看起來像數(shù)字類型的id,xxxid,xxxno 這類字段,實際上可能是字符類型。
以上就是談?wù)凪ySQL中的隱式轉(zhuǎn)換的詳細內(nèi)容,更多關(guān)于MySQL 隱式轉(zhuǎn)換的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決MYSQL出現(xiàn)Can''t create/write to file ''/tmp/#sql_5c0_0.MYD''
今天在配置服務(wù)器的時候提示這個問題Can't create/write to file,原來是php.ini中設(shè)置的tmp目錄不存在2013-07-07基于mysql實現(xiàn)group by取各分組最新一條數(shù)據(jù)
這篇文章主要介紹了基于mysql實現(xiàn)group by取各分組最新一條數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-09-09系統(tǒng)高吞吐量下的數(shù)據(jù)庫重復(fù)寫入問題分析解決
這篇文章主要介紹了系統(tǒng)高吞吐量下的數(shù)據(jù)庫重復(fù)寫入問題分析解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-04-04在ubuntu中重置mysql服務(wù)器root密碼的方法
在ubuntu下安裝了mysql 5 server,結(jié)果不知道什么原因,安裝時輸入的root帳號密碼在使用時無論如何都不能通過數(shù)據(jù)庫服務(wù)器的驗證。無奈只有重置mysql的root帳號密碼。查了一下,用了以下方法成功的重置了root帳號密碼2012-10-10CentOS系統(tǒng)中MySQL5.1升級至5.5.36
有相關(guān)測試數(shù)據(jù)說明從5.1到5.5+,MySQL性能會有明顯的提升,具體的需要自己建立測試環(huán)境去實踐下,今天我們就來操作下,并記錄下來升級的具體步驟2017-07-07MySQL對小數(shù)進行四舍五入的操作實現(xiàn)
數(shù)學(xué)函數(shù)是MySQL中常用的一類函數(shù),其主要用于處理數(shù)字,包括整型和浮點數(shù)等等,本文主要介紹了MySQL對小數(shù)進行四舍五入的操作實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2023-08-08