我有一個樣本日曆,如應用程序存儲事件,它們的重複和事件重複規則。這裏是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