在 select 子句中嵌套 select 需要很长时间才能完成

Nesting select in select clause take forever to complete

Table markclr
=============
  id     int(10) UNSIGNED AUTO_INCREMENT NOT NULL,
  name   varchar(255) NOT NULL,
  color  varchar(255) NOT NULL,
Table dvcgrp
=============
  id         int(10) UNSIGNED AUTO_INCREMENT NOT NULL,
  name       varchar(255) NOT NULL,
  markclrid  int(10) UNSIGNED NOT NULL,
Table dvc
=============
  id        int(10) UNSIGNED AUTO_INCREMENT NOT NULL,
  name      varchar(255) NOT NULL,
  shrtname  varchar(255) NOT NULL,
  dvceui    varchar(255) NOT NULL,
  dvcgrpid  int(10) UNSIGNED NOT NULL,
Table vhsrdt
=============
  id             int(10) UNSIGNED AUTO_INCREMENT NOT NULL,
  dvcid          int(10) UNSIGNED NOT NULL,
  dtrcvtm        timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  dtraw          varchar(255) NOT NULL,
  dtdvcnm        varchar(255) NOT NULL,
  dtgtwid        varchar(255) NOT NULL,
  dtport         int NOT NULL,
  dtdr           int NOT NULL,
  dtadr          varchar(255) NOT NULL,
  dtriptype      varchar(255),
  dlatitudedeg   decimal(10,8),
  dlongitudedeg  decimal(11,8),
  dvextgood      int(10) UNSIGNED NOT NULL,
  dgpscurrent    int(10) UNSIGNED NOT NULL,
  dignition      int(10) UNSIGNED NOT NULL,
  ddigin1        int(10) UNSIGNED NOT NULL,
  ddigin2        int(10) UNSIGNED NOT NULL,
  ddigout        int(10) UNSIGNED NOT NULL,
  dheadingdeg    varchar(255),
  dspeedkmph     varchar(255),
  dbatv          varchar(255),

请帮我解释一下我的查询发生了什么:

select
  dvc1.id,
  dvc1.name as dvcname,
  dvc1.dvceui as dvcdvceui,
  dvc1.shrtname as dvcshrtname,
  markclr.color as markclrcolor,
  (
    select
      tbl1.dtrcvtm
    from vhsrdt as tbl1
    where
      tbl1.dvcid = dvc1.id and
      tbl1.dtrcvtm = (
        select
          max(tbl2.dtrcvtm) as dtrcvtm
        from vhsrdt as tbl2
        where tbl2.dvcid = tbl1.dvcid
      )
  ) as dtrcvtm,
  (
    select
      tbl1.dtgtwid
    from vhsrdt as tbl1
    where
      tbl1.dvcid = dvc1.id and
      tbl1.dtrcvtm = (
        select
          max(tbl2.dtrcvtm) as dtrcvtm
        from vhsrdt as tbl2
        where tbl2.dvcid = tbl1.dvcid
      )
  ) as dtgtwid,
  (
    select
      tbl1.dtriptype
    from vhsrdt as tbl1
    where
      tbl1.dvcid = dvc1.id and
      tbl1.dtrcvtm = (
        select
          max(tbl2.dtrcvtm) as dtrcvtm
        from vhsrdt as tbl2
        where tbl2.dvcid = tbl1.dvcid
      )
  ) as dtriptype,
  (
    select
      tbl1.dlatitudedeg
    from vhsrdt as tbl1
    where
      tbl1.dvcid = dvc1.id and
      tbl1.dtrcvtm = (
        select
          max(tbl2.dtrcvtm) as dtrcvtm
        from vhsrdt as tbl2
        where tbl2.dvcid = tbl1.dvcid
      )
  ) as dlatitudedeg,
  (
    select
      tbl1.dlongitudedeg
    from vhsrdt as tbl1
    where
      tbl1.dvcid = dvc1.id and
      tbl1.dtrcvtm = (
        select
          max(tbl2.dtrcvtm) as dtrcvtm
        from vhsrdt as tbl2
        where tbl2.dvcid = tbl1.dvcid
      )
  ) as dlongitudedeg,
  (
    select
      tbl1.dspeedkmph
    from vhsrdt as tbl1
    where
      tbl1.dvcid = dvc1.id and
      tbl1.dtrcvtm = (
        select
          max(tbl2.dtrcvtm) as dtrcvtm
        from vhsrdt as tbl2
        where tbl2.dvcid = tbl1.dvcid
      )
  ) as dspeedkmph,
  (
    select
      tbl1.dheadingdeg
    from vhsrdt as tbl1
    where
      tbl1.dvcid = dvc1.id and
      tbl1.dtrcvtm = (
        select
          max(tbl2.dtrcvtm) as dtrcvtm
        from vhsrdt as tbl2
        where tbl2.dvcid = tbl1.dvcid
      )
  ) as dheadingdeg
from dvc as dvc1
left join dvcgrp on dvcgrp.id = dvc1.dvcgrpid
left join markclr on markclr.id = dvcgrp.markclrid

table vhsrdt 填充了大约 90K 数据。
如果我使用 XAMPP 模拟数据库和 运行 在我的开发环境中查询,它会在不到 1 秒的时间内成功获取。
但是,如果我 运行 使用带有 MySQL 5.7 的 linux 服务器对生产进行查询,它永远不会完成。

我也试过删除数据库,重新构造所有结构和数据,还是无法完成查询。

感谢您的帮助。

EXPLAIN的结果:

