MySQL 8.0.15 Dam慢选查询

问题描述 投票:1回答:2

查询的座右铭非常简单,找出外键列的最后一个条目。我能说的伪代码是

select vehicleid , last_journey_point , last_journey_time from journeyTable.

这是我的SQL语句

- loconumber是一个索引列 - journeyserla是一个自动编号主键int(11) - 表locojourney包含400,000条记录

- 下面的代码块在19秒内执行

with LocomotiveLastRun AS(
     -- this block of code runs in 0.016 sec
    SELECT locojourney.loconumber , MAX(locojourney.journeyserla) as lastrunid
      FROM locojourney GROUP BY loconumber)

  SELECT locojourney.CurrentCombiners , locojourney.JourneySerla , 
         locojourney.From_RunPoint , locojourney.NEXT_RunPoint 
   FROM  LocomotiveLastRun FORCE INDEX(lastrunid)
   JOIN  locojourney FORCE INDEX(PRIMARY) ON x.lastrunid = locojourney.journeyserla 
  WHERE  locojourney.ishoc = 'n'

EXPLAIN命令显示一个派生表,该表不使用索引并使用where和type ALL

enter image description here

这是表定义:

    -- SHOW CREATE TABLE locojourney
CREATE TABLE `locojourney` (
  `trainID` smallint(5) NOT NULL,
  `LocoNumber` varchar(5) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `CurrentLocoBase` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
  `CurrentDuedate` date DEFAULT NULL,
  `LocoConsist` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `CurrentLocoDomain` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
  `DomainChange` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `FEDR` enum('N','Y') CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT 'N',
  `LADR` enum('N','Y') CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT 'N',
  `ISBANKER` enum('N','Y') CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT 'N',
  `TrainName` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `WithOutLoad` enum('N','Y') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'N',
  `runRoute` varchar(50) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `From_RunPoint` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `From_RunTime` datetime NOT NULL,
  `NEXT_RunPoint` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
  `NEXT_RunTime` datetime NOT NULL,
  `Affects_Outage` enum('N','Y') CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT 'N',
  `Affects_Mileage` enum('N','Y') CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT 'N',
  `GroundDistance` double(5,2) DEFAULT '0.00',
  `SHGallowance` int(11) DEFAULT '0',
  `Outage` double(5,4) DEFAULT '0.0000',
  `UnderServiceType` enum('FHT','CHG','DEP','MIX','DETN') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'FHT',
  `SubServiceHead` varchar(25) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'RUN',
  `IShoc` enum('N','Y') CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT 'N',
  `CurrentCombiners` varchar(28) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
  `RunSetSerla` varchar(25) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
  `JourneySerla` int(11) NOT NULL AUTO_INCREMENT,
  `NominationSerla` varchar(50) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
  `Traction` enum('DSL','AC') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'DSL',
  `Trainload` smallint(4) NOT NULL DEFAULT '0',
  `LeadAssist` enum('Y','N') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'N',
  `DEO` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
  `DEOtime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`JourneySerla`),
  KEY `trainID` (`trainID`) USING BTREE,
  KEY `routesection_idx` (`runRoute`) USING BTREE,
  KEY `loconumber_idx` (`LocoNumber`) USING BTREE,
  KEY `runsetserla_idx` (`RunSetSerla`) USING BTREE,
  KEY `subservicehead_idx` (`SubServiceHead`) USING BTREE,
  CONSTRAINT `locojourney_ibfk_1` FOREIGN KEY (`SubServiceHead`) REFERENCES `ineffective` (`IneffectiveHead`) ON UPDATE CASCADE,
  CONSTRAINT `locojourney_ibfk_3` FOREIGN KEY (`runRoute`) REFERENCES `routesections` (`Sectionname`) ON DELETE RESTRICT ON UPDATE CASCADE,
  CONSTRAINT `loconumber_fk` FOREIGN KEY (`LocoNumber`) REFERENCES `lococontainer` (`LocoNumber`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=345719 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
mysql greatest-n-per-group query-performance
2个回答
0
投票
with LocomotiveLastRun AS(
       -- this block of code runs in 0.016 sec
    SELECT locojourney.loconumber , MAX(locojourney.journeyserla) as lastrunid
      FROM locojourney 
     GROUP BY loconumber)

为什么这个CTE子查询速度快?因为你的表已经在(loconumber, journeyserla)上有一个索引。 (InnoDb会自动将主键附加到每个索引。)对于该索引上的松散索引扫描,可以满足此查询,并且这些查询速度很快。

现在为您的主要查询:

  1. 摆脱FORCE INDEX()。除非你有至少十年的SQL经验,或者你已经阅读过MySQL中InnoDB索引的源代码,否则甚至不要梦想使用它。值得注意的是,它在CTE上完全没用,因为CTE没有索引。
  2. 为清楚起见,将主(细节)表放在第一位,将CTE放在第二位。
  3. 为了清楚起见,将JOIN改为WHERE...IN...

这三个建议给了我们这个:

   WITH LocomotiveLastRun AS (...)
 SELECT locojourney.CurrentCombiners , locojourney.JourneySerla , 
        locojourney.From_RunPoint , locojourney.NEXT_RunPoint 
   FROM locojourney
  WHERE journeyserla IN (SELECT lastrunid FROM LocomotiveLastRun)
    AND locojourney.ishoc = 'n'

现在,很明显索引可以帮助这个查询。

关于(ishoc)的指数将有所帮助。 (它实际上是一个索引,因为InnoDB,在(ishoc, journeyserla)所以它有助于两个WHERE条件。)查询规划器使用BTREE随机访问找到第一个索引行ishoc'n',然后扫描主键的值以匹配它们与IN条款。

覆盖查询的复合索引将有助于实现更多,而不是该索引。这样的覆盖索引特别有用,因为表的每一行都很大,有很多列。该索引提到了WHERE子句中的列以及您要选择的列,如下所示:

(ishoc, journeyserla, CurrentCombiners, From_RunPoint, NEXT_RunPoint)

查询计划程序可以完全从索引中满足您的查询,从而节省磁盘读取时间以满足查询。如果你经常使用你的查询,这个索引是个好主意。但是,它确实消耗了磁盘空间并且减慢了INSERTUPDATE操作的速度。

阅读https://use-the-index-luke.com/


0
投票

尝试一下:

SELECT  lj.CurrentCombiners , lj.JourneySerla , lj.From_RunPoint , lj.NEXT_RunPoint
    FROM (  SELECT  MAX(journeyserla) as lastrunid
                FROM  locojourney
                GROUP BY  loconumber 
         ) AS llr
    JOIN  locojourney AS lj  ON llr.lastrunid = lj.journeyserla
    WHERE  lj.ishoc = 'n' 

(给它时间并提供EXPLAIN

© www.soinside.com 2019 - 2024. All rights reserved.