记录一次一对多查询优化
第一张表 cs_user,用户表,假设数据有300+条
CREATE TABLE `cs_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`code` text NOT NULL,
`openid` text NOT NULL,
`nickname` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '名称',
`city` varchar(255) NOT NULL COMMENT '市',
`province` varchar(255) NOT NULL COMMENT '省',
`country` varchar(255) NOT NULL COMMENT '国家',
`headimgurl` text NOT NULL COMMENT '头像',
`subscribe_time` int(11) NOT NULL,
`u_time` int(11) NOT NULL,
`l_time` int(11) NOT NULL,
`remark` varchar(100) DEFAULT NULL COMMENT '备注名',
`user_group` varchar(255) DEFAULT NULL COMMENT '隶属于标签',
`license_plate` varchar(255) NOT NULL COMMENT '车牌号',
`subscribe` int(255) NOT NULL COMMENT '是否订阅公众号,值为0时没有关注',
`sex` int(11) NOT NULL COMMENT '性别,值为1男性,值为2女性,值为0时未知',
`status` int(11) NOT NULL DEFAULT '0' COMMENT '是否被绑定',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=242 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
第二张表 cs_template,通知模板表,假设数据有30000+条
CREATE TABLE `cs_template` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`o_rder` varchar(255) NOT NULL COMMENT '订单号',
`car_time` int(11) NOT NULL COMMENT '用车时间',
`car_faa` varchar(255) NOT NULL COMMENT '车费',
`conner` text NOT NULL COMMENT '行程',
`other_party` varchar(255) NOT NULL COMMENT '客户',
`other_ismobile` varchar(255) NOT NULL COMMENT '客户联系方式',
`admin_user` varchar(255) NOT NULL COMMENT '计调管理员id',
`admin_user_name` varchar(255) NOT NULL COMMENT '计调姓名',
`admin_ismobile` varchar(255) NOT NULL COMMENT '计调联系方式',
`bottom_title` varchar(50) NOT NULL COMMENT '底标题',
`openid` varchar(50) NOT NULL COMMENT '收信人openid',
`examine` int(11) NOT NULL DEFAULT '3' COMMENT '0审核,1通过,2不通过,3无审核',
`c_time` int(11) NOT NULL COMMENT '申请时间',
`l_time` int(11) NOT NULL DEFAULT '0' COMMENT '0未发送,时间戳则发送时间,1未发送成功',
`us_title` text NOT NULL COMMENT '创建人',
`template_id` text NOT NULL COMMENT '模板id',
`tem_id` int(11) NOT NULL COMMENT '记录ID',
`x_time` int(11) NOT NULL COMMENT '修改时间',
`admin_id` text NOT NULL COMMENT '审核人',
`admin_title` varchar(11) NOT NULL COMMENT '审核人姓名',
`cancellation` int(3) NOT NULL DEFAULT '0' COMMENT '0启用订单,1取消订单',
`us_id` int(11) NOT NULL COMMENT '创建人id',
`state` int(113) NOT NULL DEFAULT '0' COMMENT '收信人0未读,1已读',
`openid_remark` varchar(32) NOT NULL COMMENT '收信人姓名',
`good_id` int(11) NOT NULL COMMENT '几座',
`message_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '司机确认信息时间',
`reviewer` varchar(45) DEFAULT NULL COMMENT '复核人',
`review_time` bigint(15) DEFAULT NULL COMMENT '复核确认时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=33352 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
表一为用户表,表二为通知表,即 发送给用户的消息记录表
现在需要查询出给用户发送的所有消息的相关信息,此时需要关联查询两张表,
对比发现,关联唯一条件为openid,查询类型为一对多查询
//查询语句sql
SELECT
g.*,
c.openid,
c.nickname,
c.remark,
c.id AS c_id
FROM
cs_template g
RIGHT JOIN cs_user AS c ON c.openid = g.openid
WHERE
( 1 )
ORDER BY
g.id DESC
LIMIT 0,
10
执行sql时间用了48.3秒,这是不能忍的,用explain看下查询计划
由上图可以发现,表g扫描了33249行,再乘以表c的187行数据,共计扫描了300W次,显然进行了全表扫描
解决办法:避免全表扫描,对于一对多查询,给关联条件字段上增加索引
因为表g,也就是表cs_template 扫描了3W行+数据,所以从这里下手
表g的关联字段为openid,看上方建表sql语句,这个字段是没有索引的,所以加上一个普通索引即可
给openid 添加索引
ALTER TABLE `cs_template` ADD INDEX (`openid`);
添加完后再次查看执行计划
由图可以看出,计划给出的查询行数减少到了186行,并且用到了索引openid
再次执行sql语句查看效果
查询时间由48秒减少到了0.6秒
总结:对于一对多关联查询时,可能会造成全表扫描,从而产生慢sql,需要在关联条件上增加对应类型的索引,能够大大优化查询速度,提高sql效率
当然还有不同的优化方法,若有误的地方,欢迎指出批评~