【问题标题】:Simple Postgres queries running slow on HerokuHeroku 上运行缓慢的简单 Postgres 查询
【发布时间】:2012-10-24 05:47:46
【问题描述】:

我有一个 Movie 模型,大约有 15,000 个项目,一个 Dvd 模型有 3500 个。

以下查询是使用在 Heroku 上运行的 Crane Postgres 数据库的简单 Rails 关联。我想知道为什么以下查询需要这么长时间,以及我最终如何才能减少它的时间。

2012-10-24T05:42:19+00:00 app[postgres]: [30-1] [BLACK] LOG:  duration: 57.914 ms  statement: SELECT  "movies".* FROM "movies"  WHERE "movies"."dvd_id" = 37 ORDER BY scene LIMIT 1
2012-10-24T05:42:20+00:00 app[postgres]: [31-1] [BLACK] LOG:  duration: 77.086 ms  statement: SELECT  "movies".* FROM "movies"  WHERE "movies"."dvd_id" = 915 ORDER BY scene LIMIT 1
2012-10-24T05:42:20+00:00 app[postgres]: [32-1] [BLACK] LOG:  duration: 85.602 ms  statement: SELECT  "movies".* FROM "movies"  WHERE "movies"."dvd_id" = 108 ORDER BY scene LIMIT 1
2012-10-24T05:42:21+00:00 app[postgres]: [33-1] [BLACK] LOG:  duration: 70.147 ms  statement: SELECT  "movies".* FROM "movies"  WHERE "movies"."dvd_id" = 11 ORDER BY scene LIMIT 1
2012-10-24T05:42:21+00:00 app[postgres]: [34-1] [BLACK] LOG:  duration: 144.204 ms  statement: SELECT  "movies".* FROM "movies"  WHERE "movies"."dvd_id" = 6 ORDER BY scene LIMIT 1
2012-10-24T05:42:22+00:00 app[postgres]: [35-1] [BLACK] LOG:  duration: 56.623 ms  statement: SELECT  "movies".* FROM "movies"  WHERE "movies"."dvd_id" = 1956 ORDER BY scene LIMIT 1
2012-10-24T05:42:23+00:00 app[postgres]: [36-1] [BLACK] LOG:  duration: 64.860 ms  statement: SELECT  "movies".* FROM "movies"  WHERE "movies"."dvd_id" = 747 ORDER BY scene LIMIT 1

【问题讨论】:

标签: ruby-on-rails postgresql activerecord heroku postgresql-performance


【解决方案1】:

您可以直接连接到数据库 CLI,然后使用 PostgreSQL EXPLAIN 命令获取有关它如何运行查询的信息。这可以显示您可以向表中添加索引以加快速度的地方。 Postgres docs 更详细地解释(看看我在那里做了什么?)EXPLAIN。

【讨论】:

    【解决方案2】:

    负责这些查询的代码是什么?你在使用急切加载吗?你的查询应该是这样的:

    DVD.includes(:movies).where(whatever) #假设 DVD 有很多电影

    这应该会减少查询/请求的数量。到您的数据库。您的查询表明您可能有 N+1 个问题。

    您还应该在电影表上为 dvd_id 建立一个数据库索引,因为它是一个外键。

    【讨论】:

      【解决方案3】:

      确保您至少在 dvd_id 上有索引。 如果您可以在 (dvd_id, scene) 上创建复合索引,则您的查询将完全优化,无法进一步优化。

      也就是说,只要执行

      CREATE INDEX movies_dvd_id_scene_idx ON movies (dvd_id, scene);
      

      你应该准备好了

      【讨论】:

      • 您说“完全最优”,就好像这样的事情可以抽象地确定,而不是通过对实际数据、生产查询尸体和系统运行硬件的限制进行严格测试来确定。例如:向索引添加第二个字段会使键大小变大,从而降低索引块中的键密度。这会使完全缓存索引变得更加困难,或者导致索引树深度增加更快,需要额外的搜索来满足查询。如果场景/dvd_id 的平均基数接近 1,那么额外的字段几乎不会有好处。
      • 我大体上同意。但是,在这种情况下,考虑到数据量(只有 15k 行),使用这个配方可能不会造成伤害,并且不需要任何修改和重新向 OP 询问更多信息。从这个意义上说,它是完全最优的。
      【解决方案4】:
      duration: 57.914 ms
      duration: 77.086 ms
      duration: 85.602 ms
      duration: 70.147 ms
      duration: 144.204 ms
      duration: 56.623 ms
      duration: 64.860 ms
      

      平均而言(约 80 毫秒),这是在不同大陆进行查询所需的通常持续时间。确保您的 Heroku 应用和数据库都托管在同一地区(欧盟或美国)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-30
        • 1970-01-01
        • 2016-04-02
        • 2012-01-20
        • 1970-01-01
        • 2022-01-17
        • 2018-01-23
        相关资源
        最近更新 更多