From 303f97ce89e4789498d289727537fed88e7bdfdb Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 17 Mar 2023 09:35:29 +0000 Subject: [PATCH] PERF: Use native postgres upsert for ApplicationRequest (#20706) Using `create_or_find_by!`, followed by `update_all!` requires two or three queries (two when the row doesn't already exist, three when it does). Instead, we can use postgres's native `INSERT ... ON CONFLICT ... DO UPDATE SET` feature to do the logic in a single atomic call. --- app/models/application_request.rb | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/app/models/application_request.rb b/app/models/application_request.rb index bb308a74356..a91c67571ed 100644 --- a/app/models/application_request.rb +++ b/app/models/application_request.rb @@ -32,20 +32,14 @@ class ApplicationRequest < ActiveRecord::Base end def self.write_cache!(req_type, count, date) - id = req_id(date, req_type) - where(id: id).update_all(["count = count + ?", count]) - end - - def self.req_id(date, req_type, retries = 0) req_type_id = req_types[req_type] - create_or_find_by!(date: date, req_type: req_type_id).id - rescue StandardError # primary key violation - if retries == 0 - req_id(date, req_type, 1) - else - raise - end + DB.exec(<<~SQL, date: date, req_type_id: req_type_id, count: count) + INSERT INTO application_requests (date, req_type, count) + VALUES (:date, :req_type_id, :count) + ON CONFLICT (date, req_type) + DO UPDATE SET count = application_requests.count + excluded.count + SQL end def self.stats