最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL隱式類型的轉(zhuǎn)換陷阱和規(guī)則

 更新時間:2016年09月30日 14:42:20   投稿:daisy  
這篇文章先是通過一個實例給大家講述在MySQL隱式類型的轉(zhuǎn)換時遇到的陷阱,而后給大家介紹了MySQL隱式類型的規(guī)則,對大家操作mysql隱式類型的時候具有一定的參考借鑒價值,下面來一起看看吧。

前言

相信大家都知道隱式類型轉(zhuǎn)換有無法命中索引的風(fēng)險,在高并發(fā)、大數(shù)據(jù)量的情況下,命不中索引帶來的后果非常嚴重。將數(shù)據(jù)庫拖死,繼而整個系統(tǒng)崩潰,對于大規(guī)模系統(tǒng)損失慘重。所以下面通過本文來好好學(xué)習(xí)下MySQL隱式類型的轉(zhuǎn)換陷阱和規(guī)則。

1. 隱式類型轉(zhuǎn)換實例

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

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 看了下掃描行數(shù)和索引選擇情況:

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的過濾效果應(yīng)該很佳,但卻選擇了前者。當(dāng)使用 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行,但問題也發(fā)現(xiàn)了:select_type應(yīng)該是 range 才對,key_len看出來只用到了idx_corpid_qq1id索引的第一列。上面explain使用了 extended,所以show warnings;可以很明確的看到 f_qq1_id 出現(xiàn)了隱式類型轉(zhuǎn)換:f_qq1_idvarchar,而后面的比較值是整型。

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

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.

掃描行數(shù)從1386減少為40。

類似的還出現(xiàn)過一例:

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'

優(yōu)化后直接從掃描rows 100w行降為1。

借這個機會,系統(tǒng)的來看一下mysql中的隱式類型轉(zhuǎn)換。

2. mysql隱式轉(zhuǎn)換規(guī)則

2.1 規(guī)則

下面來分析一下隱式轉(zhuǎn)換的規(guī)則:

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

     b. 兩個參數(shù)都是字符串,會按照字符串來比較,不做類型轉(zhuǎn)換

     c. 兩個參數(shù)都是整數(shù),按照整數(shù)來比較,不做類型轉(zhuǎn)換

     d. 十六進制的值和非數(shù)字做比較時,會被當(dāng)做二進制串

     e. 有一個參數(shù)是 TIMESTAMP DATETIME,并且另外一個參數(shù)是常量,常量會被轉(zhuǎn)換為 timestamp

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

     g. 所有其他情況下,兩個參數(shù)都會被轉(zhuǎn)換為浮點數(shù)再進行比較

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要被轉(zhuǎn)換成浮點型小數(shù),然而轉(zhuǎn)換失?。ㄗ帜副唤財啵梢哉J為轉(zhuǎn)成了 0,整數(shù)11被轉(zhuǎn)成浮點型還是它自己,所以11 + 'aa' = 11。

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

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

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

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

2.2 隱式類型轉(zhuǎn)換的安全問題

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

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 |
+-----+-----------+-------------+

假如應(yīng)用前端沒有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)

總結(jié)

