繁体   English   中英

如何优化子查询?

[英]How to optimize subquery?

我有两个表,其中一个保存了第一个表的日志。我正在使用子查询从日志表中获取数据,但在 phpmyadmin 中需要0.8 秒。Mytable 中有 2,000 多条记录,日志表中有 7000 多条记录。我尝试了不同的方法,但找不到优化查询的方法。

表结构-

CREATE TABLE IF NOT EXISTS `MyTable` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2182 ;

CREATE TABLE IF NOT EXISTS `log` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `ID` int(11) NOT NULL,
  `template` varchar(255) NOT NULL,
  `status` varchar(255) NOT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7650 ;

我当前的工作查询是-

SELECT a.*,
(select status from log where ID = a.ID AND template="template1" order by timestamp desc limit 1) as template1,
(select status from log where ID = a.ID AND template="template2" order by timestamp desc limit 1) as template2,
(select status from log where ID = a.ID AND template="template3" order by timestamp desc limit 1) as template3                
FROM MyTable a
ORDER BY a.ID DESC    

日志表-

uid     ID      template    status  timestamp
7648    2181    template1   P       2014-03-07 05:32:56
7646    2181    template1   R       2014-03-07 05:30:56
7645    2181    template2   R       2014-03-07 05:30:56
7644    2181    template3   R       2014-03-07 05:30:56
7643    2181    template1   R       2014-03-07 05:30:56
7642    2180    template2   R       2014-03-07 05:20:50
7641    2180    template3   p       2014-03-07 05:20:50
7640    2180    template1   R       2014-03-07 05:20:50

我的表 -

ID      Name
2181    test1
2180    test2
2079    test0

您的查询实际上运行了 6,000 个查询。 对于 MyTable 中的每一条记录,它都在运行日志表中相关的基于列的查询。 我在这里提出的是通过按“ID”列预先分组的日志表预查询 ONCE,并获取每个日志的最大“UID”作为您想要从记录中获取状态的相应模板 ID。 由于 UID 是自动递增的,这意味着最高的日志是最近的时间。

为了帮助优化这个“预查询”,我会在日志表上有一个索引 FOR(template, ID, UID ) 日志表上的另一个索引 UID 是默认的,因为它是主键。

因此,在预查询完成后,我只是根据每个模板标识的相应 MAX() ID 创建与日志表的备用别名的 JOIN 关系。 然后,您应该能够获得所有详细信息。

如果你考虑一下这个,它是 2 个正在运行的查询......预查询,然后是主查询,它只不过是对每条记录引用别名的 JOINs

SELECT 
      a.*,
      COALESCE( L1.Status, 0 ) as template1,
      COALESCE( L2.Status, 0 ) as template2,
      COALESCE( L3.Status, 0 ) as template3
   FROM 
      MyTable a
      LEFT JOIN
      ( select 
              L.ID,
              MAX( case when L.template = 'template1' then L.UID else 0 end ) as Temp1UID,
              MAX( case when L.template = 'template2' then L.UID else 0 end ) as Temp2UID,
              MAX( case when L.template = 'template3' then L.UID else 0 end ) as Temp3UID
           from
              Log L
           where 
              L.template in ( 'template1', 'template2', 'template' )
           group by
              L.ID
           order by 
              L.ID ) TempByID
         ON a.ID = TempByID.ID
              LEFT JOIN Log L1
                 ON TempByID.Temp1UID = L1.UID
              LEFT JOIN Log L2
                 ON TempByID.Temp2UID = L2.UID
              LEFT JOIN Log L3
                 ON TempByID.Temp3UID = L3.UID

您的查询是:

SELECT a.*,
       (select status from log l where l.ID = a.ID AND template="template1" order by timestamp desc limit 1) as template1,
       (select status from log where l.ID = a.ID AND template="template2" order by timestamp desc limit 1) as template2,
       (select status from log where l.ID = a.ID AND template="template3" order by timestamp desc limit 1) as template3                
FROM MyTable a
ORDER BY a.ID DESC   ;

出于您的目的,获得所需内容的最有效方法可能是在log(ID, template, timestamp, status)上创建索引:

create index log_ID_template_timestamp_status on log(ID, template, timestamp, status)

如果你想尝试另一种方法,你可以尝试使用substring_index() / group_concat()方法来获取最新或最早的值:

select a.*, l.template1, l.template2, l.template3
from MyTable a left outer join
     (select l.id,
             substring_index(group_concat((case when template = 'template1' then status end)
                                          order by timestamp desc
                                         ), ',', 1
                            ) as template1,
             substring_index(group_concat((case when template = 'template2' then status end)
                                          order by timestamp desc
                                         ), ',', 1
                            ) as template2,
             substring_index(group_concat((case when template = 'template3' then status end)
                                          order by timestamp desc
                                         ), ',', 1
                            ) as template3
      from log l
      group by l.id
     ) l
     on a.id = l.id
order by a.id desc;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM