如何优化子查询?

时间:2014-03-22 18:13:33

标签: mysql

我有两个表,其中一个表保存第一个表的日志。我使用子查询从日志表获取数据但是它正在 .8秒在phpmyadmin中。在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

MyTable -

ID      Name
2181    test1
2180    test2
2079    test0

2 个答案:

答案 0 :(得分:1)

您的查询基本上运行了6,000个查询。对于MyTable中的每条记录,它正在从日志表中运行相关的基于列的查询。我在这里提出的是通过由" ID"预先分组的日志表预先查询ONCE。列,并获得最大值" UID"每个日志作为相应的模板ID,您希望记录状态。由于UID是自动增量,这意味着最高日志是最近的时间。

为了帮助优化这个" PreQuery",我会在LOG表FOR(模板,ID,UID)上有一个索引UID的日志表上的另一个索引是默认的,因为它是主键。

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

如果你考虑这个,那就是运行2个查询... prequery,然后是主查询,它只是每个记录引用别名的JOIN

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

答案 1 :(得分:0)

您的查询是:

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;