【问题标题】:Postgresql multicolumn index for BETWEEN and ORDER BY用于 BETWEEN 和 ORDER BY 的 Postgresql 多列索引
【发布时间】:2019-06-26 10:44:44
【问题描述】:

我有具有以下结构的大表(100M 记录)。

  length   |          created_at
-----------+-------------------------------
 506225551 | 2018-12-29 02:08:34.116618
 133712971 | 2018-10-19 21:20:14.568936
 608443439 | 2018-12-14 03:22:55.141416
 927160571 | 2019-01-30 00:51:41.639126
 407033524 | 2018-11-16 21:26:41.523047
 506008096 | 2018-11-17 00:07:42.839919
 457719749 | 2018-11-12 02:32:53.116225
  • 0 < length < 1000000000
  • '2017-01-01' < created_at < '2019-02-01'
  • lengthcreated_at 的数据均匀分布。

我想运行这样的查询

SELECT * FROM tbl WHERE length BETWEEN 2000000 and 3000000 ORDER BY  created_at DESC

2000000 到 3000000 之间有 100K 个结果,所以我想使用索引进行选择和排序。

我已经尝试过这些方法

1。简单的 BTREE 索引

create index on tbl(length);

这适用于length 的短距离,但我不能使用这个索引来记录订购记录。

2。多列BTREE索引

 create index on tbl(length, created_at);

这个索引我只能用于这样的查询

 SELECT * FROM tbl WHERE length = 2000000 ORDER BY  created_at DESC

3。带有 btree_gist 扩展名的 GIST 索引。我希望,这个索引应该可以工作。

create index on tbl using gist(length, created_at);   

但它没有。即使是这样的简单查询,我也无法使用此索引。

test=# explain analyze select * from gist_test where a = 345 order by c desc;

                                                                QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=25706.37..25730.36 rows=9597 width=12) (actual time=4.839..5.568 rows=10000 loops=1)
   Sort Key: c DESC
   Sort Method: quicksort  Memory: 853kB
   ->  Bitmap Heap Scan on gist_test  (cost=370.79..25071.60 rows=9597 width=12) (actual time=1.402..2.869 rows=10000 loops=1)
         Recheck Cond: (a = 345)
         Heap Blocks: exact=152
         ->  Bitmap Index Scan on gist_test_a_b_c_idx  (cost=0.00..368.39 rows=9597 width=0) (actual time=1.384..1.384 rows=10000 loops=1)
               Index Cond: (a = 345)
 Planning time: 0.119 ms
 Execution time: 6.271 ms

我只能将此索引用作一列上的简单 BTREE。

那么,我该如何解决这个问题呢?

也许没有可以处理此类查询的 SQL 数据库?

【问题讨论】:

  • 我认为不可能创建允许查询任何length 范围的索引。如果可能的范围有限(例如最多 100 个),您可以为每个可能的范围创建部分索引。

标签: postgresql performance indexing nosql b-tree


【解决方案1】:

我认为这是不可能的(至少在 vanilla postgresql 中,我不知道有什么扩展可以帮助解决这个问题)。排序记录的步骤可以跳过,因为索引已经产生了排序的记录。
然而:

  1. doc 中所述,只能使用 B-tree 索引进行排序(这很有意义,它是使用搜索树实现的)。
  2. 您的 where 和您的 order by 与 B 树索引不兼容:
    • 因为有两个子句,所以需要在索引(A, B)中放2列
    • 索引中的数据按(A, B)排序,因此它也按A排序(这就是当where仅在A上时postgresql能够快速索引扫描表的原因),但因此,它在索引中按B 排序(仅在A 为常数的每个子集中按B 排序,但不在整个表中)。
    • 您可能已经知道,由于where,仅在B 上建立索引并没有什么帮助。

提供的示例 #2 显示 postgresql 已针对您过滤单个值 A 的情况进行了很好的优化。

如果对(A, B) 的两列进行排序是不可接受的,那么恐怕你不应该期望更多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-29
    • 1970-01-01
    相关资源
    最近更新 更多