EmberJS和Rails 4 API的性能问题

时间:2014-04-09 21:27:45

标签: javascript sql ruby-on-rails performance ember.js

我有一个EmberJS应用程序,它由Rails 4 REST API提供支持。应用程序的工作方式很好,但是根据正在执行的查询类型,它变得非常迟缓。

目前API输出如下:

"projects": [{
    "id": 1,
    "builds": [1, 2, 3, 4]
}]

当用户有许多项目在他们之间分配大量构建时,就会出现问题。 EmberJS目前查看builds密钥然后向/builds?ids[]=1&ids[]=2发出请求,这是我想要的行为。

这个问题可能有两种解决方案之一。

  1. 更新Rails以更有效地加载build_id
  2. 更新EmberJS以支持不同的构建查询
  3. 选项1:更新Rails

    我尝试了各种有关预先加载的解决方案,并使用序列化程序上的自定义方法手动获取ID。这两个解决方案都添加了许多我不想做的额外代码,并且每个项目仍然会进行单独的查询。

    默认情况下,当执行 has_many 时,rails也会执行SELECT *样式查询,而我无法弄清楚如何在序列化程序层覆盖它。我还写了一个可怕的解决方案,它将整个事情解决了一个快速查询,但它涉及编写原始SQL,我知道这不是Rails的做事方式,我宁愿没有像默认范围这样庞大的复杂不可测试查询

    选项2:使Ember使用不同的查询

    而不是请求/builds?ids[]=1&ids[]=2我宁愿不在项目中包含构建密钥,并在我在Ember中访问该变量时向/builds?project_id=1发出请求。我想我可以通过使用类似的东西在每个字段的基础上手动执行此操作:

    builds: function () {
        return this.store.find('builds', { project_id: this.get('id') });
    }.property()
    

    而不是当前:

    builds: DS.hasMany('build', { async: true })
    

    值得一提的是,这不仅适用于“构建”。项目对象上有4个其他键可以执行相同的操作,因此每个项目有4个查询。

2 个答案:

答案 0 :(得分:4)

您是否确保已正确添加数据库索引?在project_id上的构建表上添加和索引将使其更快地工作。

或者,您应该使用links属性加载记录。

{"projects": [{
    "id": 1,
    "links": {
      "builds": "/projects/1/builds"
    }
}]}

这意味着只有在访问关系时才会查询构建表。

答案 1 :(得分:2)

你可以尝试的事情:

  • 确保您的rails控制器仅选择JSON序列化所需的列。

  • 确保在where和join子句中的列上有索引,除非该列是布尔值或具有较少的不同值。始终确保您在外键列上有索引。

  • 非常谨慎地使用ActiveRecord joins vs includes vs preload vs eagerreferences。这个区域充满了组合范围的问题,微妙的事情可以改变生成的SQL和发出的查询数量,甚至返回实际结果。我注意到AR 4的小点发布中的差异产生了不同的查询结果,因为AR会选择加入策略。

  • 通常,您希望减少发布到数据库的SQL数量,但加入表并不总是最佳解决方案。您需要进行基准测试并使用EXPLAIN来查看哪些更适合您的查询。有时子查询/子选择可能更有效。

  • 如果您可以让Ember Data以更简单的查询方式执行请求,那么通过parent_id查询是一个不错的选择。

  • 您可以考虑使用Ember-Model而不是Ember-Data,我目前使用它更简单,更容易适应我的需求,并支持多次获取以避免1 + N请求问题。 / p>

  • 您可以使用嵌入式模型或侧载模型,这样您的服务器就可以减少Web请求的数量和SQL的数量,并在一个请求/一个SQL中返回客户端所需的内容。 Ember-Model支持嵌入式和侧载式模型,因此Ember-Data也更加雄心勃勃。

  • 虽然从您的问题中可以看出Ember-Data正在进行多次抓取,但请确保您正在为这些ID执行SQL IN子句而不是单独的查询。

  • 确保rails侧的SQL没有以1 + N模式扇出。使用includes选项实现对AR关系的预先加载可能有助于避免1 + N个查询,或者可能根据您的响应中所需的结果不必要地加载模型。

  • 我还发现Ruby JSON序列化程序库不是最佳的。我创建了一个gem ToJson,可以在现有解决方案中多次加速JSON序列化。您可以自己尝试并进行基准测试。

我发现ActiveRecord(包括AR 4)对我来说效果不佳,最后我转移到了Sequel,因为它让我对连接类型,连接条件和查询组成有了更多的控制权。战术急切加载,加上它只是更快,对标准SQL功能的更广泛支持以及对postgres功能和扩展的出色支持。这些因素可能会对您设计数据库架构的方式以及您可以实现的性能和查询类型产生巨大影响。

使用SequelToJson对于我的大多数查询,我可以提供比ActiveRecord + JBuilder多30-50倍的请求,在某些情况下,它比我的数百倍好用AR实现(特别是创建/更新)。除了Sequel在从数据库实例化模型方面更快,它还有一个Postgres流媒体适配器,它可以让它更快地获得更大的结果。

更改数据访问/ ORM层和JSON序列化可以将性能提高30-50倍,或者需要在相同负载下管理30-50个服务器。打喷嚏没什么。