BETWEEN 和 ORDER BY 的 Postgresql 多列索引
Postgresql multicolumn index for BETWEEN and ORDER BY
我有大量 table(1 亿条记录),结构如下。
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'
length
和 created_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 数据库?
我认为这是不可能的(至少在 vanilla postgresql 中,我不知道可以帮助解决这个问题的扩展)。可以跳过排序记录的步骤,只是因为索引已经产生了排序的记录。
然而:
- 在doc中提到,只能使用B-tree索引进行排序(有道理,是用搜索树实现的)。
- 您的
where
和 order by
与 B 树索引不兼容:
- 因为有两个子句,你需要在索引中放2列
(A, B)
- 索引中的数据按
(A, B)
排序,因此它也按 A
排序(这就是为什么当 where
仅在 A
上),但结果是 而不是 在索引中按 B
排序(它按 B
仅在 A
不变的每个子集中,而不是在整个 table).
- 正如您可能已经知道的那样,由于
where
. ,仅在 B
上建立索引几乎没有帮助
所提供的示例 #2 显示 postgresql 针对您过滤单个值 A
.
的情况进行了很好的优化
如果无法table 对 2 列 (A, B)
进行排序,那么恐怕您不应该期望比这更多。
我有大量 table(1 亿条记录),结构如下。
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'
length
和created_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 数据库?
我认为这是不可能的(至少在 vanilla postgresql 中,我不知道可以帮助解决这个问题的扩展)。可以跳过排序记录的步骤,只是因为索引已经产生了排序的记录。
然而:
- 在doc中提到,只能使用B-tree索引进行排序(有道理,是用搜索树实现的)。
- 您的
where
和order by
与 B 树索引不兼容:- 因为有两个子句,你需要在索引中放2列
(A, B)
- 索引中的数据按
(A, B)
排序,因此它也按A
排序(这就是为什么当where
仅在A
上),但结果是 而不是 在索引中按B
排序(它按B
仅在A
不变的每个子集中,而不是在整个 table). - 正如您可能已经知道的那样,由于
where
. ,仅在
B
上建立索引几乎没有帮助 - 因为有两个子句,你需要在索引中放2列
所提供的示例 #2 显示 postgresql 针对您过滤单个值 A
.
如果无法table 对 2 列 (A, B)
进行排序,那么恐怕您不应该期望比这更多。