微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

PostgreSQL查询导致cpu峰值达到100%.给出90k记录,是7000的成本吗?

我正在努力了解应如何使用成本和实际时间来优化查询.我的应用程序是带有Postgresql 9.1 db的rails 3.我的查询由Delayed_job使用:

EXPLAIN ANALYZE SELECT  "delayed_jobs".*
FROM "delayed_jobs"
WHERE ((run_at <= '2011-05-23 15:16:43.180810' AND (locked_at IS NULL OR locked_at < '2011-01-25 11:05:28.077144') OR locked_by = 'host:foo pid:2') AND Failed_at IS NULL AND queue = 'authentication_emails')
ORDER BY priority ASC,run_at ASC LIMIT 5

要么:

EXPLAIN ANALYZE SELECT  "delayed_jobs".*
FROM "delayed_jobs"
WHERE ((run_at <= '2011-05-23 15:16:43.180810' AND (locked_at IS NULL OR locked_at < '2011-01-25 11:05:28.077144') OR locked_by = 'host:foo pid:2') AND Failed_at IS NULL )
ORDER BY priority ASC,run_at ASC LIMIT 5

对于第一个查询,输出等于:

Limit  (cost=7097.57..7097.57 rows=1 width=1008) (actual time=35.657..35.657 rows=0 loops=1)
  ->  Sort  (cost=7097.57..7097.57 rows=1 width=1008) (actual time=35.655..35.655 rows=0 loops=1)
        Sort Key: priority,run_at
        Sort Method: quicksort  Memory: 25kB
        ->  Seq Scan on delayed_jobs  (cost=0.00..7097.56 rows=1 width=1008) (actual time=35.648..35.648 rows=0 loops=1)
              Filter: ((Failed_at IS NULL) AND ((queue)::text = 'authentication_emails'::text) AND (((run_at <= '2011-05-23 15:16:43.18081'::timestamp without time zone) AND ((locked_at IS NULL) OR (locked_at < '2011-01-25 11:05:28.077144'::timestamp without time zone))) OR (locked_by = 'host:foo pid:2'::text)))
Total runtime: 35.695 ms

该表目前有90k记录,范围从0到200k.我们注意到这个查询导致cpu出现峰值并导致瓶颈.从上面的解释信息中可以学到什么.索引应该添加到哪里?谢谢

DB Schema ..表有0个索引.

create_table "delayed_jobs",:force => true do |t|
    t.integer  "priority",:default => 0
    t.integer  "attempts",:default => 0
    t.text     "handler"
    t.text     "last_error"
    t.datetime "run_at"
    t.datetime "locked_at"
    t.datetime "Failed_at"
    t.text     "locked_by"
    t.datetime "created_at",:null => false
    t.datetime "updated_at",:null => false
    t.string   "queue"
  end

解决方法

分析

如果您将转到this section of the PostgreSQL documentation,您将了解规划师如何使用统计数据来估算成本.这是非常有用的信息!

如果你说,那个表有90k的记录(并使用default costs),那么行处理的成本将是:

90000 * (cpu_tuple_cost + cpu_operator_cost) = 90000 * 0.0125 = 1125

我们现在可以估算您的表占用的页数:

(7097.56-1125)/seq_page_cost = 5972.56

这使它大约46Mb(认8k页面大小).因此,我假设您的表适合shared_buffers,甚至是认表.

看一下平均行宽我也假设,该表是mostly stored as MAIN.

接下来,您将使用text和string类型的字段作为谓词.不确定它们如何映射到Postgresql内部类型,但我认为它是文本.认情况下,此类型是可压缩的,因此Postgresql必须对每一行执行解压缩以检查谓词.我不确定在哪个阈值压缩开始后,看看this message(和整个线程).

结论

>你还没有向我们展示真正的EXPLAIN(分析)输出,因为我也不认为35ms查询会导致瓶颈,除了……
>您还没有提到在瓶颈时刻有多少会话正在使用您的数据库,而且还不清楚此查询的运行频率.我认为它非常受欢迎.
>您的表似乎适合内存,因此在任何情况下所有操作都将受cpu限制.
>谓词中使用的值是可压缩的,似乎是压缩的.

因此,我说瓶颈来自于数据并行运行的峰值查询量,这需要额外的cpu周期来进行解压缩.

该怎么办?

>规范你的表格.感觉“队列”列的选择性非常低.考虑为它创建external type(如ENUM),或组织具有适当外键的字典表.我也不确定关键字是否被锁定,是否可以归一化?
>在run_at和locked_at列上创建索引.
>索引ON优先级,run_at列将使您的排序受益,但我怀疑它在这种情况下会有所帮助.我假设优先级列的选择性较低,因此规划者更喜欢在run_at和locked_at列上使用Bitmap和Index Scans.

我希望我在这里不是非常错误:)欢迎评论/更正!

附:让我知道它是怎么回事.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