在按主键添加订单时,使用主键索引而不是更有针对性的列索引来查询计划程序

时间:2017-05-15 22:44:02

标签: postgresql

请原谅实际查询的简化。只是为了让它可读。目前,在按主键添加订单时,我们的查询速度会降低。

select id, field1, field2
from table1
where field1 = 'value'
limit 1000;

因此拥有field1的索引,此查询使用该索引,这使得查询更快。我可以通过explain命令跟踪查询规划器使用该索引。

通过突然更改用于主键索引的索引来添加订单。这使查询慢了很多。

select id, field1, field2
from table1 where field1 = 'value'
order by id asc
limit 1000;

有没有办法强制查询规划器使用field1索引?

编辑: 实际表格详细信息:

\d fax_message
                     Table "public.fax_message"
          Column          |            Type             | Modifiers 
--------------------------+-----------------------------+-----------
 id                       | bigint                      | not null
 broadcast_ref            | character varying(255)      | 
 busy_retries             | integer                     | 
 cli                      | character varying(255)      | 
 dncr                     | boolean                     | not null
 document_set_id          | bigint                      | not null
 fax_broadcast_attempt_id | bigint                      | 
 fps                      | boolean                     | not null
 header_format            | character varying(255)      | 
 last_updated             | timestamp without time zone | not null
 max_fax_pages            | integer                     | 
 message_ref              | character varying(255)      | 
 must_be_sent_before_date | timestamp without time zone | 
 request_id               | bigint                      | 
 resolution               | character varying(255)      | 
 retries                  | integer                     | 
 send_from                | character varying(255)      | 
 send_ref                 | character varying(255)      | 
 send_to                  | character varying(255)      | not null
 smartblock               | boolean                     | not null
 status                   | character varying(255)      | not null
 time_zone                | character varying(255)      | 
 total_pages              | integer                     | 
 user_id                  | uuid                        | not null
 delay_status_check_until | timestamp without time zone | 
 version                  | bigint                      | default 0
 cost                     | numeric(40,10)              | default 0
Indexes:
    "fax_message_pkey" PRIMARY KEY, btree (id)
    "fax_message_broadcast_ref_idx" btree (broadcast_ref)
    "fax_message_delay_status_check_until" btree (delay_status_check_until)
    "fax_message_document_set_idx" btree (document_set_id)
    "fax_message_fax_broadcast_attempt_idx" btree (fax_broadcast_attempt_id)
    "fax_message_fax_document_set_idx" btree (document_set_id)
    "fax_message_message_ref_idx" btree (message_ref)
    "fax_message_request_idx" btree (request_id)
    "fax_message_send_ref_idx" btree (send_ref)
    "fax_message_status_fax_broadcast_attempt_idx" btree (status, fax_broadcast_attempt_id)
    "fax_message_user" btree (user_id)
Foreign-key constraints:
    "fk2881c4e5106ed2de" FOREIGN KEY (request_id) REFERENCES core_api_send_fax_request(id)
    "fk2881c4e5246f3088" FOREIGN KEY (document_set_id) REFERENCES fax_document_set(id)
    "fk2881c4e555aad98b" FOREIGN KEY (user_id) REFERENCES users(id)
    "fk2881c4e59920b254" FOREIGN KEY (fax_broadcast_attempt_id) REFERENCES fax_broadcast_attempt(id)
Referenced by:
    TABLE "fax_message_status_modifier" CONSTRAINT "fk2dfbe52acb955ec1" FOREIGN KEY (fax_message_id) REFERENCES fax_message(id)
    TABLE "fax_message_attempt" CONSTRAINT "fk82058973cb955ec1" FOREIGN KEY (fax_message_id) REFERENCES fax_message(id)

使用的实际指数:

\d fax_message_status_fax_broadcast_attempt_idx
         Index "public.fax_message_status_fax_broadcast_attempt_idx"
          Column          |          Type          |        Definition        
--------------------------+------------------------+--------------------------
 status                   | character varying(255) | status
 fax_broadcast_attempt_id | bigint                 | fax_broadcast_attempt_id
