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