class NoSE::Plans::UpdatePlanner

A planner for update statements in the workload

Public Class Methods

new(model, trees, cost_model, by_id_graph = false) click to toggle source
# File lib/nose/plans/update_planner.rb, line 188
def initialize(model, trees, cost_model, by_id_graph = false)
  @logger = Logging.logger['nose::update_planner']

  @model = model
  @cost_model = cost_model
  @by_id_graph = by_id_graph

  # Remove anything not a support query then group by statement and index
  @query_plans = trees.select do |tree|
    tree.query.is_a? SupportQuery
  end
  @query_plans = @query_plans.group_by { |tree| tree.query.statement }
  @query_plans.each do |plan_stmt, plan_trees|
    @query_plans[plan_stmt] = plan_trees.group_by do |tree|
      index = tree.query.index
      index = index.to_id_path if @by_id_path

      index
    end
  end
end

Public Instance Methods

find_plans_for_update(statement, indexes) click to toggle source

Find the necessary update plans for a given set of indexes @return [Array<UpdatePlan>]

# File lib/nose/plans/update_planner.rb, line 212
def find_plans_for_update(statement, indexes)
  indexes = indexes.map(&:to_id_graph).to_set if @by_id_graph

  indexes.map do |index|
    next unless statement.modifies_index?(index)

    if (@query_plans[statement] &&
        @query_plans[statement][index]).nil?
      trees = []

      if statement.is_a? Insert
        cardinality = 1
      else
        cardinality = Cardinality.filter index.entries,
                                         statement.eq_fields,
                                         statement.range_field
      end
    else
      # Get the cardinality of the last step to use for the update state
      trees = @query_plans[statement][index]
      plans = trees.map do |tree|
        tree.select_using_indexes(indexes).min_by(&:cost)
      end

      # Multiply the cardinalities because we are crossing multiple
      # relationships and need the cross-product
      cardinality = plans.product_by { |p| p.last.state.cardinality }
    end

    state = UpdateState.new statement, cardinality
    update_steps = update_steps statement, index, state
    UpdatePlan.new statement, index, trees, update_steps, @cost_model
  end.compact
end

Private Instance Methods

update_steps(statement, index, state) click to toggle source

Find the required update steps @return [Array<UpdatePlanStep>]

# File lib/nose/plans/update_planner.rb, line 251
def update_steps(statement, index, state)
  update_steps = []
  update_steps << DeletePlanStep.new(index, state) \
    if statement.requires_delete?(index)

  if statement.requires_insert?(index)
    fields = if statement.is_a?(Connect)
               statement.conditions.each_value.map(&:field)
             else
               statement.settings.map(&:field)
             end

    update_steps << InsertPlanStep.new(index, state, fields)
  end

  update_steps
end