亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > MySQL > 正文

MySQL隱式類型的轉換陷阱和規則

2024-07-24 13:10:45
字體:
來源:轉載
供稿:網友

前言

相信大家都知道隱式類型轉換有無法命中索引的風險,在高并發、大數據量的情況下,命不中索引帶來的后果非常嚴重。將數據庫拖死,繼而整個系統崩潰,對于大規模系統損失慘重。所以下面通過本文來好好學習下MySQL隱式類型的轉換陷阱和規則。

1. 隱式類型轉換實例

今天生產庫上突然出現MySQL線程數告警,IOPS很高,實例會話里面出現許多類似下面的sql:(修改了相關字段和值)

SELECT f_col3_id,f_qq1_id FROM d_dbname.t_tb1 WHERE f_col1_id=1226391 and f_col2_id=1244378 and f_qq1_id in (12345,23456,34567,45678,56789,67890,78901,89012,90123,901231,901232,901233)

用 explain 看了下掃描行數和索引選擇情況:

mysql>explain SELECT f_col3_id,f_qq1_id FROM d_dbname.t_tb1 WHERE f_col1_id=1226391 and f_col2_id=1244378 and f_qq1_id in (12345,23456,34567,45678,56789,67890,78901,89012,90123,901231,901232,901233);+------+---------------+---------+--------+--------------------------------+---------------+------------+--------+--------+------------------------------------+| id | select_type | table | type | possible_keys     | key   | key_len | ref | rows | Extra        |+------+---------------+---------+--------+--------------------------------+---------------+------------+--------+--------+------------------------------------+| 1 | SIMPLE  | t_tb1 | ref | uid_type_frid,idx_corpid_qq1id | uid_type_frid | 8   | const | 1386 | Using index condition; Using where |+------+---------------+---------+--------+--------------------------------+---------------+------------+--------+--------+------------------------------------+共返回 1 行記錄,花費 11.52 ms.

t_tb1 表上有個索引uid_type_frid(f_col2_id,f_type) 、idx_corp_id_qq1id(f_col1_id,f_qq1_id) ,而且如果選擇后者時,f_qq1_id的過濾效果應該很佳,但卻選擇了前者。當使用 hint use index(idx_corp_id_qq1id)時:

mysql>explain extended SELECT f_col3_id,f_qq1_id FROM d_dbname.t_tb1 use index(idx_corpid_qq1id) WHERE f_col1_id=1226391 and f_col2_id=1244378 and f_qq1_id in (12345,23456,34567,45678,56789,67890,78901,89012,90123,901231,901232,901233);+------+---------------+--------+--------+---------------------+------------------+------------+----------+-------------+------------------------------------+| id | select_type | table | type | possible_keys  | key    | key_len | ref  | rows  | Extra        |+------+---------------+--------+--------+---------------------+------------------+------------+----------+-------------+------------------------------------+| 1 | SIMPLE  | t_tb1 | ref | idx_corpid_qq1id | idx_corpid_qq1id | 8   | const | 2375752  | Using index condition; Using where |+---- -+---------------+--------+--------+---------------------+------------------+------------+----------+-------------+------------------------------------+共返回 1 行記錄,花費 17.48 ms.mysql>show warnings;+-----------------+----------------+-----------------------------------------------------------------------------------------------------------------------+| Level   | Code   | Message                            |+-----------------+----------------+-----------------------------------------------------------------------------------------------------------------------+| Warning   |   1739 | Cannot use range access on index 'idx_corpid_qq1id' due to type or collation conversion on field 'f_qq1_id'   || Note   |   1003 | /* select#1 */ select `d_dbname`.`t_tb1`.`f_col3_id` AS `f_col3_id`,`d_dbname`.`t_tb1`.`f_qq1_id` AS `f_qq1_id` from `d_dbname`.`t_tb1` USE INDEX (`idx_corpid_qq1id`) where ||     |    | ((`d_dbname`.`t_tb1`.`f_col2_id` = 1244378) and (`d_dbname`.`t_tb1`.`f_col1_id` = 1226391) and (`d_dbname`.`t_tb1`.`f_qq1_id` in ||     |    | (12345,23456,34567,45678,56789,67890,78901,89012,90123,901231,901232,901233)))          |+-----------------+----------------+-----------------------------------------------------------------------------------------------------------------------+共返回 2 行記錄,花費 10.81 ms.

