我很确定,@kgrittn 对问题的解释是准确的,我喜欢他对行构造函数的优雅使用。在我测试了几个替代方案之后更是如此,但没有一个可以与性能相匹配:
使用 65426 行的真实表格进行测试; 32107 合格。 PostgreSQL 9.1.4,最好的五个EXPLAIN ANALYZE:
SELECT * FROM tbl
WHERE to_char(data, 'MMDD') BETWEEN '0215' AND '0621';
总运行时间:251.188 毫秒
SELECT * FROM tbl
WHERE to_char(data, 'MMDD')::int BETWEEN 215 AND 621;
总运行时间:250.965 毫秒
SELECT * FROM tbl
WHERE to_char(data, 'MMDD') COLLATE "C" BETWEEN '0215' AND '0621';
总运行时间:221.732 毫秒
使用“非语言环境”C 进行字符串比较的速度更快 - 在the manual about collation support 中更多。
SELECT * FROM tbl
WHERE EXTRACT(MONTH FROM data)*100 + EXTRACT(DAY FROM data)
BETWEEN 215 AND 621;
总运行时间:209.965 毫秒
SELECT * FROM tbl
WHERE EXTRACT(MONTH FROM data) BETWEEN 3 AND 5
OR EXTRACT(MONTH FROM data) = 2 AND EXTRACT(DAY FROM data) >= 15
OR EXTRACT(MONTH FROM data) = 6 AND EXTRACT(DAY FROM data) <= 21;
总运行时间:160.169 毫秒
SELECT * FROM tbl
WHERE EXTRACT(MONTH FROM data) BETWEEN 2 AND 6
AND CASE EXTRACT(MONTH FROM data)
WHEN 2 THEN EXTRACT(DAY FROM data) >= 15
WHEN 6 THEN EXTRACT(DAY FROM data) <=21
ELSE TRUE END;
总运行时间:147.390 毫秒
SELECT * FROM tbl
WHERE CASE EXTRACT(MONTH FROM data)
WHEN 3 THEN TRUE
WHEN 4 THEN TRUE
WHEN 5 THEN TRUE
WHEN 2 THEN EXTRACT(DAY FROM data) >= 15
WHEN 6 THEN EXTRACT(DAY FROM data) <= 21
ELSE FALSE END;
总运行时间:131.907 毫秒
@Kevin 的行构造函数解决方案:
SELECT * FROM tbl
WHERE (EXTRACT(MONTH FROM data), EXTRACT(DAY FROM data))
BETWEEN (2, 15) AND (6, 21);
总运行时间:125.460 毫秒
起首。
功能索引更快
唯一的方法就是使用索引。以上查询都不能在data 上使用普通索引。但是,如果读取性能至关重要(并且写入性能的成本很小),您可以求助于functional index:
CREATE INDEX ON tbl(EXTRACT(MONTH FROM data), EXTRACT(DAY FROM data));
SELECT * FROM tbl
WHERE (EXTRACT(MONTH FROM data), EXTRACT(DAY FROM data))
BETWEEN (2, 15) AND (6, 21);
总运行时间:85.895 毫秒
这就是我最终可以击败 Kevin 的查询的地方:使用单列索引而不是他的案例所需的多列索引。
CREATE INDEX ON tbl(
CAST(EXTRACT(MONTH FROM data) * 100 + EXTRACT(DAY FROM data) AS int));
SELECT * FROM tbl
WHERE (EXTRACT(MONTH FROM data) * 100 + EXTRACT(DAY FROM data))::int
BETWEEN 215 AND 621;
总运行时间:84.215 毫秒