快速在大表上使用LIMIT和OFFSET进行SELECT

时间:2013-03-15 09:46:05

标签: sql postgresql indexing postgresql-9.1 postgresql-9.2

我在表格中有超过1000万条记录。

SELECT * FROM tbl ORDER BY datecol DESC
LIMIT 10
OFFSET 999990

explain.depesz.comEXPLAIN ANALYZE的输出 执行上述查询大约需要10秒钟。我怎样才能让它更快?

更新

使用子查询将执行时间缩短一半:

SELECT * FROM tbl where id in 
(SELECT id FROM tbl ORDER BY datecol DESC LIMIT 10 OFFSET 999990)

explain.depesz.com上输出EXPLAIN ANALYZE

2 个答案:

答案 0 :(得分:2)

您需要在ORDER BY中使用的列上创建索引。理想情况下,排序顺序相同,但PostgreSQL可以以几乎相同的速度向后扫描索引。

CREATE INDEX tbl_datecol_idx ON tbl (datecol DESC);

当前手册中有更多about indexesCREATE INDEX 使用EXPLAIN ANALYZE进行测试以获取查询计划之外的实际时间。

当然所有the usual advice for performance optimization也适用。

答案 1 :(得分:0)

我试图用一个很大的表(> 100m条记录)做类似的事情,发现使用Offset / Limit会降低性能。 前10m个记录的偏移量(限制为1)约为1.5分钟,并且以指数方式增长。 记录到5000万,我每次选择最多需要3分钟-甚至使用子查询。

我遇到了一条帖子here which details useful alternatives

我对此做了些微修改以满足自己的需求,并想出了一种方法,可以使我快速获得结果。

CREATE TEMPORARY TABLE 
just_index AS SELECT ROW_NUMBER() 
OVER (ORDER BY [VALUE-You-need]), [VALUE-You-need] 
FROM [your-table-name];

这是一次过的活动-花费了大约4分钟,但随后我拥有了想要的所有值 接下来是创建一个在我需要的“偏移”处循环的函数:

create or replace
function GetOffsets () 
returns void as $$ 
declare 
-- For this part of the function I only wanted values after 90 million up to 120 million
counter bigint := 90000000;
maxRows bigInt := 120000000;
begin
drop table if exists OffsetValues;
create temp table OffsetValues
(
    offset_myValue bigint
);

while counter <= maxRows loop 
    insert into OffsetValues(offset_myValue)
    select [VALUE-You-need] from just_index where row_number > counter
    limit 1;

    -- here I'm looping every 500,000 records - this is my 'Offset'
    counter := counter + 500000 ;
end loop ;
end ;$$ LANGUAGE plpgsql;

然后运行功能:

select GetOffsets();

再次,一次过的时间(我从〜3分钟获得我的偏移值之一到3毫秒获得我的偏移值之一)。 然后从临时表中选择:

select * from OffsetValues;

就性能而言,这对我来说真的非常好-如果可以,我认为我不会使用偏移量。

希望这可以提高任何较大表的性能。