记录一次一对多查询优化

记录一次一对多查询优化

第一张表 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

记录一次一对多查询优化_第1张图片
执行sql时间用了48.3秒,这是不能忍的,用explain看下查询计划
记录一次一对多查询优化_第2张图片

由上图可以发现,表g扫描了33249行,再乘以表c的187行数据,共计扫描了300W次,显然进行了全表扫描

解决办法:避免全表扫描,对于一对多查询,给关联条件字段上增加索引

因为表g,也就是表cs_template 扫描了3W行+数据,所以从这里下手

表g的关联字段为openid,看上方建表sql语句,这个字段是没有索引的,所以加上一个普通索引即可

给openid 添加索引
ALTER TABLE `cs_template` ADD INDEX (`openid`);

添加完后再次查看执行计划
记录一次一对多查询优化_第3张图片
由图可以看出,计划给出的查询行数减少到了186行,并且用到了索引openid

再次执行sql语句查看效果
记录一次一对多查询优化_第4张图片
查询时间由48秒减少到了0.6秒

总结:对于一对多关联查询时,可能会造成全表扫描,从而产生慢sql,需要在关联条件上增加对应类型的索引,能够大大优化查询速度,提高sql效率


当然还有不同的优化方法,若有误的地方,欢迎指出批评~

你可能感兴趣的:(mysql,mysql,sql,数据库)