我有一个样本日历,如应用程序存储事件,它们的重复和事件重复规则。这里是PostgreSQL中的数据库模式:Seq Scan在桌上扫描的原因是什么?
CREATE TABLE event
(
id serial NOT NULL,
title character varying(2000) NOT NULL,
description character varying(2000) DEFAULT NULL::character varying,
location character varying(2000) DEFAULT NULL::character varying,
CONSTRAINT pk_event_id PRIMARY KEY (id)
)
CREATE TABLE event_repeat_rule
(
id serial NOT NULL,
event_id integer NOT NULL,
start_date bigint NOT NULL,
end_date bigint,
count integer,
repeat_type repeat_t NOT NULL,
fixed_interval integer NOT NULL,
day_of_month integer[] NOT NULL,
day_of_week integer[] NOT NULL,
week_of_month week_of_month_t[] NOT NULL,
month_of_year integer[] NOT NULL,
CONSTRAINT pk_event_repeat_rule PRIMARY KEY (id),
CONSTRAINT fk_event_repeat_rule FOREIGN KEY (event_id)
REFERENCES event (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT uq_event_repeat_rule_event_id UNIQUE (event_id)
)
-- each event can be labeled with multiple tags. Tag table is not shown here.
CREATE TABLE event_tag
(
id serial NOT NULL,
event_id integer NOT NULL,
tag_id integer NOT NULL,
CONSTRAINT pk_event_tag_id PRIMARY KEY (id),
CONSTRAINT fk_event_tag_event_id FOREIGN KEY (event_id)
REFERENCES event (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT fk_event_tag_tag_id FOREIGN KEY (tag_id)
REFERENCES tag (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT uq_evnet_tag_event_id_tag_id UNIQUE (event_id, tag_id)
)
CREATE INDEX idx_event_tag_tag_id
ON event_tag
USING btree
(tag_id);
CREATE TABLE event_time
(
id serial NOT NULL,
event_id integer NOT NULL,
start_time bigint NOT NULL,
end_time bigint,
CONSTRAINT pk_event_time_id PRIMARY KEY (id),
CONSTRAINT fk_event_time_event_id FOREIGN KEY (event_id)
REFERENCES event (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)
CREATE INDEX idx_event_time_event_id_start_time_end_time
ON event_time
USING btree
(event_id, start_time, end_time);
模式的总体描述:每个事件都有重复规则与否。每个事件都可以用标签进行标记(与标签表有多对多关系)。并且每个事件(单个或重复)的所有时间在event_time
表中,所以关系是1到很多。 event_time
表中(event_id, start_time, end_time)
有索引。
我根据tag_id
和start_time
查询此架构。这是我的查询:
SELECT * FROM
event_time
JOIN event ON event_time.event_id = event.id
JOIN event_tag ON event_tag.event_id = event.id
LEFT OUTER JOIN event_repeat_rule ON event.id = event_repeat_rule.event_id
WHERE event_tag.tag_id = 1
AND event_time.start_time <= 1411465037
AND event_time.end_time >= 1408873037;
当我运行此查询此查询与EXPLAIN
,我得到这个:
Nested Loop Left Join (cost=3.08..15.75 rows=2 width=587)
-> Hash Join (cost=2.93..9.75 rows=2 width=423)
Hash Cond: (event_time.event_id = event.id)
-> Seq Scan on event_time (cost=0.00..6.69 rows=22 width=24)
Filter: ((start_time <= 1411465037) AND (start_time >= 1408873037))
-> Hash (cost=2.87..2.87 rows=5 width=399)
-> Hash Join (cost=1.52..2.87 rows=5 width=399)
Hash Cond: (event.id = event_tag.event_id)
-> Seq Scan on event (cost=0.00..1.17 rows=17 width=386)
-> Hash (cost=1.45..1.45 rows=6 width=13)
-> Seq Scan on event_tag (cost=0.00..1.45 rows=6 width=13)
Filter: (tag_id = 1)
-> Index Scan using uq_event_repeat_rule_event_id on event_repeat_rule (cost=0.15..2.99 rows=1 width=164)
Index Cond: (event.id = event_id)
我在几乎所有的表越来越Seq Scan
。低的记录数可能是原因。但我不想要基于估计的设计。我的索引event_time
表是(event_id, start_time, end_time)
能满足这个查询吗?
我们通常要求CREATE TABLE和INSERT语句,所以我们可以把时间花在你的问题上,而不是花时间对你的模式进行逆向工程。你的CREATE TABLE语句不可用,因为它们的立场;我们没有用户定义的类型(repeat_t等)。 – 2014-09-23 11:26:51
@ MikeSherrill'CatRecall'实际的问题是如何以正确的方式使用索引。但我不能指望你在没有查看模式的情况下回答......所以最重要的字段是“PRIMARY KEY”和“FOREIGN KEY”和索引列。 – 2014-09-23 11:54:28
“start_date bigint”,数据类型DATE或TIMESTAMP出了什么问题?阅读,使用和测试更容易。 – 2014-09-23 13:32:44