为大型数据集中的每个项目选择最新条目

Jar*_*und 3 sql postgresql performance

所以,我有一个大约有150万行的表,看起来有点像这样:

name   | time       | data1 | data2  
--------------------------------------
 93-15 | 1337348782 |   11  | 60.791 
 92-02 | 1337348783 |   11  | 62.584 
 92-02 | 1337348056 |   11  | 63.281
 93-15 | 1337348068 |    8  | 65.849
 92-02 | 1337348117 |   11  | 63.271 
 93-15 | 1337348129 |    8  | 65.849 
 92-02 | 1337348176 |   10  | 63.258 
 93-15 | 1337348188 |    8  | 65.849 
 92-02 | 1337348238 |   10  | 63.245 
 93-15 | 1337348248 |    8  | 65.849  
Run Code Online (Sandbox Code Playgroud)

...这些对应于需要监控的事物的历史状态更新.现在,我想做的是找到每个单位的当前状态.

在stackoverflow上找到类似的问题并不难,并从结果中推断,我想出了这个查询:

SELECT * FROM vehicles v
  JOIN ( SELECT  MAX(time) as max, name
    FROM vehicles
    GROUP BY name)
  m_v
ON (v.time = m_v.max AND v.name = m_v.name);
Run Code Online (Sandbox Code Playgroud)

但是看到我有大约150万行(并且正在计数),是否有一种不同的方法可以加快查询速度?

Mat*_*lie 6

WITH
  sequenced_data
AS
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY name ORDER BY time DESC) AS sequence_id,
    *
  FROM
    vehicles
)
SELECT
  *
FROM
  sequenced_data
WHERE
  sequence_id = 1
Run Code Online (Sandbox Code Playgroud)

覆盖指数(name, time)也会有所帮助.


编辑:关于它是如何工作的注释等.

PostgreSQL具有窗口或分析功能.这些通常采取的形式some_function() OVER (PARTITION BY some_fields ORDER BY some_fields).

在这种情况下,我用过ROW_NUMBER() OVER (PARTITION BY name ORDER BY time DESC).

ROW_NUMBER()为一组数据创建唯一的行号. 1 to nn记录.

PARTITION BY name表示此函数独立应用于不同的名称.每个name都是它自己的组/窗口/分区,以及每个组/窗口/分区的重新ROW_NUMBER()开始的结果1.

ORDER BY time DESC获取一个组/窗口/分区中的所有记录,并按照time字段对它们进行排序,在ROW_NUMBER()应用函数之前,首先使用最高值.

因此,对于您的示例数据,您可以获得此...

 name  | time       | data1 | data2  | row_number
--------------------------------------------------

 92-02 | 1337348783 |   11  | 62.584 | 1
 92-02 | 1337348238 |   10  | 63.245 | 2
 92-02 | 1337348176 |   10  | 63.258 | 3
 92-02 | 1337348117 |   11  | 63.271 | 4
 92-02 | 1337348056 |   11  | 63.281 | 5

 93-15 | 1337348782 |   11  | 60.791 | 1
 93-15 | 1337348248 |    8  | 65.849 | 2
 93-15 | 1337348188 |    8  | 65.849 | 3
 93-15 | 1337348129 |    8  | 65.849 | 4
 93-15 | 1337348068 |    8  | 65.849 | 5
Run Code Online (Sandbox Code Playgroud)

因为排序是time DESC,价值最高的time领域,在每个name组/窗/分区,总会有一个row_number1.

(name, time)通过确保数据处于友好的顺序,索引使优化器更容易.这意味着ROW_NUMBER()实际上并未应用于所有记录; 一旦找到最高价值的time记录并分配ROW_NUMBER() = 1,它就会知道它可以停止并继续下一个name.