Пересчитать счетчик кеша из 120к записей [Rails / ActiveRecord] - PullRequest
2 голосов
/ 06 мая 2010

Следующая ситуация:

У меня есть модель poi, в которой много картинок (1: n). Я хочу пересчитать столбец counter_cache, потому что значения несовместимы.

Я пытался выполнять итерации в ruby ​​для каждой записи, но это занимает слишком много времени и иногда завершается с некоторыми ошибками «ошибки сегментации».

Так что мне интересно, возможно ли это сделать с помощью необработанного SQL-запроса?

Ответы [ 2 ]

8 голосов
/ 06 мая 2010

Если, например, у вас есть Post и Picture модели, а после has_many :pictures, вы можете сделать это с update_all:

Post.update_all("pictures_count=(Select count(*) from pictures where pictures.post_id=posts.id)")
1 голос
/ 04 декабря 2015

Я нашел хорошее решение для krautcomputing .
Он использует отражения, чтобы найти все встречные кэши проекта, запросы SQL, чтобы найти только несовместимые объекты, и используют Rails reset_counters, чтобы очистить вещи.

К сожалению, он работает только с «обычными» кешами счетчиков (без имени класса, без имен кеша счетчиков), поэтому я уточнил:

Rails.application.eager_load!

ActiveRecord::Base.descendants.each do |many_class|
  many_class.reflections.each do |name, reflection|
    if reflection.options[:counter_cache]
      one_class = reflection.class_name.constantize
      one_table, many_table = [one_class, many_class].map(&:table_name)
      # more reflections, use :inverse_of, :counter_cache etc.
      inverse_of = reflection.options[:inverse_of]
      counter_cache = reflection.options[:counter_cache]
      if counter_cache === true
        counter_cache = "#{many_table}_count"
        inverse_of ||= many_table.to_sym
      else
        inverse_of ||= counter_cache.to_s.sub(/_count$/,'').to_sym
      end
      ids = one_class
        .joins(inverse_of)
        .group("#{one_table}.id")
        .having("MAX(#{one_table}.#{counter_cache}) != COUNT(#{many_table}.id)")
        .pluck("#{one_table}.id")
      ids.each do |id|
        puts "reset #{id} on #{many_table}"
        one_class.reset_counters id, inverse_of
      end
    end
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...