id | select_type        | table    | partitions | type   | possible_keys                                                                                                                                                                                                               | key                               | key_len | ref                     | rows | filtered | Extra
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1  | PRIMARY            | dvc1     |            | ALL    |                                                                                                                                                                                                                             |                                   |         |                         | 50   | 100      |
1  | PRIMARY            | dvcgrp   |            | eq_ref | PRIMARY                                                                                                                                                                                                                     | PRIMARY                           | 4       | klksensor.dvc1.dvcgrpid | 1    | 100      |
1  | PRIMARY            | markclr  |            | ALL    | PRIMARY                                                                                                                                                                                                                     |                                   |         |                         | 5    | 100      | Using where; Using join buffer (Block Nested Loop)
14 | DEPENDENT SUBQUERY | tbl1     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.dvc1.id       | 1627 | 100      | Using where
15 | DEPENDENT SUBQUERY | tbl2     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.tbl1.dvcid    | 1627 | 100      | Using index
12 | DEPENDENT SUBQUERY | tbl1     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.dvc1.id       | 1627 | 100      | Using where
13 | DEPENDENT SUBQUERY | tbl2     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.tbl1.dvcid    | 1627 | 100      | Using index
10 | DEPENDENT SUBQUERY | tbl1     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.dvc1.id       | 1627 | 100      | Using where
11 | DEPENDENT SUBQUERY | tbl2     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.tbl1.dvcid    | 1627 | 100      | Using index
8  | DEPENDENT SUBQUERY | tbl1     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.dvc1.id       | 1627 | 100      | Using where
9  | DEPENDENT SUBQUERY | tbl2     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.tbl1.dvcid    | 1627 | 100      | Using index
6  | DEPENDENT SUBQUERY | tbl1     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.dvc1.id       | 1627 | 100      | Using where
7  | DEPENDENT SUBQUERY | tbl2     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.tbl1.dvcid    | 1627 | 100      | Using index
4  | DEPENDENT SUBQUERY | tbl1     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.dvc1.id       | 1627 | 100      | Using where
5  | DEPENDENT SUBQUERY | tbl2     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.tbl1.dvcid    | 1627 | 100      | Using index
2  | DEPENDENT SUBQUERY | tbl1     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.dvc1.id       | 1627 | 100      | Using where; Using index
3  | DEPENDENT SUBQUERY | tbl2     |            | ref    | vhsrdt_dvcid_index,vhsrdt_dvcid_dtrcvtm_dtport_index,vhsrdt_dvcid_dtgtwid_index,vhsrdt_dvcid_dtriptype_index,vhsrdt_dvcid_dlatitudedeg_index,vhsrdt_dvcid_dlongitudedeg_index,vhsrdt_dvcid_dlatitudedeg_dlongitudedeg_index | vhsrdt_dvcid_dtrcvtm_dtport_index | 4       | klksensor.tbl1.dvcid    | 1627 | 100      | Using index

从您的 EXPLAIN 语句中,您可以看到很多 Dependent Subquery 是 运行;尽管在您的情况下,它们都是相似的,只是 SELECT 差异字段不同。不幸的是,MySQL 在 SELECT 子句中使用子查询时不允许返回元组。

您可以通过在 FROM 子句中使用单个 "run" 计算所有 MAX() 值,将所有这些子查询缩减为单个子查询。请尝试以下查询:

select
  dvc1.id,
  dvc1.name as dvcname,
  dvc1.dvceui as dvcdvceui,
  dvc1.shrtname as dvcshrtname,
  markclr.color as markclrcolor,
  vhsrdt.dtrcvtm,
  vhsrdt.dtgtwid,
  vhsrdt.dtriptype,
  vhsrdt.dlatitudedeg,
  vhsrdt.dlongitudedeg,
  vhsrdt.dspeedkmph,
  vhsrdt.dheadingdeg
from dvc as dvc1
left join dvcgrp on dvcgrp.id = dvc1.dvcgrpid
left join markclr on markclr.id = dvcgrp.markclrid
left join vhsrdt on vhsrdt.dvcid = dvc1.id 
left join (select max(dtrcvtm) as max_dtrcvtm, dvcid
           from vhsrdt 
           group by dvcid
          ) as dt on dt.dvcid = vhsrdt.dvcid 
                     and dt.max_dtrcvtm = vhsrdt.dtrcvtm

无论我们是否需要,上述方法都限制了计算所有 dvcidmax() 值。此外,它会导致 temp table 创建(如果小则在内存中,否则在磁盘上)。值得庆幸的是,MySQL 8.0.14 引入了 LATERAL Derived Table;所以如果你可以升级到最新的 MySQL 版本,更多 performant 查询将是:

select
  dvc1.id,
  dvc1.name as dvcname,
  dvc1.dvceui as dvcdvceui,
  dvc1.shrtname as dvcshrtname,
  markclr.color as markclrcolor,
  v1.dtrcvtm,
  v1.dtgtwid,
  v1.dtriptype,
  v1.dlatitudedeg,
  v1.dlongitudedeg,
  v1.dspeedkmph,
  v1.dheadingdeg
from dvc as dvc1
left join dvcgrp on dvcgrp.id = dvc1.dvcgrpid
left join markclr on markclr.id = dvcgrp.markclrid
left join vhsrdt v1 on v1.dvcid = dvc1.id 
left join lateral (select max(v2.dtrcvtm) as max_dtrcvtm
                   from vhsrdt v2 
                   where v2.dvcid = v1.dvcid
                  ) as dt on dt.max_dtrcvtm = v1.dtrcvtm