索引以提高范围查询的性能

Jon*_*han 6 postgresql performance index

我在 Postgres 8.2 数据库中有一个与此类似的关系:

CREATE TABLE foo (
    foo_id varchar(160) NOT NULL,
    bar_id varchar(160) NOT NULL,
    created bigint NOT NULL,
    PRIMARY KEY (foo_id, bar_id)
);
Run Code Online (Sandbox Code Playgroud)

让我们暂时搁置 PK 是复合的并使用 varchars(不是我的选择,遗留产品等)这一事实。

目前,我们的应用程序从不发出包含created在 WHERE 子句中的查询,因此它没有被索引。但是,我们有一个新要求,要求我们查询一系列created值。建议的查询是这样的:

SELECT * FROM foo WHERE foo_id IN (...) AND created > 1234 AND created <= 6789
Run Code Online (Sandbox Code Playgroud)

foo表在我们的应用程序中很容易成为最大的,但即便如此,即使在最大的部署中也很可能少于 50,000 行,并且很少有超过十多行具有相同的foo_id.

我的问题是,created考虑foo_id到 PK 的一部分,是否应该在列上添加索引?如果是这样,仅对created列进行索引还是对 ( foo_id, created)进行索引有意义吗?

我对上述语句的 EXPLAIN 显示正在使用 PK,然后正在应用 FILTER 操作。使用测试数据,性能似乎不错。如果表增长到很大,我担心的是性能。

谢谢!

Jac*_*las 8

如果您有索引,created那么规划器将需要在使用该索引或 PK(或全表扫描)之间进行选择 - 它不会同时受益于两者

- 编辑

正如@jug 在下面的评论中指出的那样,至少从 8.1 开始,这并不准确:规划器可能会选择构建两个内存中的位图并将它们组合起来以获得结果集。随着表变大,这会变得更加昂贵,因此规划器可能会根据表的大小和使用一个索引然后过滤的估计成本来选择不这样做。

--结束编辑

只有在某些情况下使用新索引比通过 PK 访问更有效时,新索引才会有用。可能导致这种情况的事情包括:

  • 大量的 (...)SELECT * FROM foo WHERE foo_id IN (...) AND created > 1234 AND created <= 6789
  • 小范围,例如 created > 6780 AND created <= 6790

除非一个或两个可能发生,否则您不应创建二级索引 - 如果可能,最好测试每个使用和不使用索引的场景,看看是否有任何性能优势值得付出代价(例如增加存储和开销用于insertupdate操作)

  • @Jonathan - 所以你大概是在使用子查询:) 50000 对于“嵌套循环”类型的操作来说肯定是“大”的。您可能希望将其他列附加到索引(仍然以 `created` 开头),如果这样做可以避免访问该表 - 或者查看 postgres 对 [clustering](http://www.postgresql.org) 的看法/docs/8.2/static/sql-cluster.html)(不幸的是需要每隔一段时间重复一次) (2认同)