MySQL SQL優化之字符串索引隱式轉換

以前有用戶很不解:SQL語句很是簡單,就是select * from test_1 where user_id=1 這種類型,並且user_id上已經創建索引了,怎麼仍是查詢很慢?mysql

test_1的表結構:sql

CREATE TABLE `test_1` (測試

  `id` int(11) NOT NULL AUTO_INCREMENT,spa

  `user_id` varchar(30) NOT NULL,索引

  `name` varchar(30) DEFAULT NULL,字符串

  PRIMARY KEY (`id`),table

  KEY `idx_user_id` (`user_id`)test

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8select

 

查看執行計劃,能夠看出進行了全表掃描,並無用上user_id的索引。im

mysql> explain select * from test_1 where user_id=1;

+----+-------------+--------+------+---------------+------+---------+------+------+-------------+

| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra       |

+----+-------------+--------+------+---------------+------+---------+------+------+-------------+

|  1 | SIMPLE      | test_1 | ALL  | idx_user_id   | NULL | NULL    | NULL |    3 | Using where |

+----+-------------+--------+------+---------------+------+---------+------+------+-------------+

1 row in set (0.01 sec)

 

仔細看下錶結構,user_id的字段類型:  `user_id` varchar(30) NOT NULL,

而用戶傳入的是int,這裏會有一個隱式轉換的問題。隱式轉換會致使全表掃描。

 

把輸入改爲字符串類型,執行計劃以下,這樣就會很快了。

mysql> explain select * from test_1 where user_id='1';

+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------------+

| id | select_type | table  | type | possible_keys | key         | key_len | ref   | rows | Extra       |

+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------------+

|  1 | SIMPLE      | test_1 | ref  | idx_user_id   | idx_user_id | 92      | const |    1 | Using where |

+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------------+

1 row in set (0.00 sec)

 

此外,還須要注意的是:

數字類型的0001等價於1

字符串的0001和1不等價

 

mysql> select * from test_1;

+----+---------+------+

| id | user_id | name |

+----+---------+------+

|  1 | 0001    | kate |

|  2 | 1101    | Jim  |

|  3 | 1       | Jim  |

+----+---------+------+

3 rows in set (0.01 sec)

 

 

mysql> select * from test_1 where user_id=1;

+----+---------+------+

| id | user_id | name |

+----+---------+------+

|  1 | 0001    | kate |

|  3 | 1       | Jim  |

+----+---------+------+

2 rows in set (0.00 sec)

 

mysql> select * from test_1 where user_id='1';

+----+---------+------+

| id | user_id | name |

+----+---------+------+

|  3 | 1       | Jim  |

+----+---------+------+

1 row in set (0.00 sec)

 

若是表定義的是int字段,傳入的是字符串,則不會發生隱式轉換。

看下面的測試:

CREATE TABLE `test_2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`name` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

 

mysql> explain select * from test_2 where user_id=1;
+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+
| 1 | SIMPLE | test_2 | ref | idx_user_id | idx_user_id | 4 | const | 2 | |
+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+
1 row in set (0.00 sec)

mysql> explain select * from test_2 where user_id='1';+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+| 1 | SIMPLE | test_2 | ref | idx_user_id | idx_user_id | 4 | const | 2 | |+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+1 row in set (0.00 sec)

相關文章
相關標籤/搜索