我有一个像这样定义的表:
CREATE TABLE sessions (
session_id BIGSERIAL PRIMARY KEY,
session_start TIMESTAMP NOT NULL,
session_end TIMESTAMP NOT NULL,
site_id BIGINT NOT NULL,
photo_id BIGINT NOT NULL,
uuid TEXT NOT NULL
)
CREATE INDEX sessions_lookup ON sessions (
site_id, photo_id, uuid, session_start, session_end
)
我需要针对它运行此类型的查询:
SELECT session_id
FROM sessions
WHERE site_id = %s
AND photo_id = %s
AND uuid = %s
AND %s <@ tsrange(
session_start - interval '3 hours',
session_end + interval '3 hours'
)
范围查询部分有不同的变体(分别检查session_start和session_end,使用OVERLAPS
等等,但据我测试,它们都做同样的事情。)
使用EXPLAIN ANALYZE
我得到以下结果(使用实际值而不是占位符):
Index Scan using sessions_lookup on sessions (cost=0.00..8.30 rows=1 width=8) (actual time=0.062..0.063 rows=1 loops=1)
Index Cond: ((site_id = 10113150) AND (photo_id = 10240980) AND (uuid = '042d6f26-e298-0140-a4cc-7bfd0f9ccd27'::text))
Filter: (((session_start - '03:00:00'::interval) <= '2014-09-05 09:45:38'::timestamp without time zone) AND ((session_end + '03:00:00'::interval) >= '2014-09-05 09:45:38'::timestamp without time zone))
Total runtime: 1.384 ms
(4 rows)
后续运行提供~0.080ms查询运行时。
理想情况下,我想将索引用作时间戳查找的一部分,但它似乎完全被忽略(在索引中有或没有它的结果相同)。我是否需要改变字段的顺序或者我做错了什么(我需要不同类型的索引)吗?
这是在具有45k记录的表格上进行测试,但如果需要,我可以创建更大的样本集。
答案 0 :(得分:1)
初步想法:OVERLAPS
operator的工作方式与重叠(&&
)range operator相似。包含(<@
和变体)运算符稍有不同,但如果要测试单个时间点是否在(日期)时间范围内,它们的工作方式类似。
您的查询背后的原因无法使用您的索引,即您没有直接在查询中测试您的列。您测试了一个范围表达式,它是使用您的列创建的。在这些情况下,您通常可以设置expression based index,但在您的情况下,这也无济于事(已由@CraigRinger's comment提及)。
如果我们可以忘记一些范围和重叠,这里是你的WHERE
子句:
(session_start - interval '3 hours' <= '2014-09-05 09:45:38') AND
(session_end + interval '3 hours' >= '2014-09-05 09:45:38')
让我们做一些数学运算:
(session_start <= '2014-09-05 09:45:38'::timestamp + interval '3 hours') AND
(session_end >= '2014-09-05 09:45:38'::timestamp - interval '3 hours')
现在将使用您的索引。
带参数:
SELECT session_id
FROM sessions
WHERE site_id = %s
AND photo_id = %s
AND uuid = %s
AND (session_start <= %s::timestamp + interval '3 hours')
AND (session_end >= %s::timestamp - interval '3 hours')