Project

General

Profile

« Previous | Next » 

Revision ce5bf100

Added by Lukas Zapletal over 5 years ago

Fixes #25053 - expensive db_facts query executed just once

View differences:

app/services/fact_importer.rb
private
attr_reader :host, :facts, :fact_names, :fact_names_by_id
attr_reader :host, :facts, :fact_names, :fact_names_by_id, :facts_to_create
def fact_name_class_name
@fact_name_class_name ||= fact_name_class.name
......
end
def initialize_fact_names
name_records = fact_name_class.unscoped.where(:name => facts.keys, :type => fact_name_class_name)
name_records = fact_name_class.unscoped.where(:name => facts.keys, :type => fact_name_class_name).reorder('')
@fact_names = {}
@fact_names_by_id = {}
name_records.find_each do |record|
name_records.each do |record|
@fact_names[record.name] = record
@fact_names_by_id[record.id] = record
end
......
end
def delete_removed_facts
delete_query = FactValue.joins(:fact_name).where(:host => host, 'fact_names.type' => fact_name_class_name).where.not(:fact_name => fact_names.values)
delete_query = FactValue.joins(:fact_name).where(:host => host, 'fact_names.type' => fact_name_class_name).where.not(:fact_name => fact_names.values).reorder('')
if ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'mysql'
# MySQL does not handle delete with inner query correctly (slow) so we will do two queries on purpose
@counters[:deleted] = FactValue.where(:id => delete_query.pluck(:id)).delete_all
......
end
def add_new_facts
facts_to_create = facts.keys - db_facts.pluck(:fact_name_id).map { |name_id| fact_names_by_id[name_id].name }
facts_to_create.each { |f| add_new_fact(f) }
@counters[:added] = facts_to_create.size
end
def update_facts
time = Time.now.utc
updated = []
updated = 0
db_facts_names = []
db_facts.find_each do |record|
new_value = facts[record.name]
if record.value != new_value
# skip callbacks/validations
record.update_columns(:value => new_value, :updated_at => time)
updated << record.name
updated += 1
end
db_facts_names << record.name
end
@counters[:updated] = updated.size
@facts_to_create = facts.keys - db_facts_names
@counters[:updated] = updated
end
def normalize(facts)
......
end
def db_facts
host.fact_values.where(:fact_name => fact_names.values)
query = host.fact_values
if ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'mysql'
# MySQL query optimizer does not appear to pick the correct index here: https://projects.theforeman.org/issues/25053
query = query.from("fact_values USE INDEX(index_fact_values_on_fact_name_id_and_host_id)")
end
query.where(:fact_name => fact_names.values).reorder('')
end
def ensure_no_active_transaction

Also available in: Unified diff