Postgres没有使用超过某个行限制的索引?

时间:2016-02-26 15:21:13

标签: postgresql postgresql-9.4 sql-execution-plan

有一个这样的测试表:

testdb=> \d test_table
                                             Table "public.test_table"
           Column           |            Type             |                         Modifiers
----------------------------+-----------------------------+-----------------------------------------------------------
 id                         | integer                     | not null default nextval('test_table_id_seq'::regclass)
 phone                      | character varying(15)       | not null
 comment                    | text                        |
 timestamp                  | timestamp without time zone | not null
Indexes:
    "test_table_pkey" PRIMARY KEY, btree (id)
    "i_test_substr" btree ("substring"(phone::text, 1, 1), "timestamp" DESC)
Triggers:

使用这样的索引:

testdb=> create index i_test_substr ON test_table (substring(phone, 1, 1), timestamp desc);

这些查询将使用索引在203行的限制下排序,但会在内存中排序超过204行。

任何人都可以解释这种行为吗?

testdb=> explain analyze select * from test_table where substring(phone,1 ,1) = '2' order by timestamp desc limit 203;
                                                                QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.42..709.52 rows=203 width=202) (actual time=0.043..0.194 rows=203 loops=1)
   ->  Index Scan using i_test_substr on test_table  (cost=0.42..1146.16 rows=328 width=202) (actual time=0.041..0.170 rows=203 loops=1)
         Index Cond: ("substring"((phone)::text, 1, 1) = '2'::text)
 Total runtime: 0.249 ms
(4 rows)



testdb=> explain analyze select * from test_table where substring(phone,1 ,1) = '2' order by timestamp desc limit 204;
                                                               QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=711.74..712.25 rows=204 width=202) (actual time=7.655..7.681 rows=204 loops=1)
   ->  Sort  (cost=711.74..712.56 rows=328 width=202) (actual time=7.653..7.664 rows=204 loops=1)
         Sort Key: "timestamp"
         Sort Method: top-N heapsort  Memory: 53kB
         ->  Bitmap Heap Scan on test_table  (cost=10.96..698.03 rows=328 width=202) (actual time=1.340..5.010 rows=11514 loops=1)
               Recheck Cond: ("substring"((phone)::text, 1, 1) = '2'::text)
               ->  Bitmap Index Scan on i_test_substr  (cost=0.00..10.88 rows=328 width=0) (actual time=1.217..1.217 rows=11514 loops=1)
                     Index Cond: ("substring"((phone)::text, 1, 1) = '2'::text)
 Total runtime: 7.746 ms
(9 rows)

1 个答案:

答案 0 :(得分:0)

简而言之,如果要返回的行太多,使用索引扫描会变得很昂贵。索引扫描将为每行加载磁盘页面,使它们显示在索引中。因此,一些页面将被加载多次(可能多次)。位图索引扫描首先制作一种磁盘页面列表,然后才加载它们一次。

因此,优化程序会计算每个可能计划的成本,并决定哪个计划最便宜。