我有一个包含不同站点上的生成器运行时的表,我想为每个站点选择最新的条目。每台发电机每周运行一次或两次。
我有一个查询会做到这一点,但我想知道它是否是最好的选择。我不禁想到使用WHERE x IN(SELECT ...)是懒惰的,而不是制定查询的最佳方式 - 任何查询。
表格如下:
CREATE TABLE generator_logs (
id integer NOT NULL,
site_id character varying(4) NOT NULL,
start timestamp without time zone NOT NULL,
"end" timestamp without time zone NOT NULL,
duration integer NOT NULL
);
查询:
SELECT id, site_id, start, "end", duration
FROM generator_logs
WHERE start IN (SELECT MAX(start) AS start
FROM generator_logs
GROUP BY site_id)
ORDER BY start DESC
没有大量数据,所以我并不担心优化查询。但是,我必须在具有数百万行的表格上做类似的事情(据我所关注的是大表!)并且优化更为重要。
那么有更好的查询,内联查询通常是个坏主意吗?
答案 0 :(得分:4)
您的查询是否应该相关?即:
SELECT id, site_id, start, "end", duration
FROM generator_logs g1
WHERE start = (SELECT MAX(g2.start) AS start
FROM generator_logs g2
WHERE g2.site_id = g1.site_id)
ORDER BY start DESC
否则,您可能会选择非最新日志,其起始值恰好与其他网站的最新开始日期相匹配。
或者:
SELECT id, site_id, start, "end", duration
FROM generator_logs g1
WHERE (site_id, start) IN (SELECT site_id, MAX(g2.start) AS start
FROM generator_logs g2
GROUP BY site_id)
ORDER BY start DESC
答案 1 :(得分:1)
我会使用连接,因为它们的表现比“IN”子句要好得多:
select gl.id, gl.site_id, gl.start, gl."end", gl.duration
from
generator_logs gl
inner join (
select max(start) as start, site_id
from generator_logs
group by site_id
) gl2
on gl.site_id = gl2.site_id
and gl.start = gl2.start
另外,Tony pointed out您在原始查询中缺少相关性
答案 2 :(得分:0)
在MYSQL中它可能会有问题,因为Last i Checked它无法有效地优化子查询(即:通过查询重写)
许多DBMS都有基因查询规划器,无论您的输入查询结构如何,它都会做同样的事情。
MYSQL在某些情况下会针对这种情况创建临时表,有时则不会,并且根据具体情况,索引,条件,子查询仍然可以相当快。
有些人抱怨子查询难以阅读,但如果将它们分解为局部变量,它们就完全可以了。$maxids = 'SELECT MAX(start) AS start FROM generator_logs GROUP BY site_id';
$q ="
SELECT id, site_id, start, \"end\", duration
FROM generator_logs
WHERE start IN ($maxids)
ORDER BY start DESC
";
答案 3 :(得分:0)
这个问题 - 不仅找到MAX
,而且找到相应行的其余部分 - 是一个常见问题。幸运的是,Postgres使用DISTINCT ON
:
SELECT DISTINCT ON (site_id)
id, site_id, start, "end", duration
FROM generator_logs
ORDER BY site_id, start DESC;
DISTINCT ON (site_id)
表示"每site_id
"返回一条记录。 order by子句确定哪条记录。但请注意,这与您的原始查询略有不同 - 如果同一站点的两条记录具有相同的start
,则查询将返回两条记录,而这只返回一条记录。
答案 4 :(得分:0)
查找每组每组 的记录的方法是选择那些在同一组中没有记录的记录具有更高的值:
SELECT id, site_id, "start", "end", duration
FROM generator_logs g1
WHERE NOT EXISTS (
SELECT 1
FROM generator_logs g2
WHERE g2.site_id = g1.site_id
AND g2."start" > g1."start"
);