一次MySQL的优化之旅

一、问题

有一张数据表,表数据现在200W条左右。表结构如下:

CREATE TABLE `device_desk` ( `id` int(11) NOT NULL AUTO_INCREMENT, `running_number` varchar(45) DEFAULT NULL COMMENT '流水号', `time` timestamp NULL DEFAULT NULL COMMENT '时间', `temperature` double DEFAULT NULL COMMENT '温度', `humidity` double DEFAULT NULL COMMENT '湿度', `body_infrared` int(11) DEFAULT NULL COMMENT '人体红外', `particulate_matter` int(11) DEFAULT NULL COMMENT 'PM2.5', `air_quality` int(11) DEFAULT NULL COMMENT '空气质量', `brightness` int(11) DEFAULT NULL COMMENT '灯光亮度', `device_id` int(11) DEFAULT NULL COMMENT '设备编号', `phone` varchar(45) DEFAULT NULL COMMENT '手机号码', `origin` varchar(100) DEFAULT NULL COMMENT '原始值', `color` varchar(45) DEFAULT NULL COMMENT '颜色(用于自定义备注)', `remark` varchar(45) DEFAULT NULL COMMENT '备注' PRIMARY KEY (`id`), KEY `fk_device_idx` (`device_id`), KEY `index_common_2` (`body_infrared`,`day`,`device_id`,`phone`,`time`), CONSTRAINT `fk_device2` FOREIGN KEY (`device_id`) REFERENCES `device` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=2123065 DEFAULT CHARSET=utf8 COMMENT='桌子数据';

业务:
需要找出手机号码为13800000000,绑定的设备编号为164,在2015年11月26日有人在的时间段。body_infrared字段0表示无人,1、16、17都表示有人。

查询语句为:

select * from device_desk t where t.body_infrared>0 and t.phone='13800000000' and t.device_id=164 and t.time like '2015-11-25%' order by t.time;

得到查询结果所需耗时为83秒。
这里写图片描述

下面我们相办法把这个查询时间尽可能缩短。

二、优化过程

1、使用精确的字段代替*

其实我这里需要获取的只有时间time,备注remark,和颜色color。

select t.time,t.remark,t.color from device_desk t where t.body_infrared>0 and t.phone='13800000000' and t.device_id=164 and t.time like '2015-11-25%' order by t.time;

特别是使用Hibernate作为ORM中间件的朋友,会习惯性地使用HQL获取整表的所有数据,然后部分数据竟然要比获取所有数据要快。

2、优化时间的模糊查询

timestamp 类型的字段可以通过类字符串比较的方式来作为模糊查询的条件。而MySQL对于like %关键字作为查询条件是全表扫描的,则没法使用索引。因为我要查询的是当天(某天)的数据,因为我为这张表增加一个day字段,用于保存每天的日期。

增加day字段:

ALTER TABLE `time_table`.`device_desk` ADD COLUMN `day` VARCHAR(45) NULL COMMENT '日期' AFTER `remark`;

为原有的数据的day字段赋值:

update device_desk t set t.day= DATE_FORMAT(`t`.`time`, '%Y-%m-%d') where t.day is null; 

这个操作涉及数据比较多,执行过程会比较长。

更新查询语句为:

select t.time,t.remark,t.color from device_desk t where t.body_infrared>0 and t.phone='13800000000' and t.device_id=164 and t.day='2015-11-25' order by t.time;

3、建立索引

为数据表增加一个组合索引:

ALTER TABLE `time_table`.`device_desk` ADD INDEX `index_common_2` (`body_infrared` ASC, `day` DESC, `device_id` ASC, `phone` ASC, `time` DESC);

索引建立成功后,执行查询语句的时候发生需要的时间还是很长。
查看一下查询语句的执行过程:

explain select t.time,t.remark,t.color from device_desk t where t.body_infrared>0 and t.phone='13800000000' and t.device_id=164 and t.day='2015-11-25' order by t.time;

结果:
这里写图片描述

这里发现我们的select语句并没有使用到我们建立的索引。
经过一番度娘谷哥后,发现MySQL的where条件中用到大于或者小于时,也是进行全表扫描,是不会使用索引查询的。所以把这个大于查询更换掉就好。

explain select t.time,t.remark,t.color from device_desk t where (t.body_infrared=1 or t.body_infrared=16 or t.body_infrared=17) and t.day= '2015-11-25' and t.device_id=164 and t.phone='13800000000' order by t.time;

这样就使用到我们建立的索引了。

查询效率也得到了大大的改善。

你可能感兴趣的:(mysql,优化,索引,Timestamp,大于小于)