首页 > 数据库 >记录一次MySQL多表查询,order by不走索引的情况.

记录一次MySQL多表查询,order by不走索引的情况.

时间:2023-11-29 15:55:05浏览次数:44  
标签:多表 id MySQL t1 periods time device NULL order

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

 

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秒左右.

目前尚未有更好的解决方法.

 

标签:多表,id,MySQL,t1,periods,time,device,NULL,order
From: https://www.cnblogs.com/MarsPanda/p/17865055.html

相关文章

  • python连接数据库(连MySQL)
    Python操作和连接数据库原创 阳阳 Python小例子 2023-10-1109:20 发表于湖北在Python中,你可以使用不同的库来操作和连接数据库,最常用的是sqlite3、MySQLdb和psycopg2。使用sqlite3连接和操作SQLite数据库:import sqlite3# 连接数据库conn = sqlite3.connect('......
  • MySQL 连接字符串中加入 nullCatalogMeansCurrent = true 的含义
    nullCatalogMeansCurrent的含义:nullCatalogMeansCurrent=true#在指定的数据库中查找需要的表nullCatalogMeansCurrent=false#在服务器全部数据库中查找需要的表不同MySQL驱动nullCatalogMeansCurrent默认情况:从mysql-connector-java5.x版本起,nullCatal......
  • MySQL Shell连接数据库报MySQL Error 1045 (28000)错误浅析
    这里简单总结一下mysqlshell访问数据库时报MySQLError1045(28000):Accessdeniedforuser'root'@'::1'(usingpassword:YES)的原因以及如何解决这个问题这里测试的环境为MySQL8.0.35,我们先来看看报错案例:$mysqlsh-hlocalhost-P7306-uroot-pPleaseprovidethep......
  • MySQL安装与配置(免安装版)
    MySQL下载1)进入官网下载地址:https://downloads.mysql.com/archives/installer/2)然后选择自己想要下载的MySQL版本,这里我选择的是5.7.40免安装版。MySQL安装配置1)将压缩包解压至你想要放置的文件夹中,注意:绝对路径中要避免出现中文。2)在解压目录下新建my.ini文件,并在文件中输入......
  • Mysql - Error 1055: Expression #1 of SELECT list is not in GROUP BY clause and c
    执行SQL时出现错误ERROR1055,SELECT列表不在GROUPBY语句内且存在不函数依赖GROUPBY语句的非聚合字段'edusassvc.u.nickname'这是和sql_mode=only_full_group_by不兼容的(即不支持)。分析问题1)原理层面这个错误会发生在mysql5.7版本及以上版本mysql5.7版本以上默认的sql......
  • [转]Linux 安装 MySQL 经验
    也可以参考:https://www.cnblogs.com/z5337/p/16514955.html本文内容参考:https://www.cnblogs.com/syncmr/p/11991050.html在Centos7.9安装MySQL5.7步骤记录:1、新建目录,保存安装包cdhomemkdirinstall_packetcd/home/install_packet2、下载mysql5.7rpm源wgeth......
  • 如何查看MySQL会话连接方式?
    MySQL总共支持四种连接方式访问数据库,如下表格所示,其中Linux平台环境下,主要有两种连接方式,一种是TCP/IP连接方式,另外一种是socket方式。Namepipe和Sharememory是Windows平台下独有的连接方式。那么,MySQL数据库中,我们能否查看会话具体使用的连接方式呢(例如,使用TCP/IP连接方式)?如果......
  • [翻译]——How the MySQL Optimizer Calculates the Cost of a Query (Doc ID 1327497
    本文是对这篇文章HowtheMySQLOptimizerCalculatestheCostofaQuery(DocID1327497.1)[1]的翻译,翻译如有不当的地方,敬请谅解,请尊重原创和翻译劳动成果,转载的时候请注明出处。谢谢!适用于:MySQL4.0及后续更高的版本本文档中的内容适用于任何平台。目标了解MySQL优化器如......
  • linux启动mysql数据库,报错mysql: error while loading shared libraries: libtinfo.so
    如下 原因: 解决方案:1、在/usr/lib64目录里面找一个差不多名称版本的文件进行链接#软连接出一个新的文件sudoln-s/usr/lib64/libtinfo.so.6.1/usr/lib64/libtinfo.so.5若本服务器没有相近版本的文件2、从其他服务器下载一个libtinfo.so.5拷贝进去即可,或者下载相近版本......
  • linux安装MySQL数据库初始化报错
    在使用如下初始化命令进行数据库初始化时报错,./bin/mysqld--user=mysql--basedir=/usr/local/mysql/mysql/--datadir=/usr/local/mysql/mysql/data/--initialize--lower-case-table-names=1; 权限不足导致,修改命令为:./bin/mysqld--user=root--basedir=/usr/local/mysql/m......