如何告诉Postgres使用索引而不是位图扫描?

时间:2018-07-08 21:00:26

标签: postgresql

如果我添加一个额外的ORDER子句,则Postgres会进行位图扫描,并且性能会惊人地下降(4秒对0.06毫秒)。该应用程序变得无法使用。但是,我只是要求它排序一小部分结果,这些结果会被索引。

应如何修改查询,以便Postgres使用索引而不是位图扫描?因为应该使用索引,所以表中有1亿条记录。

慢速查询,位图扫描:

EXPLAIN ANALYZE
SELECT
        valtr_id,
        from_id,
        to_id,
        from_balance,
        to_balance,
        block_num
FROM value_transfer v
WHERE v.block_num<=2435013 AND v.to_id = 22479 
ORDER BY block_num desc,valtr_id desc
LIMIT 1

 Limit  (cost=1235402.27..1235402.27 rows=1 width=32) (actual time=4665.595..4665.596 rows=1 loops=1)
   ->  Sort  (cost=1235402.27..1238237.41 rows=1134056 width=32) (actual time=4665.594..4665.594 rows=1 loops=1)
         Sort Key: block_num DESC, valtr_id DESC
         Sort Method: top-N heapsort  Memory: 25kB
         ->  Bitmap Heap Scan on value_transfer v  (cost=21229.61..1229731.99 rows=1134056 width=32) (actual time=268.917..4170.374 rows=1102867 loops=1)
               Recheck Cond: (to_id = 22479)
               Rows Removed by Index Recheck: 9412580
               Filter: (block_num <= 2435013)
               Heap Blocks: exact=32392 lossy=132879
               ->  Bitmap Index Scan on vt_to_id_idx  (cost=0.00..20946.10 rows=1134071 width=0) (actual time=254.870..254.870 rows=1102867 loops=1)
                     Index Cond: (to_id = 22479)
 Planning time: 0.290 ms
 Execution time: 4665.634 ms
(13 rows)

现在,如果仅删除一个ORDER条件,查询速度将提高几个数量级。

没有ORDER by valtr_id DESC,我的表现如下:

EXPLAIN ANALYZE
SELECT
        valtr_id,
        from_id,
        to_id,
        from_balance,
        to_balance,
        block_num
FROM value_transfer v
WHERE v.block_num<=2435013 AND v.to_id = 22479 
ORDER BY block_num desc
LIMIT 1

 Limit  (cost=0.57..2.46 rows=1 width=32) (actual time=0.028..0.028 rows=1 loops=1)
   ->  Index Scan using idx_2 on value_transfer v  (cost=0.57..2148650.88 rows=1134056 width=32) (actual time=0.027..0.027 rows=1 loops=1)
         Index Cond: ((to_id = 22479) AND (block_num <= 2435013))
 Planning time: 0.310 ms
 Execution time: 0.060 ms
(5 rows)

如何告诉Postgres首先使用INDEX,然后才使用-对结果进行排序?

我的表是这样定义的:

CREATE TABLE value_transfer (
    valtr_id            BIGSERIAL       PRIMARY KEY,
    tx_id               BIGINT          REFERENCES transaction(tx_id) ON DELETE CASCADE ON UPDATE CASCADE,
    block_id            INT             REFERENCES block(block_id) ON DELETE CASCADE ON UPDATE CASCADE,
    block_num           INT             NOT NULL,
    from_id             INT             NOT NULL,
    to_id               INT             NOT NULL,
    value               NUMERIC         DEFAULT 0,
    from_balance        NUMERIC         DEFAULT 0,
    to_balance          NUMERIC         DEFAULT 0,
    kind                CHAR            NOT NULL,
    depth               INT             DEFAULT 0,
    error               TEXT            NOT NULL
);

我在测试期间创建了许多不同的索引:

      indexname      |                                        indexdef                                         
---------------------+-----------------------------------------------------------------------------------------
 value_transfer_pkey | CREATE UNIQUE INDEX value_transfer_pkey ON public.value_transfer USING btree (valtr_id)
 vt_block_id_idx     | CREATE INDEX vt_block_id_idx ON public.value_transfer USING btree (block_id)
 vt_block_num_idx    | CREATE INDEX vt_block_num_idx ON public.value_transfer USING btree (block_num)
 vt_from_id_idx      | CREATE INDEX vt_from_id_idx ON public.value_transfer USING btree (from_id)
 vt_to_id_idx        | CREATE INDEX vt_to_id_idx ON public.value_transfer USING btree (to_id)
 vt_tx_from_idx      | CREATE INDEX vt_tx_from_idx ON public.value_transfer USING btree (tx_id)
 idx_1               | CREATE INDEX idx_1 ON public.value_transfer USING btree (from_id, block_num DESC)
 idx_2               | CREATE INDEX idx_2 ON public.value_transfer USING btree (to_id, block_num DESC)
 idx_1_rev           | CREATE INDEX idx_1_rev ON public.value_transfer USING btree (block_num DESC, from_id)
 idx_2_rev           | CREATE INDEX idx_2_rev ON public.value_transfer USING btree (block_num DESC, to_id)
 valtr_ordered_idx   | CREATE INDEX valtr_ordered_idx ON public.value_transfer USING btree (valtr_id)
(11 rows)

0 个答案:

没有答案