[英]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.