在PostgreSQL大表中高效检索最新值

时间:2017-03-12 03:37:35

标签: postgresql

目前,在努力获得以下格式查询表格的有效方法后,我正在使用此查询......

select distinct on (symbol, date) date, symbol, value, created_time
from "test_table"
where symbol in ('symbol15', 'symbol19', 'symbol36', 'symbol54', 'symbol13', 'symbol90', 'symbol115', 'symbol145', 'symbol165', 'symbol12')
order by symbol, date, created_time desc

有了这个索引......

test_table(symbol, date, created_time)

下面是一个数据示例,用于显示我正在使用的列。真实的表是1300万行。

date           symbol      value      created_time
2010-01-09     symbol1     101        3847474847
2010-01-10     symbol1     102        3847474847
2010-01-10     symbol1     102.5      3847475500
2010-01-10     symbol2     204        3847474847
2010-01-11     symbol1     109        3847474847
2010-01-12     symbol1     105        3847474847
2010-01-12     symbol2     206        3847474847

目前看起来80%以上的查询是基于EXPLAIN ANALYZE进行排序的。知道如何提高此查询的速度吗?我需要为每个日期和符号组合获取最新的created_time。

4 个答案:

答案 0 :(得分:0)

由于您的where子句仅使用列symbol,因此不会使用您创建的索引。

我建议您在symbol上创建一个索引:

CREATE INDEX ON test_table(symbol);

此外,这可能是编写查询的更好方法

SELECT date, symbol, MAX(created_time)
FROM "test_table"
WHERE symbol in ('symbol15', 'symbol19', 'symbol36', 'symbol54', 'symbol13', 'symbol90', 'symbol115', 'symbol145', 'symbol165', 'symbol12')
GROUP BY date, symbol
ORDER BY symbol, date
LIMIT 10;

如果可以选择,添加限制将大大提高性能。

您应该运行EXPLAIN ANALYZE SELECT...以更好地了解使用哪些索引以及PostgreSQL如何运行查询。

答案 1 :(得分:0)

您可以考虑为此目的创建部分或筛选索引 - 但请注意,如果IN子句通过添加更多值或添加不在筛选索引中的值而更改,则它可能不起作用。它也可能对INSERT速度产生一些不利影响,因为索引必须评估您的INSERT是否包含一个有趣的值 - 所以如果您正在进行大量插入操作并且可以&考虑到任何额外的惩罚,请记住这一点。您还应在索引中指定您希望datecreated_time 降序

E.g。

CREATE INDEX test_table_ix ON test_table (symbol, date DESC, created_time DESC)
    WHERE (symbol in ('symbol15', 'symbol19', 'symbol36', 'symbol54', 'symbol13', 'symbol90', 'symbol115', 'symbol145', 'symbol165', 'symbol12'));

请参阅:https://www.postgresql.org/docs/8.0/static/indexes-partial.htmlhttps://www.postgresql.org/docs/9.6/static/indexes-ordering.html

您的查询将能够使用此索引,并且应该看到一些好处 - 请记住,此索引与某些成本相关联,并考虑您的查询是否经常运行以证明其合理性。您也可以通过将订单应用于索引来看到好处。

答案 2 :(得分:0)

如果没有正确测试超过1300万行的能力,那么问题始终是建立“最新”所需的排序。虽然我有点不愿意在这里提出这个问题, row_number()over()通常是一种很好的技术来达到“最新”。

模仿你执行排序以建立“最新”的方式的索引最有可能提供帮助,所以我希望在符号,日期,created_time desc 的索引中有用。

select date, symbol, value, created_time
from (select date, symbol, value, created_time
         , row_number() over(partition by symbol, date order by created_time DESC) rn
      from test_table
      where symbol in ('symbol15', 'symbol19', 'symbol36', 'symbol54', 'symbol13', 'symbol90', 'symbol115', 'symbol145', 'symbol165', 'symbol12')
     ) d
where rn = 1
order by symbol, date, created_time desc
;

答案 3 :(得分:0)

您使用的索引已经是最好的了。由于您未显示explain analyze输出,我建议您尝试使用values语法:

select distinct on (symbol, date) date, symbol, value, created_time
from test_table
where symbol in (values ('symbol15'), ('symbol19'), ('symbol36'), ('symbol54'), ('symbol13'), ('symbol90'), ('symbol115'), ('symbol145'), ('symbol165'), ('symbol12'))
order by symbol, date, created_time desc