记录一次MySQL多表查询,order by不走索引的情况.
首先是表结构,部分字段脱敏已删除
CREATE TABLE `log_device_heart` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`device_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`time_periods_begin` datetime NOT NULL,
`time_periods_end` datetime DEFAULT NULL,
`create_time` timestamp NULL DEFAULT NULL,
`date` datetime DEFAULT NULL,
`num` int DEFAULT NULL,
`other_num` int DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE,
KEY `device_number` (`device_number`) USING BTREE,
KEY `time_periods_begin_desc` (`time_periods_begin` DESC)
) ENGINE=InnoDB AUTO_INCREMENT=1168466 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; CREATE TABLE `m_device` (
`id` int NOT NULL AUTO_INCREMENT,
`type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '仪器类型',
`number` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '仪器编号',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '仪器名称',
`organization` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '机构',
`dealer` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '经销商', `area` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '区县',
`engineer_id` int DEFAULT NULL COMMENT '工程师id',
`update_date` datetime DEFAULT NULL,
`maintain_date` datetime DEFAULT NULL COMMENT '保养时间',
`dealer_id` int DEFAULT NULL COMMENT '经销商id',
`organization_id` int DEFAULT NULL COMMENT '机构id',
`socket_heart_last_time` datetime DEFAULT NULL COMMENT 'socket最后一次心跳时间',
`flag` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '标志位,0:未填写地址;1:已填写地址',
PRIMARY KEY (`id`) USING BTREE,
KEY `fk_device` (`engineer_id`) USING BTREE,
KEY `index_m_device_number` (`number`) USING BTREE,
KEY `organization_id` (`organization_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4615 DEFAULT CHARSET=utf8; CREATE TABLE `m_organization` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`deleted_flag` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '删除标志',
`dealer_id` int DEFAULT NULL COMMENT '经销商id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10066 DEFAULT CHARSET=utf8;
其中log_device_heart大概200w条数据,其它表都在200条左右
这是实际业务中的查询条件,这个项目是后续接手的,所以是不熟悉的Java项目
<select id="findDeviceHeartList" resultType="com.egs.biz.entity.vo.rsp.DeviceLogRsp$HeartRsp" parameterType="com.egs.biz.entity.vo.req.DeviceLogReq">
SELECT
t3.`name` as orgName,t1.num,t1.other_num as otherNum,
t1.device_number as deviceNumber,t1.time_periods_begin as timePeriodsBeginStr,
t1.time_periods_end as timePeriodsEndStr,t1.create_time as createTimeStr,t1.date as updateTimeStr
FROM log_device_heart t1 FORCE INDEX (time_periods_begin_desc)
left join m_device t2
on t1.device_number=t2.number
left join m_organization t3
on t3.id=t2.organization_id
WHERE 1=1
<if test="heartReq.organization!=null and heartReq.organization!=''">
and t3.`name` like '%${heartReq.organization}%'
</if>
<if test="heartReq.dataCleanFlag==true">
and organization_id<>'10007' and organization not like '%测试机器%'
</if>
<if test="heartReq.deviceNumber!=null and heartReq.deviceNumber!=''">
and t1.device_number=#{heartReq.deviceNumber}
</if>
<if test="heartReq.heart4GNum!=null and heartReq.heart4GNum!=''">
and t1.num < #{heartReq.heart4GNum}
</if>
<if test="heartReq.startDate!=null">
and t1.time_periods_begin >= DATE_FORMAT(#{heartReq.startDate},'%Y-%m-%d 00:00:00')
</if>
<if test="heartReq.endDate!=null">
and t1.time_periods_begin <= DATE_FORMAT(#{heartReq.endDate},'%Y-%m-%d 23:59:59')
</if>
order by t1.time_periods_begin desc
</select>
1 常规查询写法分析
select t3.`name` as orgName,t1.num,t1.other_num as otherNum,
t1.device_number AS deviceNumber,
t1.time_periods_begin AS timePeriodsBeginStr,
t1.time_periods_end AS timePeriodsEndStr,
t1.create_time AS createTimeStr,
t1.date AS updateTimeStr
FROM
log_device_heart t1 -- use index(time_periods_begin_desc)
STRAIGHT_JOIN m_device t2 ON t1.device_number = t2.number
LEFT JOIN m_organization t3 ON t3.id = t2.organization_id
WHERE
1 = 1
ORDER BY
t1.time_periods_begin DESC
LIMIT 10;
查询耗时3秒左右,查询计划显示驱动表并没有走索引,

200多w的主表数据,显然是无法接受这个结果的.
于是加上force index

SELECT
t3.`name` AS orgName,
t1.num,
t1.other_num AS otherNum,
t1.device_number AS deviceNumber,
t1.time_periods_begin AS timePeriodsBeginStr,
t1.time_periods_end AS timePeriodsEndStr,
t1.create_time AS createTimeStr,
t1.date AS updateTimeStr
FROM
log_device_heart t1 force INDEX ( time_periods_begin_desc )
LEFT JOIN m_device t2 ON t1.device_number = t2.number
LEFT JOIN m_organization t3 ON t3.id = t2.organization_id
WHERE
1 = 1
ORDER BY
t1.time_periods_begin DESC
LIMIT 10
> OK
> 时间: 0.001s
查询耗时可以忽略,提升了1000多倍.
但这会带来另一个问题,当我where条件添加筛选的时候,强制索引会导致效率降低,如下:
SELECT
t3.`name` AS orgName,
t1.num,
t1.other_num AS otherNum,
t1.device_number AS deviceNumber,
t1.time_periods_begin AS timePeriodsBeginStr,
t1.time_periods_end AS timePeriodsEndStr,
t1.create_time AS createTimeStr,
t1.date AS updateTimeStr
FROM
log_device_heart t1 force INDEX ( time_periods_begin_desc )
LEFT JOIN m_device t2 ON t1.device_number = t2.number
LEFT JOIN m_organization t3 ON t3.id = t2.organization_id
WHERE
1 = 1
-- and t1.device_number='MDA20122110039' --该查询性能正常
and t3.`name`='xxx医院'
ORDER BY
t1.time_periods_begin DESC
LIMIT 10;
该查询耗时0.6秒,已经较慢了.
查看查询计划,优化成了t3作为驱动表了,

那么根据情况,把,left join 改成straight_join
SELECT t3.`name` as orgName,t1.num,t1.other_num as otherNum,
t1.device_number as deviceNumber,t1.time_periods_begin as timePeriodsBeginStr,
t1.time_periods_end as timePeriodsEndStr,t1.create_time as createTimeStr,t1.date as updateTimeStr
FROM log_device_heart t1 -- use index(time_periods_begin_desc)
STRAIGHT_JOIN m_device t2
on t1.device_number=t2.number
left join m_organization t3
on t3.id=t2.organization_id
WHERE 1=1
and t1.device_number='MDA20123010006'
and t3.`name`='xxx医院'
-- and organization_id<>'10007' and organization not like '%学术机%'
order by t1.time_periods_begin desc limit 100;
改成这样子,速度变成0.009秒.
查询计划也正常了

STRAIGH_JOIN会有两个问题,本质上更类似于inner join,不过这边对我的逻辑影响不大
第二个就是当查询结果匹配不到,会奇慢无比.大概耗时10秒左右.
目前尚未有更好的解决方法.
另外新增索引后,记得再次重新优化下表结构
CREATE INDEX idx_time_number ON log_device_heart (time_periods_begin DESC,device_number);
ANALYZE TABLE log_device_heart;
记录一次MySQL多表查询,order by不走索引的情况.的更多相关文章
- 百万年薪python之路 -- MySQL数据库之 MySQL行(记录)的操作(二) -- 多表查询
MySQL行(记录)的操作(二) -- 多表查询 数据的准备 #建表 create table department( id int, name varchar(20) ); create table ...
- python 3 mysql 单表查询
python 3 mysql 单表查询 1.准备表 company.employee 员工id id int 姓名 emp_name varchar 性别 sex enum 年龄 age int 入职 ...
- python3 mysql 多表查询
python3 mysql 多表查询 一.准备表 创建二张表: company.employee company.department #建表 create table department( id ...
- MySQL优化:如何避免回表查询?什么是索引覆盖? (转)
数据库表结构: create table user ( id int primary key, name varchar(20), sex varchar(5), index(name) )engin ...
- MySQL多表查询合并结果union all,内连接查询
MySQL多表查询合并结果和内连接查询 1.使用union和union all合并两个查询结果:select 字段名 from tablename1 union select 字段名 from tab ...
- 记一次mysql多表查询(left jion)优化案例
一次mysql多表查询(left jion)优化案例 在新上线的供需模块中,发现某一个查询按钮点击后,出不来结果,找到该按钮对应sql手动执行,发现需要20-30秒才能出结果,所以服务端程序判断超时, ...
- MySQL 回表查询 & 索引覆盖优化
回表查询 先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据 建表示例 mysql> create table user( -> id int(10) auto_incre ...
- MySQL多表查询之外键、表连接、子查询、索引
MySQL多表查询之外键.表连接.子查询.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为 ...
- (转)Mysql 多表查询详解
MySQL 多表查询详解 一.前言 二.示例 三.注意事项 一.前言 上篇讲到mysql中关键字执行的顺序,只涉及了一张表:实际应用大部分情况下,查询语句都会涉及到多张表格 : 1.1 多表连接有 ...
- Mysql 单表查询-排序-分页-group by初识
Mysql 单表查询-排序-分页-group by初识 对于select 来说, 分组聚合(((group by; aggregation), 排序 (order by** ), 分页查询 (limi ...
随机推荐
- jqGrid--动态列
前台部门 <select id="xuenian" name="xuenian" class="form-control">&l ...
- 11个Python循环技巧
本文分享自华为云社区<Python中的循环技巧指南>,作者:柠檬味拥抱. 当我们处理数据时,有时候需要创建多个列表以存储不同类型或不同条件下的数据.在Python中,我们可以利用循环来快速 ...
- vue-单独引入css文件,设置公共的css样式或者修改默认的vant,mint样式
1.css文件夹下新建global.css文件并粘贴复制: ======================= :root{ --bgColor : #d3252a; --pinkColo ...
- [Python急救站]基于Transformer Models模型完成GPT2的学生AIGC学习训练模型
为了AIGC的学习,我做了一个基于Transformer Models模型完成GPT2的学生AIGC学习训练模型,指在训练模型中学习编程AI. 在编程之前需要准备一些文件: 首先,先win+R打开运行 ...
- LLaMA 3 源码解读-大语言模型5
本来不是很想写这一篇,因为网上的文章真的烂大街了,我写的真的很有可能没别人写得好.但是想了想,创建这个博客就是想通过对外输出知识的方式来提高自身水平,而不是说我每篇都能写得有多好多好然后吸引别人来看. ...
- gorm 关系一对一,一对多,多对多查询
gorm 关系一对一,一对多,多对多查询 gorm v2版本 Belongs To mysql表 CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_IN ...
- console小知识
console.log(JSON.stringify(object,null,2));
- Netflow/IPFIX 流量收集与分析
目录 文章目录 目录 Netflow(网络数据流检测协议) IPFIX(网络流量监测) IPFIX 组网架构 IPFIX 应用场景 Usage-based Accounting(基于使用流量的计费) ...
- video2blog 视频转图文AI小工具正式开源啦
前言 最近对一些小细节做了很多处理,但是其实还是有非常多的问题,没办法时间毕竟时间有限.为什么在这个时候开源,因为主要功能可以全部跑通了,分支暂时没开发的功能也可以通过其他的工具来替代. 这个工具开发 ...
- NumPy 随机数据分布与 Seaborn 可视化详解
随机数据分布 什么是数据分布? 数据分布是指数据集中所有可能值出现的频率,并用概率来表示.它描述了数据取值的可能性. 在统计学和数据科学中,数据分布是分析数据的重要基础. NumPy 中的随机分布 N ...