Я создаю Rails API из модели Service
с несколькими вложенными отношениями (многие-к-одному и многие-ко-многим).
Базовый индексный маршрут имеет достаточно быстрое время отклика(~ 150 мс), но когда я добавляю запрос фильтра к URL-адресу (например, ?category=MyCategory,MyOtherCategory
), время отклика абсурдно медленно (~ 20 с).
Как я могу оптимизировать область активной записи и запрос кисправить это?
Я вижу из журнала рельсов, что виноват этот абсолютно массивный запрос:
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.-поддерживаемый массив, а не один.