91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

類型轉換對MySQL選擇索引有什么影響

發布時間:2021-09-15 10:05:49 來源:億速云 閱讀:159 作者:chen 欄目:數據庫

這篇文章主要講解了“類型轉換對MySQL選擇索引有什么影響”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“類型轉換對MySQL選擇索引有什么影響”吧!

遇到了幾例 MySQL 沒用使用預期索引的問題,讀了些文檔之后,發現 MySQL 的類型轉換對索引選擇的影響還真是一個不大不小的坑。

比如有這樣一張 MySQL 表:

CREATE TABLE `indextest` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
`age` tinyint(3) unsigned NOT NULL DEFAULT ’0′,
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`),
KEY `idx_age` (`age`),
KEY `idx_create` (`create_time`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1

name 是一個有索引的 varchar 字段,表內數據是這樣的:

+—-+——–+—–+———————+
| id | name | age | create_time |
+—-+——–+—–+———————+
| 1 | hello | 10 | 2012-02-01 20:00:00 |
| 2 | world | 20 | 2012-02-02 20:00:00 |
| 3 | 111222 | 30 | 2012-02-03 20:00:00 |
| 4 | wow | 40 | 2012-02-04 20:00:00 |
+—-+——–+—–+———————+

使用字符串 ’111222′ 作為參數對 name 字段查詢,Execution Plan 如預期的一樣,會使用 name 字段上的索引 idx_name:

mysql [localhost] {msandbox} (test) > explain select age from
-> indextest where name=’111222′\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: indextest
type: ref
possible_keys: idx_name
key: idx_name
key_len: 13
ref: const
rows: 1
Extra: Using where
1 row in set (0.00 sec)

而使用數字作為參數對 name 字段做查詢時,explain 表明這將是全表掃描:

mysql [localhost] {msandbox} (test) > explain select age from
-> indextest where name=111222\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: indextest
type: ALL
possible_keys: idx_name
key: NULL
key_len: NULL
ref: NULL
rows: 4
Extra: Using where
1 row in set (0.00 sec)

究其原因,是當文本字段與數字進行比較時,由于類型不同,MySQL 需要做隱式類型轉換才能進行比較,結果就如上面的例子所提到的一樣。

MySQL 的文檔 (Type Conversion in Expression Evaluation) 中提到,在做比較時,會按這樣的規則進行必要的類型轉換:

兩個參數至少有一個是 NULL 時,比較的結果也是 NULL,例外是使用 <=> 對兩個 NULL 做比較時會返回 1,這兩種情況都不需要做類型轉換
兩個參數都是字符串,會按照字符串來比較,不做類型轉換
兩個參數都是整數,按照整數來比較,不做類型轉換
十六進制的值和非數字做比較時,會被當做二進制串,和數字做比較時會按下面的規則處理
有一個參數是 TIMESTAMP 或 DATETIME,并且另外一個參數是常量,常量會被轉換為 timestamp
有一個參數是 decimal 類型,如果另外一個參數是 decimal 或者整數,會將整數轉換為 decimal 后進行比較,如果另外一個參數是浮點數,則會把 decimal 轉換為浮點數進行比較
所有其他情況下,兩個參數都會被轉換為浮點數再進行比較
比如:

mysql [localhost] {msandbox} (test) > SELECT &rsquo;18015376320243459&prime; =
-> 18015376320243459;
+&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&ndash;+
| &rsquo;18015376320243459&prime; = 18015376320243459 |
+&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&ndash;+
| 0 |
+&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&ndash;+
1 row in set (0.00 sec)

mysql [localhost] {msandbox} (test) > SELECT &rsquo;18015376320243459&prime; + 0;
+&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;-+
| &rsquo;18015376320243459&prime; + 0 |
+&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;-+
| 1.80153763202435e+16 |
+&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;-+
1 row in set (0.00 sec)
mysql [localhost] {msandbox} (test) > SELECT
-> cast(&rsquo;18015376320243459&prime; as unsigned) = 18015376320243459;
+&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&ndash;+
| cast(&rsquo;18015376320243459&prime; as unsigned) = 18015376320243459 |
+&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&ndash;+
| 1 |
+&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&ndash;+
1 row in set (0.00 sec)

因為浮點數精度(53 bits)問題,并且 MySQL 將字符串轉換為浮點數和將整數轉換為浮點數使用不同的方法,字符串 &rsquo;18015376320243459&prime; 和整數 18015376320243459 相比較就不相等,如果要避免隱式浮點數轉換帶來的精度問題,可以顯式地使用 cast 做類型轉換,將字符串轉換為整數。

按照這些規則,對于上面的例子來說,name 字段的值和查詢參數 &rsquo;111222&prime; 都會被轉換為浮點數才會做比較,而很多文本都能轉換為和 111222 相等的數值,比如 &rsquo;111222&prime;, &rsquo;111222aabb&rsquo;, &lsquo; 111222&prime; 和 &rsquo;11122.2e1&prime;,所以 MySQL 不能有效使用索引,就退化為索引掃描甚至是全表掃描。

而反過來,如果使用一個字符串作為查詢參數,對一個數字字段做比較查詢,MySQL 則是可以有效利用索引的:

mysql [localhost] {msandbox} (test) > explain select name from
-> indextest where age=&rsquo;30&prime;\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: indextest
type: ref
possible_keys: idx_age
key: idx_age
key_len: 1
ref: const
rows: 1
Extra:
1 row in set (0.00 sec)

原因則是,MySQL 可以將查詢參數 &rsquo;30&prime; 轉換為確定的數值 30,之后可以快速地在索引中找到與之相等的數值。

除此之外,使用函數對索引字段做顯式類型轉換或者計算也會使 MySQL 無法使用索引:

mysql [localhost] {msandbox} (test) > explain select name from
-> indextest where cast(age as unsigned)=30\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: indextest
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4
Extra: Using where
1 row in set (0.00 sec)

如上,使用 cast 函數對 age 做顯式的類型轉換,會使索引失效,當然了,在實際的代碼中很少會有這樣的寫法,但類似下面這樣對時間字段做運算的用法就比較多了:

mysql [localhost] {msandbox} (test) > explain select * from
-> indextest where date(create_time)=&rsquo;2012-02-02&prime;\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: indextest
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4
Extra: Using where
1 row in set (0.00 sec)

對于本例的需求,是想查找 create_time 是 2012-02-02 這一天的記錄,用變通的方法,避免在索引字段上做運算就可以有效使用索引了:

mysql [localhost] {msandbox} (test) > explain select * from
-> indextest where create_time between &rsquo;2012-02-02&prime; and &rsquo;2012-02-03&prime;\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: indextest
type: range
possible_keys: idx_create
key: idx_create
key_len: 4
ref: NULL
rows: 1
Extra: Using where
1 row in set (0.00 sec)

感謝各位的閱讀,以上就是“類型轉換對MySQL選擇索引有什么影響”的內容了,經過本文的學習后,相信大家對類型轉換對MySQL選擇索引有什么影響這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

连平县| 娱乐| 金昌市| 南召县| 淳安县| 鹰潭市| 都昌县| 万盛区| 诸暨市| 凤庆县| 扬中市| 阿瓦提县| 广宁县| 成安县| 拉孜县| 鸡西市| 武鸣县| 新闻| 平湖市| 南昌县| 梁平县| 璧山县| 富民县| 遵义市| 绵竹市| 巩义市| 巴南区| 庆云县| 新泰市| 永吉县| 平遥县| 华池县| 保靖县| 阿拉善左旗| 永年县| 双流县| 壶关县| 水城县| 东至县| 山阳县| 崇明县|