rows列達到200w行,但問題也發現了:select_type應該是 range 才對,key_len看出來只用到了idx_corpid_qq1id索引的第一列。上面explain使用了 extended,所以show warnings;可以很明確的看到 f_qq1_id 出現了隱式類型轉換:f_qq1_idvarchar,而后面的比較值是整型。

解決該問題就是避免出現隱式類型轉換(implicit type conversion)帶來的不可控:把f_qq1_id in的內容寫成字符串:

mysql>explain SELECT f_col3_id,f_qq1_id FROM d_dbname.t_tb1 WHERE f_col1_id=1226391 and f_col2_id=1244378 and f_qq1_id in ('12345','23456','34567','45678','56789','67890','78901','89012','90123','901231');+-------+---------------+--------+---------+--------------------------------+------------------+-------------+---------+---------+------------------------------------+| id | select_type | table | type | possible_keys     | key    | key_len  | ref  | rows | Extra        |+-------+---------------+--------+---------+--------------------------------+------------------+-------------+---------+---------+------------------------------------+| 1  | SIMPLE  | t_tb1 | range | uid_type_frid,idx_corpid_qq1id | idx_corpid_qq1id | 70   |   | 40  | Using index condition; Using where |+-------+---------------+--------+---------+--------------------------------+------------------+-------------+---------+---------+------------------------------------+共返回 1 行記錄,花費 12.41 ms.

掃描行數從1386減少為40。

類似的還出現過一例:

SELECT count(0) FROM d_dbname.t_tb2 where f_col1_id= '1931231' AND f_phone in(098890);| Warning | 1292 | Truncated incorrect DOUBLE value: '1512-98464356'

優化后直接從掃描rows 100w行降為1。

借這個機會,系統的來看一下mysql中的隱式類型轉換。

2. mysql隱式轉換規則

2.1 規則

下面來分析一下隱式轉換的規則:

     a. 兩個參數至少有一個是 NULL 時,比較的結果也是 NULL,例外是使用 <=> 對兩個 NULL 做比較時會返回 1,這兩種情況都不需要做類型轉換

     b. 兩個參數都是字符串,會按照字符串來比較,不做類型轉換

     c. 兩個參數都是整數,按照整數來比較,不做類型轉換

     d. 十六進制的值和非數字做比較時,會被當做二進制串

     e. 有一個參數是 TIMESTAMP DATETIME,并且另外一個參數是常量,常量會被轉換為 timestamp

     f. 有一個參數是 decimal 類型,如果另外一個參數是 decimal 或者整數,會將整數轉換為 decimal 后進行比較,如果另外一個參數是浮點數,則會把 decimal 轉換為浮點數進行比較

     g. 所有其他情況下,兩個參數都會被轉換為浮點數再進行比較

mysql> select 11 + '11', 11 + 'aa', 'a1' + 'bb', 11 + '0.01a'; +-----------+-----------+-------------+--------------+| 11 + '11' | 11 + 'aa' | 'a1' + 'bb' | 11 + '0.01a' |+-----------+-----------+-------------+--------------+|  22 |  11 |   0 |  11.01 |+-----------+-----------+-------------+--------------+1 row in set, 4 warnings (0.00 sec)mysql> show warnings;+---------+------+-------------------------------------------+| Level | Code | Message         |+---------+------+-------------------------------------------+| Warning | 1292 | Truncated incorrect DOUBLE value: 'aa' || Warning | 1292 | Truncated incorrect DOUBLE value: 'a1' || Warning | 1292 | Truncated incorrect DOUBLE value: 'bb' || Warning | 1292 | Truncated incorrect DOUBLE value: '0.01a' |+---------+------+-------------------------------------------+4 rows in set (0.00 sec)mysql> select '11a' = 11, '11.0' = 11, '11.0' = '11', NULL = 1;+------------+-------------+---------------+----------+| '11a' = 11 | '11.0' = 11 | '11.0' = '11' | NULL = 1 |+------------+-------------+---------------+----------+|   1 |   1 |    0 |  NULL |+------------+-------------+---------------+----------+1 row in set, 1 warning (0.01 sec)

