<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文來自於我近期工作中遇到的一個真實問題,稍作整理後分享給大家~
一張使用者表,其中 phone 新增了普通索引:
CREATE TABLE users ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID', name varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名稱', phone varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '手機', created_at timestamp NOT NULL DEFAULT '1970-01-01 16:00:00' COMMENT '建立時間', updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間', PRIMARY KEY (id), KEY idx_phone (phone) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='使用者表';
分別執行以下 SQL:
EXPLAIN SELECT * FROM users WHERE phone = '2';
執行計劃如下:
EXPLAIN SELECT * FROM users WHERE phone = 2;
執行計劃如下:
發現問題:
當索引欄位 `phone
` 為字串型別時,字串查詢時候使用了索引`idx_phone
`,而數值型別查詢時候竟無法使用索引`idx_phone
`。
假如索引欄位為整型的話,那用字串查詢時會不會走索引呢?
實踐出真知,我們來驗證一下。
同樣如上表,修改欄位 `phone` 型別由 varchar 變更為 bigint:
ALTER TABLE users MODIFY COLUMN phone bigint(16) NOT NULL COMMENT '手機';
然後,分別執行以下 SQL:
1、字串型別查詢
EXPLAIN SELECT * FROM users WHERE phone = '2';
執行計劃如下:
2、數值型查詢
EXPLAIN SELECT * FROM users WHERE phone = 2;
執行計劃如下:
執行後發現,無論是以字串查詢還是以數值型查詢都會用到索引。
小結:
為什麼會是這樣呢?其根源就是 MySQL 的隱式型別轉換。
在 MySQL 中,當操作符與不同型別的運算元一起使用時,會發生型別轉換以使運算元相容,則會發生隱式型別轉換。
即 MySQL 會根據需要自動將數位轉換為字串,或者將字串轉換為數位。
mysql> SELECT 1+'1'; -> 2 mysql> SELECT CONCAT(2,' test'); -> '2 test'
很明顯,上面的 SQL 語句的執行過程中就出現了隱式轉化。
從結果我們可以判定,SQL1 中將字串的“1”轉換為數位 1,而在 SQL2 中,將數位 2 轉換為字串“2”。
只有當清楚的知道隱式型別轉換的規則,才能從根本上避免產生隱式型別轉換。
參考 MySQL 檔案相關描述,確定隱式型別轉換規則:
1、兩個引數至少有一個是 NULL 時,比較的結果也是 NULL,例外是使用 <=> 對兩個 NULL 做比較時會返回 1,這兩種情況都不需要做型別轉換
2、兩個引數都是字串,會按照字串來比較,不做型別轉換
3、兩個引數都是整數,按照整數來比較,不做型別轉換
4、十六進位制的值和非數位做比較時,會被當做二進位制串
5、有一個引數是 TIMESTAMP 或 DATETIME,並且另外一個引數是常數,常數會被轉換為 timestamp
6、有一個引數是 decimal 型別,如果另外一個引數是 decimal 或者整數,會將整數轉換為 decimal 後進行比較,如果另外一個引數是浮點數,則會把 decimal 轉換為浮點數進行比較
7、所有其他情況下,兩個引數都會被轉換為浮點數再進行比較
驗證範例:
mysql> SELECT 'aa' + 1; -> '1' mysql> show warnings; +---------+------+----------------------------------------+ | Level | Code | Message | +---------+------+----------------------------------------+ | Warning | 1292 | Truncated incorrect DOUBLE value: 'aa' | +---------+------+----------------------------------------+
上述範例中,將字串 'aa' 和 1 進行求和,因為 'aa' 和數位 1 的型別不同,通過上述轉換規則並且經檢視 warnings 可以確認:隱式型別轉化將字串轉為了 double 型別。
由於字串是非數位型的,所以就會被轉換為 0,因此計算結果:0+1=1
MySQL 對資料進行型別轉換,提供了 cast() 和 convert()。
相同點:兩者都是進行資料型別轉換,實現的功能基本等同
不同點:兩者的語法不同:cast(value as type) 、 convert(value,type)
將數值型轉換為字串型,應用範例如下:
mysql> SELECT CAST(123 as char); -> '123' mysql> SELECT CONVERT(123, char); -> '123'
假如應用在開篇描述問題的查詢中,則如下所示:
EXPLAIN SELECT * FROM users WHERE phone = CAST(123 AS CHAR);
結果所示:
結果顯示同應用字串型別引數一樣,可使用索引`idx_phone
`。
最簡單的一種,保證查詢應用規範,SQL 引數型別與資料庫中欄位型別保持一致即可。
另外,關於字串型別轉換的一些補充:
mysql> select '1a2b3c' = 1; -> 1 mysql> select 'a1b2c3' = 0; -> 1
從上面的例子可以得出:
本文主要從問題入手,繼而進行問題引申,最終挖掘出問題根源:MySQL 隱式型別轉換。
同時也告誡我們日常在寫 SQL 時一定要檢查引數型別與資料庫欄位型別是否一致,否則可能造成隱式型別轉換,不能正常應用索引,造成慢查詢,甚至拖垮整個資料庫服務叢集。
如果引數不一致,也可以考慮使用 CAST 函數顯性轉換成一致型別。
資料表設計及應用絕非易事,需要考慮的因素太多了,大家應用過程注意保持敬畏心。
以上就是詳解隱祕的 MySQL 型別轉換問題詳解的詳細內容,更多關於MySQL 型別轉換的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45