使用Postgresql进行高效的最新记录查询

时间:2009-11-05 22:56:33

标签: sql postgresql subquery distinct

我需要做一个大问题,但我只想要最新的记录。

对于单个条目,我可能会做类似

的事情
SELECT * FROM table WHERE id = ? ORDER BY date DESC LIMIT 1;

但是我需要为大量(数千个条目)的记录提取最新记录,但只记录最新记录。

这就是我所拥有的。效率不高。我想知道是否有更好的方法。

SELECT * FROM table a WHERE ID IN $LIST AND date = (SELECT max(date) FROM table b WHERE b.id = a.id);

5 个答案:

答案 0 :(得分:42)

如果您不想更改数据模型,可以使用DISTINCT ON从表“b”中获取“a”中每个条目的最新记录:

SELECT DISTINCT ON (a.id) *
FROM a
INNER JOIN b ON a.id=b.id
ORDER BY a.id, b.date DESC

如果你想避免查询中的“排序”,添加像这样的索引可能会帮助你,但我不确定:

CREATE INDEX b_id_date ON b (id, date DESC)

SELECT DISTINCT ON (b.id) *
FROM a
INNER JOIN b ON a.id=b.id
ORDER BY b.id, b.date DESC

或者,如果您想以某种方式对表“a”中的记录进行排序:

SELECT DISTINCT ON (sort_column, a.id) *
FROM a
INNER JOIN b ON a.id=b.id
ORDER BY sort_column, a.id, b.date DESC

替代方法

但是,上述所有查询仍然需要从表“b”中读取所有引用的行,因此如果您有大量数据,它可能仍然太慢。

你可以创建一个新表,它只保存每个a.id的最新“b”记录 - 或者甚至将这些列移动到“a”表本身。

答案 1 :(得分:33)

这可能更有效率。差异:表b的查询只执行一次,每行都执行相关的子查询:

SELECT * 
FROM table a 
JOIN (SELECT ID, max(date) maxDate
        FROM table
      GROUP BY ID) b
ON a.ID = b.ID AND a.date = b.maxDate
WHERE ID IN $LIST 

答案 2 :(得分:4)

在方法上 - 创建一个包含表a上最近更新/插入时间的小型衍生表 - 调用此表a_latest。表a_latest需要足够的粒度来满足您的特定查询要求。在你的情况下,使用

就足够了
CREATE TABLE 
a_latest 
( id INTEGER NOT NULL, 
  date TSTAMP NOT NULL, 
  PRIMARY KEY (id, max_time) );

然后使用类似于najmeddine建议的查询:

SELECT a.* 
FROM TABLE a, TABLE a_latest 
USING ( id, date );

然后诀窍是保持a_latest最新。在插入和更新时使用触发器执行此操作。用plppgsql编写的触发器很容易编写。如果您愿意,我很乐意提供一个例子。

这里的要点是在更新过程中会计算最新的更新时间。这会使更多的负载远离查询。

答案 3 :(得分:3)

你怎么看待这个?

select * from (
   SELECT a.*, row_number() over (partition by a.id order by date desc) r 
   FROM table a where ID IN $LIST 
)
WHERE r=1

我过去经常使用它

答案 4 :(得分:1)

如果每个id有很多行,你肯定需要一个相关的子查询。 它将为每个id进行1次索引查找,但这比对整个表进行排序要快。

类似的东西:

SELECT a.id,
(SELECT max(t.date) FROM table t WHERE t.id = a.id) AS lastdate
FROM table2;

您将使用的'table2'不是您在上面的查询中提到的表,因为在这里您需要一个不同ID的列表以获得良好的性能。由于您的ID可能是FK到另一个表中,请使用此表。