关于cast类型转换后无法使用索引的优化
因为表设计时是各开发人员建立的表,同是建立日期字段add_time,有int,还有varchar(50)几种数据类型,如下:
(字段有删减)
mys
ql> show create table credit_tender;
+--------------------------+------------------------
| Table | Create Table |
+--------------------------+------------------------
| credit_tender | CREATE TABLE `credit_tender` (
`assign_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户名称',
`credit_user_id` int(11) DEFAULT NULL COMMENT '出让人id',
`status` int(2) DEFAULT '0' COMMENT '状态',
`add_time` varchar(50) DEFAULT NULL COMMENT '添加时间',
`addip` varchar(50) DEFAULT NULL COMMENT 'ip',
`client` int(11) DEFAULT NULL COMMENT '客户端',
PRIMARY KEY (`assign_id`),
KEY `user_id` (`user_id`),
KEY `idx_add_time` (`add_time`)
) ENGINE=InnoDB AUTO_INCREMENT=20152 DEFAULT CHARSET=utf8 COMMENT='债权投资表' |
可以看到字段
add_time
varchar(50) DEFAULT NULL COMMENT ‘添加时间’,
有索引:
KEY idx_add_time
(add_time
)
但现在的查询,所有都是使用了以下查询
SELECT * FROM borrow_tender t
WHERE FROM_UNIXTIME(t.addtime,'%Y-%m-%d %H:%i:%s') >= '2018-03-19 00:00:00'
AND FROM_UNIXTIME(t.addtime,'%Y-%m-%d %H:%i:%s') <= '2018-03-19 23:59:59'
查看执行计划如下:
可以看到,有索引,但并没有走索引,还是全表搜索(type:ALL),
mysql> explain SELECT * FROM borrow_tender t
WHERE FROM_UNIXTIME(t.addtime,'%Y-%m-%d %H:%i:%s') >= '2018-03-19 00:00:00'
AND FROM_UNIXTIME(t.addtime,'%Y-%m-%d %H:%i:%s') <= '2018-03-19 23:59:59';
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | tender | ALL | NULL | NULL | NULL | NULL | 664731 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
1 row in set
mysql>
还看到这个表有以下查询条件的,相对于上面的查询,稍有思考,知道转换成相同数据类型进行对比查询:
mysql> explain
SELECT user_id,status,add_time
from credit_tender t
WHERE t.add_time >= cast(unix_timestamp('2018-03-19 00:00:00') as CHAR)
AND t.add_time <= cast(unix_timestamp('2018-03-19 23:59:59') as CHAR);
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
| 1 | SIMPLE | hct | ALL | NULL | NULL | NULL | NULL | 14287 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
1 row in set
但我们看到,还是没走索引,为什么?
cast(unix_timestamp(‘2018-03-19 00:00:00’) as CHAR) 已转换成字串了呀,为什么。
这里是因为char 是定长,而我们的字段类型为 varchar()
所以,这里只要使用以下函数即可
cast(unix_timestamp(‘2018-03-19 00:00:00’) as NCHAR)
mysql> explain
SELECT user_id,status,add_time
from credit_tender hct
WHERE hct.add_time >= cast(unix_timestamp('2018-03-19 00:00:00') as NCHAR)
AND hct.add_time <= cast(unix_timestamp('2018-03-19 23:59:59') as NCHAR);
+----+-------------+-------+-------+---------------+--------------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+--------------+---------+------+------+-----------------------+
| 1 | SIMPLE | hct | range | idx_add_time | idx_add_time | 153 | NULL | 45 | Using index condition |
+----+-------------+-------+-------+---------------+--------------+---------+------+------+-----------------------+
1 row in set
或者使用 CONCAT 函数,隐性转换成字串的方法
mysql> explain
SELECT user_id,status,add_time
from credit_tender hct
WHERE hct.add_time >= CONCAT(unix_timestamp('2018-03-19 00:00:00'),'')
AND hct.add_time <= CONCAT(unix_timestamp('2018-03-19 23:59:59') ,'')
;
+----+-------------+-------+-------+---------------+--------------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+--------------+---------+------+------+-----------------------+
| 1 | SIMPLE | hct | range | idx_add_time | idx_add_time | 153 | NULL | 45 | Using index condition |
+----+-------------+-------+-------+---------------+--------------+---------+------+------+-----------------------+
1 row in set
mysql>