From 11939fa8b93d77c7344c62c90fcfa72f598e2af4 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 12 Aug 2016 13:04:46 -0400 Subject: [PATCH] PERF: Avoid some more count queries when fetching more results --- lib/search.rb | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/lib/search.rb b/lib/search.rb index c09907716e4..91f2833f202 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -566,16 +566,8 @@ class Search posts = posts.joins('JOIN users u ON u.id = posts.user_id') posts = posts.where("posts.raw || ' ' || u.username || ' ' || COALESCE(u.name, '') ilike ?", "%#{term_without_quote}%") else - - posts = posts.where("post_search_data.search_data @@ #{ts_query}") - min_id = Search.min_post_id - if min_id > 0 - fast_query = posts.dup.where("post_search_data.post_id >= #{min_id}") - posts = fast_query if fast_query.dup.count >= 50 - end - exact_terms = @term.scan(/"([^"]+)"/).flatten exact_terms.each do |exact| posts = posts.where("posts.raw ilike ?", "%#{exact}%") @@ -687,34 +679,51 @@ class Search @ts_query_cache[(locale || query_locale) + " " + @term] ||= Search.ts_query(@term, locale) end - def aggregate_search(opts = {}) + def wrap_rows(query) + "SELECT *, row_number() over() row_number FROM (#{query.to_sql}) xxx" + end + def aggregate_post_sql(opts) min_or_max = @order == :latest ? "max" : "min" - post_sql = + query = if @order == :likes # likes are a pain to aggregate so skip posts_query(@limit, private_messages: opts[:private_messages]) .select('topics.id', "post_number") - .to_sql else - posts_query(@limit, aggregate_search: true, - private_messages: opts[:private_messages]) + posts_query(@limit, aggregate_search: true, private_messages: opts[:private_messages]) .select('topics.id', "#{min_or_max}(post_number) post_number") .group('topics.id') - .to_sql end + min_id = Search.min_post_id + if min_id > 0 + low_set = query.dup.where("post_search_data.post_id < #{min_id}") + high_set = query.where("post_search_data.post_id >= #{min_id}") + + return { default: wrap_rows(high_set), remaining: wrap_rows(low_set) } + end + # double wrapping so we get correct row numbers - post_sql = "SELECT *, row_number() over() row_number FROM (#{post_sql}) xxx" + { default: wrap_rows(query) } + end - posts = Post.includes(:topic => :category) - .includes(:user) - .joins("JOIN (#{post_sql}) x ON x.id = posts.topic_id AND x.post_number = posts.post_number") - .order('row_number') + def aggregate_posts(post_sql) + return [] unless post_sql - posts.each do |post| - @results.add(post) + Post.includes(:topic => :category) + .includes(:user) + .joins("JOIN (#{post_sql}) x ON x.id = posts.topic_id AND x.post_number = posts.post_number") + .order('row_number') + end + + def aggregate_search(opts = {}) + post_sql = aggregate_post_sql(opts) + + aggregate_posts(post_sql[:default]).each {|p| @results.add(p)} + if @results.posts.size < @limit + aggregate_posts(post_sql[:remaining]).each {|p| @results.add(p) } end end