我正在设计一些系统来存储包含开始和结束时间的记录.例如:
CREATE TABLE test (
id bigserial PRIMARY KEY,
ts_start timestamp NOT NULL,
ts_end timestamp NOT NULL,
foo bar NOT NULL,
...
);
Run Code Online (Sandbox Code Playgroud)
现在我想对此运行查询以查找与某个时间戳重叠的所有行.这将产生一个where子句,如:
WHERE ts_start <= '2006-4-6 12:34:56' AND ts_end > '2006-4-6 12:34:56'
Run Code Online (Sandbox Code Playgroud)
我用大量生成的测试数据对此进行了测试,性能非常糟糕.我使用ts_start上的索引和ts_end上的另一个索引以及ts_start和ts_end上的多列索引来测试它.最后一个给出了最好的结果,但它仍远未达到最佳状态.
问题是postgresql不知道ts_end保证比ts_start大,所以它使用的计划能够找到ts_end小于ts_start的行.
有什么建议如何解决这个问题?
编辑:对于有这个问题的人,如果你可以再等一会儿,那么PostgreSQL 9.2就有了完美的解决方案:范围类型.9.2现在处于测试阶段,最终版本很可能会在2012年底发布.
有"时间postgres"(谷歌它)但我不知道它是否仍然保持...我相信有讨论将这种类型的搜索包括在postgres但我不记得它的最终状态.无论如何:
使用框和要点的示例:
CREATE TABLE segments( start INTEGER NOT NULL, stop INTEGER NOT NULL, range_box BOX NOT NULL );
INSERT INTO segments SELECT n,n+1,BOX(POINT(n,-1),POINT(n+1,1)) FROM generate_series( 1, 1000000 ) n;
CREATE INDEX segments_box ON segments USING gist( range_box );
CREATE INDEX segments_start ON segments(start);
CREATE INDEX segments_stop ON segments(stop);
EXPLAIN ANALYZE SELECT * FROM segments WHERE 300000 BETWEEN start AND stop;
Index Scan using segments_start on segments (cost=0.00..12959.24 rows=209597 width=72) (actual time=91.990..91.990 rows=2 loops=1)
Index Cond: (300000 >= start)
Filter: (300000 <= stop)
Total runtime: 92.023 ms
EXPLAIN ANALYZE SELECT * FROM segments WHERE range_box && '(300000,0,300000,0)'::BOX;
Bitmap Heap Scan on segments (cost=283.49..9740.27 rows=5000 width=72) (actual time=0.036..0.037 rows=2 loops=1)
Recheck Cond: (range_box && '(300000,0),(300000,0)'::box)
-> Bitmap Index Scan on segments_box (cost=0.00..282.24 rows=5000 width=0) (actual time=0.032..0.032 rows=2 loops=1)
Index Cond: (range_box && '(300000,0),(300000,0)'::box)
Total runtime: 0.064 ms
Run Code Online (Sandbox Code Playgroud)
你可以看到gist索引在这里非常快(1500次!lol)(并且你可以使用许多运算符,如重叠,包含,包含等等)
http://www.postgresql.org/docs/8.2/static/functions-geometry.html
| 归档时间: |
|
| 查看次数: |
7318 次 |
| 最近记录: |