所以,我有一个大约有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万行(并且正在计数),是否有一种不同的方法可以加快查询速度?
答案 0 :(得分: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_number
始终为1
(name, time)
}。
在ROW_NUMBER()
上设置索引可以确保数据处于友好的顺序,从而使优化器更容易。这意味着time
实际上并未应用于所有记录;一旦找到最高价值的ROW_NUMBER() = 1
记录,并指定name
,它就会知道它可以停止并转到下一个{{1}}。