【发布时间】:2013-08-29 10:46:36
【问题描述】:
我有以下选择,在大型数据库上,它很慢:
SELECT eventid
FROM track_event
WHERE inboundid IN (SELECT messageid FROM temp_message);
temp_message 表很小(100 行),只有一列(messageid varchar),列上有一个 btree 索引。
track_event 表有 19 列和近 1300 万行。此查询中使用的列(eventid bigint 和 inboundid varchar)都有 btree 索引。
我无法从大数据库复制/粘贴解释计划,但这是来自具有相同架构的较小数据库(track_event 中只有 348 行)的计划:
explain analyse SELECT eventid FROM track_event WHERE inboundid IN (SELECT messageid FROM temp_message);
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------
Nested Loop Semi Join (cost=0.00..60.78 rows=348 width=8) (actual time=0.033..3.186 rows=348 loops=1)
-> Seq Scan on track_event (cost=0.00..8.48 rows=348 width=25) (actual time=0.012..0.860 rows=348 loops=1)
-> Index Scan using temp_message_idx on temp_message (cost=0.00..0.48 rows=7 width=32) (actual time=0.005..0.005 rows=1 loops=348)
Index Cond: ((temp_message.messageid)::text = (track_event.inboundid)::text)
Total runtime: 3.349 ms
(5 rows)
在大型数据库上,此查询大约需要 450 秒。任何人都可以看到任何明显的加速吗?我注意到解释计划中的 track_event 上有一个 Seq Scan - 我想我想失去它,但无法确定我可以使用哪个索引。
编辑
Postgres 9.0
track_event 表是一个非常大的复杂架构的一部分,我无法对其进行重大更改。这是信息,包括我刚刚添加的新索引:
Table "public.track_event"
Column | Type | Modifiers
--------------------+--------------------------+-----------
eventid | bigint | not null
messageid | character varying | not null
inboundid | character varying | not null
newid | character varying |
parenteventid | bigint |
pmmuser | bigint |
eventdate | timestamp with time zone | not null
routeid | integer |
eventtypeid | integer | not null
adminid | integer |
hostid | integer |
reason | character varying |
expiry | integer |
encryptionendpoint | character varying |
encryptionerror | character varying |
encryptiontype | character varying |
tlsused | integer |
tlsrequested | integer |
encryptionportal | integer |
Indexes:
"track_event_pk" PRIMARY KEY, btree (eventid)
"foo" btree (inboundid, eventid)
"px_event_inboundid" btree (inboundid)
"track_event_idx" btree (messageid, eventtypeid)
Foreign-key constraints:
"track_event_parent_fk" FOREIGN KEY (parenteventid) REFERENCES track_event(eventid)
"track_event_pmi_route_fk" FOREIGN KEY (routeid) REFERENCES pmi_route(routeid)
"track_event_pmim_smtpaddress_fk" FOREIGN KEY (pmmuser) REFERENCES pmim_smtpaddress(smtpaddressid)
"track_event_track_adminuser_fk" FOREIGN KEY (adminid) REFERENCES track_adminuser(adminid)
"track_event_track_encryptionportal_fk" FOREIGN KEY (encryptionportal) REFERENCES track_encryptionportal(id)
"track_event_track_eventtype_fk" FOREIGN KEY (eventtypeid) REFERENCES track_eventtype(eventtypeid)
"track_event_track_host_fk" FOREIGN KEY (hostid) REFERENCES track_host(hostid)
"track_event_track_message_fk" FOREIGN KEY (inboundid) REFERENCES track_message(messageid)
Referenced by:
TABLE "track_event" CONSTRAINT "track_event_parent_fk" FOREIGN KEY (parenteventid) REFERENCES track_event(eventid)
TABLE "track_eventaddress" CONSTRAINT "track_eventaddress_track_event_fk" FOREIGN KEY (eventid) REFERENCES track_event(eventid)
TABLE "track_eventattachment" CONSTRAINT "track_eventattachment_track_event_fk" FOREIGN KEY (eventid) REFERENCES track_event(eventid)
TABLE "track_eventrule" CONSTRAINT "track_eventrule_track_event_fk" FOREIGN KEY (eventid) REFERENCES track_event(eventid)
TABLE "track_eventthreatdescription" CONSTRAINT "track_eventthreatdescription_track_event_fk" FOREIGN KEY (eventid) REFERENCES track_event(eventid)
TABLE "track_eventthreattype" CONSTRAINT "track_eventthreattype_track_event_fk" FOREIGN KEY (eventid) REFERENCES track_event(eventid)
TABLE "track_quarantineevent" CONSTRAINT "track_quarantineevent_track_event_fk" FOREIGN KEY (eventid) REFERENCES track_event(eventid)
【问题讨论】:
-
1) mesaage_id 是否有任何理由成为 varchar 类型? 2)也许添加一个代理主键,将其用作FK,并在文本列上添加一个唯一约束? 3) 也许更喜欢
EXISTS(...) toIN (...)`? (虽然计划已经显示了索引扫描)0)请在问题中添加表定义。 0a) 和可调参数 (random_page_cost, work_mem, ?) -
顺便说一句:索引条件上的演员
((temp_message.messageid)::text = (track_event.inboundid)::text)非常可疑我无法在这里重现它(pg9.3beta:我只得到 hashjoins;即使对于 varchar 键)。 Postgres 版本? 表定义 ? -
正如 joop 所说,添加您的 Postgres 版本。没有计划和版本就不能给出答案。
-
解决了!一些答案非常有用,尽管没有一个是一针见血的。我遇到了问题,因为测试数据库非常小,因此两个数据库之间的查询行为不同,导致了一些混乱。最后,在 track_event 表上运行分析让它使用索引,几分钟的查询下降到毫秒。
-
下次请发布真实查询。使用真实的模式和真实的数据。和真正的调音。这将为一些真实的人节省很多猜测。谢谢。
标签: sql postgresql