btree, for table "public.fax_message"

真实查询:

订购方式:

explain select this_.id as id65_0_, this_.version as version65_0_, this_.broadcast_ref as broadcast3_65_0_, this_.busy_retries as busy4_65_0_, this_.cli as cli65_0_, this_.cost as cost65_0_, this_.delay_status_check_until as delay7_5_0_, this_.dncr as dncr65_0_, this_.document_set_id as document9_65_0_, this_.fax_broadcast_attempt_id as fax10_65_0_, this_.fps as fps65_0_, this_.header_format as header12_65_0_, this_.last_updated as last13_65_0_, this_.max_fax_pages as max14_65_0_, this_.message_ref as message15_65_0_, this_.must_be_sent_before_date as must16_65_0_, this_.request_id as request17_65_0_, this_.resolution as resolution65_0_, this_.retries as retries65_0_, this_.send_from as send20_65_0_, this_.send_ref as send21_65_0_, this_.send_to as send22_65_0_, this_.smartblock as smartblock65_0_, this_.status as status65_0_, this_.time_zone as time25_65_0_, this_.total_pages as total26_65_0_, this_.user_id as user27_65_0_ from fax_message this_ where this_.status='TO_CHARGE_GROUP' order by id asc limit 1000;
                                                 QUERY PLAN                                                  
-------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.43..53956.06 rows=1000 width=2234)
   ->  Index Scan using fax_message_pkey on fax_message this_  (cost=0.43..2601902.61 rows=48223 width=2234)
         Filter: ((status)::text = 'TO_CHARGE_GROUP'::text)
(3 rows)

这个没有订单的那个:

explain select this_.id as id65_0_, this_.version as version65_0_, this_.broadcast_ref as broadcast3_65_0_, this_.busy_retries as busy4_65_0_, this_.cli as cli65_0_, this_.cost as cost65_0_, this_.delay_status_check_until as delay7_5_0_, this_.dncr as dncr65_0_, this_.document_set_id as document9_65_0_, this_.fax_broadcast_attempt_id as fax10_65_0_, this_.fps as fps65_0_, this_.header_format as header12_65_0_, this_.last_updated as last13_65_0_, this_.max_fax_pages as max14_65_0_, this_.message_ref as message15_65_0_, this_.must_be_sent_before_date as must16_65_0_, this_.request_id as request17_65_0_, this_.resolution as resolution65_0_, this_.retries as retries65_0_, this_.send_from as send20_65_0_, this_.send_ref as send21_65_0_, this_.send_to as send22_65_0_, this_.smartblock as smartblock65_0_, this_.status as status65_0_, this_.time_zone as time25_65_0_, this_.total_pages as total26_65_0_, this_.user_id as user27_65_0_ from fax_message this_ where this_.status='TO_CHARGE_GROUP'  limit 1000;
                                                              QUERY PLAN                                                               
---------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.56..1744.13 rows=1000 width=2234)
   ->  Index Scan using fax_message_status_fax_broadcast_attempt_idx on fax_message this_  (cost=0.56..84080.59 rows=48223 width=2234)
         Index Cond: ((status)::text = 'TO_CHARGE_GROUP'::text)
(3 rows)

使用fax_message_pkey的查询的开销大于使用fax_message_status_fax_broadcast_attempt_idx的查询的最大开销。 我希望查询仍然会使用fax_message_status_fax_broadcast_attempt_idx索引,即使是那里的订单。

2 个答案:

答案 0 :(得分:0)

根据How do I force Postgres to use a particular index?(以及答案中的链接),似乎没有办法强制使用特定索引。

答案 1 :(得分:0)

CTE是一个优化范围。您没有向我们提供足够的信息来告诉您为什么您的查询计划错误,但如果您不关心实际解决问题,这应该有用。

WITH t AS (

    select id, field1, field2
    from table1
    where field1 = 'value'
    limit 1000

)
SELECT *
FROM t  
order by id asc;