我有 PostgreSQL 表,每个表都有数百万条记录和一百多个字段。
其中之一是日期字段,我们在查询中对此进行过滤。为这个日期字段创建索引提高了读取小范围日期的查询的性能,但在大范围的日期中,性能下降了......
我必须优先考虑其中一个吗?可以在不减少大范围查询的情况下提高小范围的性能吗?
我有 PostgreSQL 表,每个表都有数百万条记录和一百多个字段。
其中之一是日期字段,我们在查询中对此进行过滤。为这个日期字段创建索引提高了读取小范围日期的查询的性能,但在大范围的日期中,性能下降了......
我必须优先考虑其中一个吗?可以在不减少大范围查询的情况下提高小范围的性能吗?
仅使用索引中的信息无法回答 PostgreSQL 中的查询。从正在执行的查询的角度来看,该行是否可见,都存储在主行本身中。因此,当您向某事物添加索引并执行使用它的查询时,涉及两个步骤:
因此,使用索引回答查询可能需要比直接访问数据块并获取行更长的时间。发生这种情况的最常见情况是,如果您实际上正在获取大部分数据。通常,如果使用了超过 20% 的表,则认为仅按顺序访问它会很快。有时规划者认为不到 20% 会被访问,所以首选索引,但事实并非如此;这是添加索引会减慢查询速度的一种方式。根据您的描述,这可能是您所看到的情况——如果大范围涉及的表比优化器估计的要多,则使用索引可能会导致速度下降。
为了解决这个问题,数据库收集每个表中每一列的统计信息,以确定特定的 WHERE 条件是否具有足够的选择性以使用索引。这个想法是你需要通过不读取整个表来保存这么多块,在它上面添加索引 I/O 仍然是一个净赢。
这种计算可能会出错,因此在某些情况下,您最终会执行比直接读取表更多的 I/O。如果您使用 EXPLAIN ANALYZE 运行查询,则会显示其中大多数的原因。如果“预期”值与“实际”数字非常不同,这可能表明优化器对表的统计信息不正确。另一种可能性是优化器在查询的选择性方面犯了一个错误——它认为它只会返回少量的行,但实际上它返回了大部分的表。再次,更好的统计数据是开始工作的正常方式。如果您使用的是 PostgreSQL 8.3 或更早版本,默认情况下收集的统计信息量非常低。
一些工作负载最终也会调整 random_page_cost 可调参数,该可调参数控制此索引与表扫描权衡发生的位置。不过,这只是在检查统计信息后才需要考虑的事情。请参阅Tuning Your PostgreSQL Server以了解您可以在此处调整的几项内容。
为这个日期字段创建索引提高了读取小范围日期的查询的性能,但在大范围的日期中,性能下降了......
尝试使用该索引对表进行聚类。性能下降可能是由于整个表在大范围内打开。如果是这样,沿着该索引对表进行聚类将导致更少的磁盘查找。
两个建议:
1)调查table inheritance
时间序列数据的使用。例如,每月创建一个子表,然后对每个表的日期进行 INDEX。PostgreSQL 足够聪明,只能index_scan
在日期范围内具有实际数据的子表上执行 's。一旦子表因为是新月份而被“密封”,CLUSTER
请在表上运行以按日期对数据进行排序。
2)看看创建一堆INDEX
使用WHERE
子句的's。
建议 #1 将成为长期的赢家,但需要一些工作来设置(但将永远扩展/运行),但如果您关心扫描的日期范围有限,建议 #2 可能是一个快速的临时修复。请记住,您只能在'子句中使用IMMUTABLE
函数。INDEX
WHERE
CREATE INDEX tbl_date_2011_05_idx ON tbl(date) WHERE date >= '2011-05-01' AND date <= '2011-06-01';
我会尝试几件事: