我有一个表,我在限制和偏移量之前进行排序,以便分页.

在ORDER BY列上添加索引会对性能产生巨大影响(当与小限制结合使用时).在一个500000行的表中,我看到添加索引时有10000x的改进,只要有一个小的限制.

但是,索引对高偏移量(即我的分页中较晚的页面)没有影响.这是可以理解的:b-tree索引使得从头开始按顺序迭代很容易,但找不到第n个项目.

看起来counted b-tree index会有帮助,但我不知道PostgreSQL是否支持这些.还有其他解决办法吗?对于大偏移量的优化(特别是在分页用例中)似乎并不少见.

不幸的是,PostgreSQL手册只是简单地写道:"OFFSET子句跳过的行仍然需要在服务器内部计算;因此,较大的偏移量可能效率不高."

推荐答案

您可能需要计算索引.

让我们创建一个表:

create table sales(day date, amount real);

然后用一些随机的东西填满它:

insert into sales 
    select current_date + s.a as day, random()*100 as amount
    from generate_series(1,20);

按天编制索引,这里没有什么特别之处:

create index sales_by_day on sales(day);

创建行位置函数.还有其他方法,这是最简单的方法:

create or replace function sales_pos (date) returns bigint 
   as 'select count(day) from sales where day <= $1;' 
   language sql immutable;

判断它是否有效(但不要在大型数据集上这样称呼它):

select sales_pos(day), day, amount from sales;

     sales_pos |    day     |  amount  
    -----------+------------+----------
             1 | 2011-07-08 |  41.6135
             2 | 2011-07-09 |  19.0663
             3 | 2011-07-10 |  12.3715
    ..................

现在是棘手的部分:添加另一个根据Sales_pos函数值计算的索引:

create index sales_by_pos on sales using btree(sales_pos(day));

下面是你如何使用它.5是你的"补偿",10是"限制":

select * from sales where sales_pos(day) >= 5 and sales_pos(day) < 5+10;

        day     | amount  
    ------------+---------
     2011-07-12 | 94.3042
     2011-07-13 | 12.9532
     2011-07-14 | 74.7261
    ...............

它很快,因为当您这样调用它时,postgres使用索引中的预先计算的值:

explain select * from sales 
  where sales_pos(day) >= 5 and sales_pos(day) < 5+10;

                                    QUERY PLAN                                
    --------------------------------------------------------------------------
     Index Scan using sales_by_pos on sales  (cost=0.50..8.77 rows=1 width=8)
       Index Cond: ((sales_pos(day) >= 5) AND (sales_pos(day) < 15))

希望有帮助.

Database相关问答推荐

如何使用 Gramex FormHandler 动态(在运行时)创建或更改数据库模式

任何必要的可空外键示例?

为什么引用 SQLite rowid 会导致外键不匹配?

什么是Open Schema的数据库?

MongoDB和Redis有什么区别?

Sql更新查询

在 Oracle 中查找数据库的大小

如何将正在使用的数据库复制到django中的其他数据库?

如何在 SQL Server 中生成随机数据?

Membase 和 Couchbase 有什么区别?

Oracle 和 SQL Server 中的 NVARCHAR 之间的区别?

如何找到 Oracle 数据库的 URL?

使用varchar作为主键?

Android Room:如何建模关系?

使用十进制数据类型(MySQL / Postgres)是否会影响性能

您最喜欢在 django 中管理数据库迁移的解决方案是什么?

使用 PHP 和 MySQL 开发测验Web 应用程序的数据库设计

Google 的 Bigtable 与关系数据库

如何在 SQL Server 中生成并手动插入唯一标识符?

字符串列上的postgresql索引