上面可以看出11 + 'aa',由于操作符兩邊的類型不一樣且符合第g條,aa要被轉換成浮點型小數,然而轉換失?。ㄗ帜副唤財啵梢哉J為轉成了 0,整數11被轉成浮點型還是它自己,所以11 + 'aa' = 11。

0.01a轉成double型也是被截斷成0.01,所以11 + '0.01a' = 11.01。

等式比較也說明了這一點,'11a'和'11.0'轉換后都等于 11,這也正是文章開頭實例為什么沒走索引的原因: varchar型的f_qq1_id,轉換成浮點型比較時,等于 12345 的情況有無數種如12345a、12345.b等待,MySQL優化器無法確定索引是否更有效,所以選擇了其它方案。

但并不是只要出現隱式類型轉換,就會引起上面類似的性能問題,最終是要看轉換后能否有效選擇索引。像f_id = '654321' 、f_mtime between '2016-05-01 00:00:00' and '2016-05-04 23:59:59'就不會影響索引選擇,因為前者f_id是整型,即使與后面的字符串型數字轉換成double比較,依然能根據double確定f_id的值,索引依然有效。后者是因為符合第e條,只是右邊的常量做了轉換。

開發人員可能都只要存在這么一個隱式類型轉換的坑,但卻又經常不注意,所以干脆無需記住那么多規則,該什么類型就與什么類型比較。

2.2 隱式類型轉換的安全問題

implicit type conversion 不僅可能引起性能問題,還有可能產生安全問題。

mysql> desc t_account;+-----------+-------------+------+-----+---------+----------------+| Field  | Type  | Null | Key | Default | Extra   |+-----------+-------------+------+-----+---------+----------------+| fid  | int(11)  | NO | PRI | NULL | auto_increment || fname  | varchar(20) | YES |  | NULL |    || fpassword | varchar(50) | YES |  | NULL |    |+-----------+-------------+------+-----+---------+----------------+mysql> select * from t_account;+-----+-----------+-------------+| fid | fname  | fpassword |+-----+-----------+-------------+| 1 | xiaoming | p_xiaoming || 2 | xiaoming1 | p_xiaoming1 |+-----+-----------+-------------+

假如應用前端沒有WAF防護,那么下面的sql很容易注入:

mysql> select * from t_account where fname='A' ;fname傳入 A' OR 1='1 mysql> select * from t_account where fname='A' OR 1='1';

攻擊者更聰明一點: fname傳入 A'+'B ,fpassword傳入 ccc'+0 :

mysql> select * from t_account where fname='A'+'B' and fpassword='ccc'+0;+-----+-----------+-------------+| fid | fname  | fpassword |+-----+-----------+-------------+| 1 | xiaoming | p_xiaoming || 2 | xiaoming1 | p_xiaoming1 |+-----+-----------+-------------+2 rows in set, 7 warnings (0.00 sec)

總結

