如何优化我的SQL查询以在更短的时间内执行

时间:2018-01-23 15:51:09

标签: sql postgresql activerecord subquery

我有以下ActiveRecord查询

LoanApplication.joins(:case_status => :loan_case).where.not(case_code: nil).group("loan_cases.id, loan_cases.case_status").select("loan_cases.case_status, count(loan_applications.id)").order("loan_cases.rank ASC")

,如果使用.explain细分,则会提供以下查询计划

QUERY PLAN
------------------------------------------------------------------------------------------------------------------
 Sort  (cost=2924.84..2924.85 rows=1 width=532)
   Sort Key: loan_cases.rank
   ->  GroupAggregate  (cost=0.43..2924.83 rows=1 width=532)
         Group Key: loan_cases.id
         ->  Nested Loop  (cost=0.43..2918.67 rows=1230 width=528)
               ->  Nested Loop  (cost=0.14..1898.81 rows=1765 width=528)
                     Join Filter: (case_statuses.loan_case_id = loan_cases.id)
                     ->  Index Scan using loan_cases_pkey on loan_cases  (cost=0.14..12.45 rows=1 width=524)
                           Filter: (deleted_at IS NULL)
                     ->  Seq Scan on case_statuses  (cost=0.00..1423.03 rows=37066 width=8)
                           Filter: (deleted_at IS NULL)
               ->  Index Scan using loan_applications_pkey on loan_applications  (cost=0.29..0.58 rows=1 width=4)
                     Index Cond: (id = case_statuses.loan_application_id)
                     Filter: ((deleted_at IS NULL) AND (case_code IS NOT NULL))
(14 rows)

或以下SQL查询

 SELECT loan_cases.case_status, count(loan_applications.id) FROM
 "loan_applications" INNER JOIN "case_statuses" ON
 "case_statuses"."loan_application_id" = "loan_applications"."id" AND
 "case_statuses"."deleted_at" IS NULL INNER JOIN "loan_cases" ON
 "loan_cases"."id" = "case_statuses"."loan_case_id" AND
 "loan_cases"."deleted_at" IS NULL WHERE
 "loan_applications"."deleted_at" IS NULL AND
 ("loan_applications"."case_code" IS NOT NULL) GROUP BY loan_cases.id,
 loan_cases.case_status  ORDER BY loan_cases.rank ASC"

创建表定义

create_table "loan_applications", force: :cascade do |t|
  t.string "name"
  t.string "email"
  t.string "case_code"
end

create_table "loan_cases", force: :cascade do |t|
    t.string   "case_status", limit: 255
    t.text     "description"
    t.text     "can_flow_to"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.datetime "deleted_at"
    t.integer  "rank"
  end

create_table "case_statuses", force: :cascade do |t|
  t.integer "loan_application_id"
  t.integer "loan_case_id"
end
add_index "case_statuses", ["loan_application_id"], name: "index_case_statuses_on_loan_application_id", using: :btree

Rails模型

class LoanApplication 
  has_one :case_status, inverse_of: :loan_application, :dependent => :destroy
  has_one :loan_case, :through => :case_status, :source => :loan_case
end

class CaseStatus
  belongs_to :loan_application, inverse_of: :case_status
  belongs_to :loan_case
end

class LoanCase
  has_many :case_statuses
end

这在大约239ms内执行,但我相信它可以更短,并询问是否有任何方法可以更好地优化它?

0 个答案:

没有答案