【问题标题】:Index for a WHERE clause with datetime, and more带有日期时间等的 WHERE 子句的索引
【发布时间】:2012-10-16 21:17:49
【问题描述】:

我使用的是 Postgres 9.1,但查询的执行速度非常慢。

查询:

Explain Analyze SELECT COUNT(DISTINCT email) FROM "invites" WHERE (
 created_at < '2012-10-10 21:08:05.259200'
 AND invite_method = 'email' 
 AND accept_count = 0 
 AND reminded_count < 3 
 AND (last_reminded_at IS NULL OR last_reminded_at < '2012-10-10 21:08:05.261483'))

结果:

Aggregate  (cost=19828.24..19828.25 rows=1 width=21) (actual time=11395.903..11395.903 rows=1 loops=1)
  ->  Seq Scan on invites  (cost=0.00..18970.57 rows=343068 width=21) (actual time=0.036..353.121 rows=337143 loops=1)
        Filter: ((created_at < '2012-10-10 21:08:05.2592'::timestamp without time zone) AND (reminded_count < 3) AND ((last_reminded_at IS NULL) OR (last_reminded_at < '2012-10-10 21:08:05.261483'::timestamp without time zone)) AND ((invite_method)::text = 'email'::text) AND (accept_count = 0))
Total runtime: 11395.970 ms

如您所见,这大约需要 11 秒。我将如何添加索引以优化此查询性能?

【问题讨论】:

标签: sql performance postgresql indexing postgresql-performance


【解决方案1】:

仅仅索引像Jim advises 这样的“一切”并不是一个非常有效的策略。索引需要维护成本,并且组合许多单独的索引比一个定制的索引更昂贵(维护和查询)。这始终取决于您的整体情况。

对于只读或很少写入的表而言,索引的成本较低,但对于具有大量写入操作的易失性表而言,索引成本较高。另一个缺点是索引禁止 HOT-Updates(仅堆元组)更改涉及的列。见:

如果特定查询的性能很重要,partial multi-column index 将是一个不错的策略。专业化,但比所有相关列上的单个索引更便宜、更快。经验法则是...

  • 将易变条件的列(因查询而异)放入索引中。
  • WHERE 子句中使用稳定条件(每个查询都相同)来缩小索引的分区范围。

从您的列名来看(由于缺乏信息),accept_count = 0 似乎是这里最具选择性(和稳定)的过滤器,而 created_atlast_reminded_at 可能会不断变化。所以可能是这样的:

CREATE INDEX invites_special_idx
ON     invites (created_at, last_reminded_at)
WHERE  accept_count = 0
AND    invite_method = 'email'
AND    reminded_count < 3;

排序created_atlast_reminded_at 升序 以完美匹配查询 - 无论如何这恰好是默认值。这样,系统可以在一次扫描中从索引顶部获取所有相关行。应该很快。

正如我们在您之前的一个问题中所讨论的,在索引上对表进行集群可能会有所帮助。请务必阅读有关CLUSTER 的手册。
正如@Craig 提供的那样,您不能在部分索引上使用CLUSTER。由于CLUSTER 是一次性操作(效果会随着以后的写入操作而降低),您可以通过创建full 索引、CLUSTER 表并再次删除索引来规避此限制。喜欢:

CREATE INDEX invites_special_idx2 ON invites (created_at, last_reminded_at);
CLUSTER invites USING invites_special_idx2;
DROP INDEX invites_special_idx2;

CLUSTER 仅在没有其他与数据分发要求相矛盾的重要查询时才有用。

PostgreSQL 9.2 有几个新功能可以让您的查询更快。特别是仅索引扫描 (first item in the release notes)。考虑升级。

【讨论】:

  • 您不能在部分索引上CLUSTER,因此需要一个全范围索引。
  • @CraigRinger:好点。 CLUSTER不适用..我提供了一种解决方法。
【解决方案2】:

您应该为 email、created_at、invite_method、accept_count、remind_count 和 last_remitted 添加索引。通常,WHERE 语句左侧的任何内容。

【讨论】:

    猜你喜欢
    • 2020-09-16
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 2018-10-06
    • 2023-03-21
    相关资源
    最近更新 更多