Javascript EmberJS和Rails 4 API的性能问题

Javascript EmberJS和Rails 4 API的性能问题,javascript,sql,ruby-on-rails,performance,ember.js,Javascript,Sql,Ruby On Rails,Performance,Ember.js,我有一个由Rails4RESTAPI支持的EmberJS应用程序。应用程序的工作方式很好,但是根据正在执行的查询类型,它变得非常缓慢 目前API输出如下: "projects": [{ "id": 1, "builds": [1, 2, 3, 4] }] 当一个用户有很多项目,其中有很多构建被分割时,问题就出现了。EmberJS目前查看builds键,然后请求/builds?ids[]=1&ids[]=2,这是我想要的行为 这个问题可以有两种解决方案之一 更新Rails以更有效

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

目前API输出如下:

"projects": [{
    "id": 1,
    "builds": [1, 2, 3, 4]
}]
当一个用户有很多项目,其中有很多构建被分割时,问题就出现了。EmberJS目前查看
builds
键,然后请求
/builds?ids[]=1&ids[]=2
,这是我想要的行为

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

  • 更新Rails以更有效地加载构建ID
  • 更新EmberJS以支持对构建的不同查询
  • 选项1:更新Rails 我已经尝试了各种解决方案,包括在序列化程序上使用自定义方法进行即时加载和手动获取ID。这两种解决方案都添加了很多我不愿意做的额外代码,并且仍然会对每个项目执行单独的查询

    默认情况下,rails在执行时也会执行
    SELECT*
    样式查询,有许多类型,我不知道如何在序列化器层覆盖这些类型。我还编写了一个可怕的解决方案,它将整个过程都简化为一个快速查询,但它涉及到编写原始SQL,我知道这不是Rails的工作方式,我不希望有一个像默认范围这样庞大复杂的不稳定查询

    选项2:使余烬使用不同的查询 与其请求
    /builds?ids[]=1&ids[]=2
    ,我宁愿在项目中根本不包含builds键,并在访问Ember中的变量时请求
    /builds?project_id=1
    。我想我可以通过使用类似的方法,在每个字段的基础上手动执行此操作:

    builds: function () {
        return this.store.find('builds', { project_id: this.get('id') });
    }.property()
    
    而不是当前的:

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

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

    是否已确保已将索引正确添加到数据库中?在
    project\u id
    的builds表上添加和索引将使其工作得更快

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

    {"projects": [{
        "id": 1,
        "links": {
          "builds": "/projects/1/builds"
        }
    }]}
    
    这意味着只有在访问关系时才会查询builds表。

    您可以尝试的事项:

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

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

    • 在如何使用ActiveRecord
      连接时要非常小心
      vs
      includes
      vs
      preload
      vs
      eager
      引用
      。这个领域充满了将作用域组合在一起的问题,微妙的事情可能会改变生成的SQL和发出的查询的数量,甚至改变返回的实际结果。我注意到,由于AR会选择连接策略,AR 4的次要版本会产生不同的查询结果

    • 通常,您希望减少向数据库发出的SQL的数量,但连接表并不总是最好的解决方案。您将需要基准测试和使用EXPLAIN来查看什么更适合您的查询。有时子查询/子选择可能更有效

    • 如果您可以通过这种方式获取余烬数据以执行请求,那么按父\ u id进行查询是一个很好的选择,因为数据库具有更简单的查询

    • >p>可以考虑使用烬模型代替烬数据,我现在使用它,因为它更简单和更容易适应我的需要,并且支持多取以避免1 +N请求问题。

    • 您可以使用嵌入式模型或侧加载模型,这样服务器就可以减少web请求的数量和SQL的数量,并在一个请求/一个SQL中返回客户端所需的内容。余烬模型既支持嵌入式模型,也支持侧面加载的模型,所以余烬数据更具雄心也可能更具挑战性

    • 尽管从您的问题中可以看出,Ember数据正在执行多重获取,但请确保您正在为这些ID执行SQL IN子句,而不是单独的查询

    • 确保rails端的SQL不是以1+N模式展开的。使用
      includes
      选项对AR关系进行即时加载可能有助于避免1+N查询,或者根据您的响应中所需的结果不必要地加载模型

    • 我还发现Ruby JSON序列化程序库并不是最理想的。我创建了一个gem,它可以在现有解决方案的基础上多次加速JSON序列化。你可以尝试一下,为自己设定基准

    我发现ActiveRecord(包括AR 4)不适合我,我最终选择了它,因为它让我可以更好地控制连接类型、连接条件、查询组合和战术加载,而且速度更快,对标准SQL特性有更广泛的支持,对postgres特性和扩展有极好的支持。这些事情会对您设计数据库模式的方式以及可以实现的查询的性能和类型产生巨大的影响

    在我的大多数查询中,使用和我可以处理比使用ActiveRecord+JBuilder多30-50倍的请求,在某些情况下,它比我使用AR(尤其是创建/更新)实现的请求要好数百倍。除了Sequel能够更快地从DB实例化模型外,它还有一个Postgres流式适配器,这使得它在获得大的结果时速度更快


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

    我认为在哪里使用ORM