summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorick Peterse <yorickpeterse@gmail.com>2015-10-29 12:05:47 +0100
committerYorick Peterse <yorickpeterse@gmail.com>2015-10-30 12:00:58 +0100
commit24c8f42278844cf48cdd9871b8285445379623f0 (patch)
tree178c430017076126db2d0b3e6fc84276270707d8
parent0a6aaf256900ab47058d03d3b74883420c4643ae (diff)
downloadgitlab-ce-24c8f42278844cf48cdd9871b8285445379623f0.tar.gz
Use a UNION for User.find_by_any_email
This is significantly faster than using a sub-query, at least when run on the GitLab.com production database. The benchmarks are a lot slower now with these changes, most likely due to PostgreSQL choosing a different (and less efficient) plan based on the amount of data present in the test database. Thanks to @dlemstra for suggesting the use of a UNION.
-rw-r--r--app/models/user.rb15
1 files changed, 12 insertions, 3 deletions
diff --git a/app/models/user.rb b/app/models/user.rb
index 924cb543fab..35f5ab56798 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -235,9 +235,18 @@ class User < ActiveRecord::Base
# Find a User by their primary email or any associated secondary email
def find_by_any_email(email)
- User.reorder(nil).
- where('id IN (SELECT user_id FROM emails WHERE email = :email) OR email = :email', email: email).
- take
+ # Arel doesn't allow for chaining operations on union nodes, thus we have
+ # to write this query by hand. See the following issue for more info:
+ # https://github.com/rails/arel/issues/98.
+ sql = '(SELECT * FROM users WHERE email = :email
+ UNION
+ SELECT users.*
+ FROM emails
+ INNER JOIN users ON users.id = emails.user_id
+ WHERE emails.email = :email)
+ LIMIT 1;'
+
+ User.find_by_sql([sql, { email: email }]).first
end
def filter(filter_name)