以上就是為大家總結(jié)的MySQL隱式類型的轉(zhuǎn)換陷阱和規(guī)則,希望這篇文章對大家學(xué)習(xí)或者mysql能有所幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • 深入研究mysql中的varchar和limit(容易被忽略的知識)

    深入研究mysql中的varchar和limit(容易被忽略的知識)

    這篇文章主要介紹了深入研究mysql中的varchar和limit(容易被忽略的知識),本文探究了varchar(5)可以存儲多少個漢字、多少個字母數(shù)字和mysql中的limit你真的會用嗎兩個知識點,需要的朋友可以參考下
    2015-03-03
  • MySql 存儲引擎和索引相關(guān)知識總結(jié)

    MySql 存儲引擎和索引相關(guān)知識總結(jié)

    這篇文章主要介紹了MySql 存儲引擎和索引相關(guān)知識總結(jié),文中講解非常細致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • Ubuntu Server 16.04下mysql8.0安裝配置圖文教程

    Ubuntu Server 16.04下mysql8.0安裝配置圖文教程

    這篇文章主要為大家詳細介紹了Ubuntu Server 16.04下mysql8.0安裝配置圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • MySQL?RC事務(wù)隔離的實現(xiàn)原理

    MySQL?RC事務(wù)隔離的實現(xiàn)原理

    這篇文章主要介紹了MySQL?RC事務(wù)隔離的實現(xiàn),Read?Committed,事務(wù)運行期間,只要別的事務(wù)修改數(shù)據(jù)并提交,即可讀到人家修改的數(shù)據(jù),所以會有不可重復(fù)讀、幻讀問題,下文相關(guān)介紹需要的朋友可以參考下
    2022-03-03
  • MySQL5.7.21安裝與密碼圖文配置教程

    MySQL5.7.21安裝與密碼圖文配置教程

    這篇文章主要為大家詳細介紹了MySQL5.7.21安裝與密碼圖文配置教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 關(guān)于mysql調(diào)用新手們常犯的11個錯誤總結(jié)

    關(guān)于mysql調(diào)用新手們常犯的11個錯誤總結(jié)

    對于很多新手們來說,使用PHP可以在短短幾個小時之內(nèi)輕松地寫出具有特定功能的代碼。但是,構(gòu)建一個穩(wěn)定可靠的數(shù)據(jù)庫卻需要花上一些時日和相關(guān)技能。下面這篇文章就來總結(jié)了關(guān)于mysql調(diào)用新手們常犯的十一個錯誤,需要的朋友可以參考學(xué)習(xí)。
    2017-03-03
  • MySQL優(yōu)化之對RAND()的優(yōu)化方法

    MySQL優(yōu)化之對RAND()的優(yōu)化方法

    這篇文章主要介紹了MySQL優(yōu)化之對RAND()的優(yōu)化方法,本文詳細分析了Mysql中對RAND()的幾種優(yōu)化方法,并最終得出一個結(jié)論,需要的朋友可以參考下
    2014-07-07
  • MySQL?Community?Server?8.0.29安裝配置方法圖文教程

    MySQL?Community?Server?8.0.29安裝配置方法圖文教程

    這篇文章主要為大家詳細介紹了MySQL?Community?Server?8.0.29安裝配置方法圖文教程,文中安裝步驟介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • MySQL之FIELD()與ORDER BY()相結(jié)合實現(xiàn)對結(jié)果的自定義排序方式

    MySQL之FIELD()與ORDER BY()相結(jié)合實現(xiàn)對結(jié)果的自定義排序方式

    這篇文章主要介紹了MySQL之FIELD()與ORDER BY()相結(jié)合實現(xiàn)對結(jié)果的自定義排序方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • MySQL使用EXISTS檢查記錄是否存在的詳細過程

    MySQL使用EXISTS檢查記錄是否存在的詳細過程

    EXISTS是SQL中用于檢查子查詢是否返回至少一條記錄的運算符,它通常用于測試是否存在滿足特定條件的記錄,從而在主查詢中進行相應(yīng)操作,本文給大家介紹MySQL使用EXISTS檢查記錄是否存在,感興趣的朋友一起看看吧
    2025-08-08

最新評論

遵义市| 金山区| 舒城县| 临夏县| 吉林省| 常熟市| 东明县| 祥云县| 泽库县| 连山| 广灵县| 云梦县| 韶山市| 仙游县| 丽水市| 海淀区| 武冈市| 太仆寺旗| 吐鲁番市| 尼木县| 平南县| 农安县| 吴堡县| 阿巴嘎旗| 墨江| 洮南市| 遂宁市| 辽宁省| 奉贤区| 桑植县| 正宁县| 惠安县| 齐河县| 浮梁县| 辰溪县| 忻城县| 永宁县| 苍南县| 克东县| 常熟市| 隆化县|