Postgres查询优化(强制索引扫描)

Jef*_*eff 28 postgresql indexing query-optimization postgresql-9.1 postgresql-performance

以下是我的查询.我试图让它使用索引扫描,但它只会seq扫描.

顺便说一下,这个metric_data表有1.3亿行.该metrics表有大约2000行.

metric_data 表格列:

  metric_id integer
, t timestamp
, d double precision
, PRIMARY KEY (metric_id, t)
Run Code Online (Sandbox Code Playgroud)

如何让此查询使用我的PRIMARY KEY索引?

SELECT
    S.metric,
    D.t,
    D.d
FROM metric_data D
INNER JOIN metrics S
    ON S.id = D.metric_id
WHERE S.NAME = ANY (ARRAY ['cpu', 'mem'])
  AND D.t BETWEEN '2012-02-05 00:00:00'::TIMESTAMP
              AND '2012-05-05 00:00:00'::TIMESTAMP;
Run Code Online (Sandbox Code Playgroud)

说明:

Hash Join  (cost=271.30..3866384.25 rows=294973 width=25)
  Hash Cond: (d.metric_id = s.id)
  ->  Seq Scan on metric_data d  (cost=0.00..3753150.28 rows=29336784 width=20)
        Filter: ((t >= '2012-02-05 00:00:00'::timestamp without time zone)
             AND (t <= '2012-05-05 00:00:00'::timestamp without time zone))
  ->  Hash  (cost=270.44..270.44 rows=68 width=13)
        ->  Seq Scan on metrics s  (cost=0.00..270.44 rows=68 width=13)
              Filter: ((sym)::text = ANY ('{cpu,mem}'::text[]))
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 44

出于测试目的,您可以通过"禁用"顺序扫描来强制使用索引 - 最好只在当前会话中使用:

SET enable_seqscan = OFF;
Run Code Online (Sandbox Code Playgroud)

手册中的详细信息在这里.我引用了"禁用",因为您实际上无法禁用顺序表扫描.但是现在任何其他可用选项都适用于Postgres.这将证明(metric_id, t) 可以使用多列索引- 只是不如前导列上的索引有效.

你可能通过切换你的PRIMARY KEY(以及用它在窗帘后面实现它的索引)中的列顺序来获得更好的结果(t, metric_id).或者使用相反的列创建一个额外的索引.

您通常不必通过手动干预强制更好的查询计划.如果设置 enable_seqscan = OFF导致一个更好的计划,一些可能是不正确的在你的数据库.考虑这个相关的答案:

  • 手册中没有任何内容说明为什么使用提示是错误的。它只是说它们应该被视为临时解决方案,但该声明没有任何依据。我正在处理一个运行时间为 1500 毫秒的查询,但在没有参数的 TVF 中,它会进行完整扫描,运行时间超过 2 分钟。禁用完整扫描修复。它将进入生产人员手中!PostgreSQL 社区对提示的诽谤需要结束!所有其他专业都支持他们。查询优化器的作者并非绝对正确。 (2认同)