首先是表结构,部分字段脱敏已删除

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不走索引的情况.的更多相关文章

  1. 百万年薪python之路 -- MySQL数据库之 MySQL行(记录)的操作(二) -- 多表查询

    MySQL行(记录)的操作(二) -- 多表查询 数据的准备 #建表 create table department( id int, name varchar(20) ); create table ...

  2. python 3 mysql 单表查询

    python 3 mysql 单表查询 1.准备表 company.employee 员工id id int 姓名 emp_name varchar 性别 sex enum 年龄 age int 入职 ...

  3. python3 mysql 多表查询

    python3 mysql 多表查询 一.准备表 创建二张表: company.employee company.department #建表 create table department( id ...

  4. MySQL优化:如何避免回表查询?什么是索引覆盖? (转)

    数据库表结构: create table user ( id int primary key, name varchar(20), sex varchar(5), index(name) )engin ...

  5. MySQL多表查询合并结果union all,内连接查询

    MySQL多表查询合并结果和内连接查询 1.使用union和union all合并两个查询结果:select 字段名 from tablename1 union select 字段名 from tab ...

  6. 记一次mysql多表查询(left jion)优化案例

    一次mysql多表查询(left jion)优化案例 在新上线的供需模块中,发现某一个查询按钮点击后,出不来结果,找到该按钮对应sql手动执行,发现需要20-30秒才能出结果,所以服务端程序判断超时, ...

  7. MySQL 回表查询 & 索引覆盖优化

    回表查询 先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据 建表示例 mysql> create table user( -> id int(10) auto_incre ...

  8. MySQL多表查询之外键、表连接、子查询、索引

    MySQL多表查询之外键.表连接.子查询.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为 ...

  9. (转)Mysql 多表查询详解

    MySQL 多表查询详解 一.前言  二.示例 三.注意事项 一.前言  上篇讲到mysql中关键字执行的顺序,只涉及了一张表:实际应用大部分情况下,查询语句都会涉及到多张表格 : 1.1 多表连接有 ...

  10. Mysql 单表查询-排序-分页-group by初识

    Mysql 单表查询-排序-分页-group by初识 对于select 来说, 分组聚合(((group by; aggregation), 排序 (order by** ), 分页查询 (limi ...

随机推荐

  1. 学术顶会再突破!计算平台MaxCompute论文入选国际顶会VLDB 2021

    ​ 简介: VLDB 2021上,阿里云计算平台MaxCompute参与的论文入选,核心分布式调度执行引擎Fangorn.基于TVR Cost模型的通用增量计算优化器框架Tempura等分别被Indu ...

  2. 2018-2-13-win10-uwp-无法附加到CoreCLR

    title author date CreateTime categories win10 uwp 无法附加到CoreCLR lindexi 2018-2-13 17:23:3 +0800 2018- ...

  3. 18.基于Consul的服务发现和ConsulManager管理

    192.168.10.14 prometheus.consul 192.168.10.100 各类服务 一.基于Consul的服务发现 Consul 是由 HashiCorp 开发的一个支持多数据中心 ...

  4. WebGL实现简易的局部“马赛克”

    前言 接触过Canvas的小伙伴应该都知道,在Canvas2D中我们要加载一个图片很简单,通过调用drawImage API就能将图像绘制到画布上,当然在WebGL中我们也可以绘制图像,在绘制时我们需 ...

  5. OpenCompass-书生浦语大模型实战营第二期第7节作业

    书生浦语大模型实战营第二期第7节作业 这一节的作业和第6节作业一样没有特别多好说的,以运行结果为主. 基础作业 使用 OpenCompass 评测 internlm2-chat-1_8b 模型在 C- ...

  6. AIRIOT物联网低代码平台如何配置Modbus RTU协议?

    MBRTU即MODBUS RTU的简称,MODBUS是OSI模型第7层上的应用层报文传输协议,它在连接至不同类型总线或网络的设备之间提供客户机/服务器通信.平台的MBRTU协议是建立在TCP协议之上的 ...

  7. 大数据之Hadoop集群中Yarn常用命令

    Yarn状态的查询,除了可以在hadoop103:8088页面查看以外,还可以通过命令操作.常见的命令操作如下所示. 需求:执行WordCount案例,并通过Yarn命令查看任务运行情况.原文:sw- ...

  8. 【U8】 生产订单下bom 提示 “遇到以0做除数错误”错误

    一个虚拟件子件的子件为无换算率存货,bom中对应的换算率.辅助基本用量为0,修改为null后正常. 对应 bom_opcomponent表的 ChangeRate 换算率 AuxBaseQtyN 辅助 ...

  9. objectarx 之让用户自定义插件命令

    #include <iostream> #include <fstream> virtual AcRx::AppRetCode On_kInitAppMsg (void *pk ...

  10. 分享5款.NET开源免费的Redis客户端组件库

    前言 今天大姚给大家分享5款.NET开源.免费的Redis客户端组件库,希望可以帮助到有需要的同学. StackExchange.Redis StackExchange.Redis是一个基于.NET的 ...