我正在从具有几个嵌套关系(多对一和多对多)的模型Service
构建Rails API。
基本索引路由具有足够快的响应时间(〜150ms),但是当我向URL添加过滤查询(例如?category=MyCategory,MyOtherCategory
)时,响应时间非常慢(〜20s)。
如何优化活动记录范围和查询以解决此问题?
我从rails日志中看到,这绝对是庞大的查询的罪魁祸首:
SELECT "services"."id" AS t0_r0, "services"."name" AS t0_r1, "services"."parent_organisation" AS t0_r2, "services"."description" AS t0_r3, "services"."created_at" AS t0_r4, "services"."updated_at" AS t0_r5, "services"."url" AS t0_r6, "services"."contact_name" AS t0_r7, "services"."phone" AS t0_r8, "services"."email" AS t0_r9, "services"."review_status" AS t0_r10, "services"."review_number" AS t0_r11, "services"."review_notes" AS t0_r12, "services"."clo_notes" AS t0_r13, "services"."health_safety" AS t0_r14, "services"."insurance" AS t0_r15, "services"."safeguarding" AS t0_r16, "services"."vol_dbs_check" AS t0_r17, "services"."review_date" AS t0_r18, "services"."laf_area" AS t0_r19, "services"."ccg_locality" AS t0_r20, "services"."venue" AS t0_r21, "services"."area" AS t0_r22, "services"."postcode" AS t0_r23, "services"."latitude" AS t0_r24, "services"."longitude" AS t0_r25, "services"."price" AS t0_r26, "services"."daytime" AS t0_r27, "services"."frequency" AS t0_r28, "services"."assigned_to" AS t0_r29, "services"."services" AS t0_r30, "services"."category_id" AS t0_r31, "days"."id" AS t1_r0, "days"."name" AS t1_r1, "days"."created_at" AS t1_r2, "days"."updated_at" AS t1_r3, "categories"."id" AS t2_r0, "categories"."name" AS t2_r1, "categories"."created_at" AS t2_r2, "categories"."updated_at" AS t2_r3, "keywords"."id" AS t3_r0, "keywords"."name" AS t3_r1, "keywords"."created_at" AS t3_r2, "keywords"."updated_at" AS t3_r3, "accessibilities"."id" AS t4_r0, "accessibilities"."name" AS t4_r1, "accessibilities"."created_at" AS t4_r2, "accessibilities"."updated_at" AS t4_r3, "suitabilities"."id" AS t5_r0, "suitabilities"."name" AS t5_r1, "suitabilities"."created_at" AS t5_r2, "suitabilities"."updated_at" AS t5_r3, "age_groups"."id" AS t6_r0, "age_groups"."name" AS t6_r1, "age_groups"."created_at" AS t6_r2, "age_groups"."updated_at" AS t6_r3 FROM "services" INNER JOIN "categories" ON "categories"."id" = "services"."category_id" LEFT OUTER JOIN "days_services" ON "days_services"."service_id" = "services"."id" LEFT OUTER JOIN "days" ON "days"."id" = "days_services"."day_id" LEFT OUTER JOIN "keywords_services" ON "keywords_services"."service_id" = "services"."id" LEFT OUTER JOIN "keywords" ON "keywords"."id" = "keywords_services"."keyword_id" LEFT OUTER JOIN "accessibilities_services" ON "accessibilities_services"."service_id" = "services"."id" LEFT OUTER JOIN "accessibilities" ON "accessibilities"."id" = "accessibilities_services"."accessibility_id" LEFT OUTER JOIN "services_suitabilities" ON "services_suitabilities"."service_id" = "services"."id" LEFT OUTER JOIN "suitabilities" ON "suitabilities"."id" = "services_suitabilities"."suitability_id" LEFT OUTER JOIN "age_groups_services" ON "age_groups_services"."service_id" = "services"."id" LEFT OUTER JOIN "age_groups" ON "age_groups"."id" = "age_groups_services"."age_group_id" WHERE "categories"."name" = $1 AND "services"."id" IN ($2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
我的模型:
# models/service.rb
class Service < ApplicationRecord
belongs_to :category
has_and_belongs_to_many :days
has_and_belongs_to_many :keywords
has_and_belongs_to_many :accessibilities
has_and_belongs_to_many :suitabilities
has_and_belongs_to_many :age_groups
has_and_belongs_to_many :legacy_category
scope :category, -> (category) {
category_array = category.split(',')
joins(:category).where(categories: {name: category_array})
}
end
# models/category.rb
class Category < ApplicationRecord
has_many :services
end
我的控制器:
class ServicesController < ApplicationController
has_scope :category, only: :index
def index
services = apply_scopes(Service.includes(
:category,
:days,
:keywords,
:accessibilities,
:suitabilities,
:age_groups
))
paginate json: services, per_page: 10
end
end
我正在使用has_scope在控制器中应用范围。
我应该能够在我的API端点的末尾添加一个查询,并筛选出与给定类别匹配的服务列表。
请注意,重要的是要能够过滤提供URL的数组中存在的所有类别,而不仅仅是一个类别。
答案 0 :(得分:0)
我首先要检查的是数据库中的Service表是否在Category上正确索引。我以为可以,但是最好确认一下。显然,如果没有,请在其中添加索引。您可能还需要检查一下类别索引是否在名称上。
现在,我从未使用过has_scope
库(也没有使用您在示例中显示的分页库),所以我不能专门针对那些人,而是通过标准方式实现它,这对您不起作用吗?
category_names = params[:category].split(",")
per_page = params[:per_page].to_i
page = params[:page].to_i * per_page
category_ids = Category.where(name: category_names).pluck(:id)
services = Service
.includes(
:category,
:days,
:keywords,
:accessibilities,
:suitabilities,
:age_groups
).where(category: category_ids)
.limit(per_page)
.offset(page)
render json: services, status: :ok
听起来好像是优化问题,因为您的数据库没有正确索引,因此如果没有更多信息,我认为修复该问题应该可以解决您在那方面的不良表现。