以上就是為大家總結的MySQL隱式類型的轉換陷阱和規則,希望這篇文章對大家學習或者mysql能有所幫助,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到MYSQL教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
一本一本久久a久久精品牛牛影视| 成人网欧美在线视频| 亚洲一区二区三区香蕉| 色偷偷偷亚洲综合网另类| 91精品综合视频| 国产伦精品一区二区三区精品视频| 亚洲精品成人网| 亚洲成人黄色网址| 日韩综合中文字幕| 91老司机在线| 欧美成人一区二区三区电影| 色偷偷噜噜噜亚洲男人| 亚洲一区二区三区视频播放| www.日韩不卡电影av| 精品中文字幕久久久久久| 亚洲成人av在线播放| 日本高清不卡在线| 成人情趣片在线观看免费| 精品亚洲一区二区三区在线播放| 92国产精品久久久久首页| 国产美女直播视频一区| 草民午夜欧美限制a级福利片| 精品亚洲精品福利线在观看| 九九热精品视频| 欧美日韩成人在线播放| 丝袜亚洲欧美日韩综合| 日本欧美一级片| 97精品视频在线| 成人信息集中地欧美| 日韩女优在线播放| 欧美成人精品激情在线观看| 久久久久久久999精品视频| 亚洲欧美日韩国产中文| 亚洲自拍偷拍在线| 亚洲老司机av| 欧美性猛交xxxx久久久| 日韩av在线电影网| 色噜噜狠狠狠综合曰曰曰| 欧美日韩免费一区| 国产在线999| 91麻豆国产语对白在线观看| 亚洲a在线播放| 日韩精品在线播放| 日韩成人中文字幕| 伊人激情综合网| 欧美日韩综合视频网址| 成人97在线观看视频| 亚洲jizzjizz日本少妇| 91精品视频免费观看| 亚洲人成电影网站色…| 国产女同一区二区| 亚洲无限乱码一二三四麻| 亚洲精品一区二区网址| 欧美精品中文字幕一区| 欧美国产极速在线| 国产亚洲精品久久久| 久久国产精品久久久久久久久久| 国语对白做受69| 国产成人精品免费久久久久| 欧美激情videoshd| 久久69精品久久久久久久电影好| 日韩在线www| 伊人亚洲福利一区二区三区| 一本色道久久综合亚洲精品小说| 精品久久久久久久久久国产| 久久精品国产亚洲| 亚洲jizzjizz日本少妇| 亚洲成人精品久久| 国产精品爱啪在线线免费观看| 热久久视久久精品18亚洲精品| 77777亚洲午夜久久多人| 亚洲精品日韩激情在线电影| 欧美日韩国产精品一区二区不卡中文| 伊人久久综合97精品| 亚洲国产高清自拍| 亚洲欧美一区二区三区久久| 欧美日韩高清区| 国产欧美日韩精品在线观看| 日韩在线观看你懂的| 美日韩丰满少妇在线观看| 永久免费看mv网站入口亚洲| 日韩在线观看av| 91在线视频免费| 97热在线精品视频在线观看| 国产精品69精品一区二区三区| 国产97在线视频| 亚洲福利精品在线| 日韩在线观看你懂的| 国产精品美女网站| 欧美激情中文网| 久久精品国产视频| 岛国精品视频在线播放| 亚洲国产小视频在线观看| 成人国产精品久久久| 精品久久久国产| 精品无码久久久久久国产| 国产精品99免视看9| 久久电影一区二区| 中文字幕国内精品| 黄色成人av网| www.xxxx精品| 97久久久久久| 日日骚av一区| 日韩欧美成人精品| 亚洲午夜未删减在线观看| 精品视频9999| 在线精品国产成人综合| 亚洲精品wwwww| 欧美人在线视频| 国语自产精品视频在线看| 欧美理论电影在线观看| 欧美日韩国产va另类| 亚洲男人天堂久| 欧美激情在线视频二区| 久久精品国产成人精品| 久久久精品欧美| 亚洲无亚洲人成网站77777| 这里只有视频精品| 欧美性受xxxx黑人猛交| 北条麻妃99精品青青久久| 国产精品v日韩精品| 欧美第一淫aaasss性| 亚洲精品视频在线观看视频| 日韩中文字幕国产精品| 亚洲欧洲在线免费| 欧美特黄级在线| 青青在线视频一区二区三区| 91av免费观看91av精品在线| 亚洲精品福利在线| 欧美美最猛性xxxxxx| 欧美大片在线看免费观看| 亚洲老头老太hd| 伊人久久免费视频| 日韩精品高清在线观看| 国产成人一区二| 美女视频黄免费的亚洲男人天堂| 欧美国产日韩一区二区三区| 亚洲一区二区自拍| 成人免费激情视频| 欧美激情视频一区二区三区不卡| 国产精品夜色7777狼人| 久热精品视频在线观看一区| 久久久久久高潮国产精品视| 精品av在线播放| 亚洲人在线观看| 久久亚洲私人国产精品va| 中文字幕日韩在线播放| 国产不卡一区二区在线播放| 亚洲免费成人av电影| 欧美日韩亚洲系列| 亚洲精品久久久久久下一站| 亚洲欧美综合区自拍另类| 欧美噜噜久久久xxx| 欧美一级免费看| 欧美精品做受xxx性少妇| 久久久久久久国产| 岛国av一区二区| 秋霞午夜一区二区| 曰本色欧美视频在线| 亚洲欧洲在线观看| 国内精品久久久久| 中文字幕视频在线免费欧美日韩综合在线看| 成人免费福利视频| 久久乐国产精品|