3

所以,我有一个大约有 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  

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

在 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);

但是看到我大约有 150 万行(并且还在增加),是否有不同的方法可以实现更快的查询?

4

1 回答 1

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

一个覆盖索引(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 n用于n记录。

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

因为排序是,所以每个组/窗口/分区中time DESC的最高值time字段name将始终具有row_number1

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

于 2012-05-18T14:23:18.337 回答