module IndexShotgun::Analyzer

Constants

ORACLE_SYSTEM_TABLES

Public Class Methods

check_indexes(table) click to toggle source

check duplicate indexes of table @param table [String] table name @return [Array<Hash>] array of index info

index: index info `ActiveRecord::ConnectionAdapters::IndexDefinition`
result: search result message
# File lib/index_shotgun/analyzer.rb, line 75
def check_indexes(table)
  indexes = table_indexes(table)

  indexes.permutation(2).each_with_object([]) do |(source_index, target_index), response|
    next unless source_index.columns.start_with?(target_index.columns)

    next if source_index.unique && target_index.unique

    if target_index.unique
      response << {
        index:  source_index,
        result: "#{source_index.name} has column(s) on the right side of unique index (#{target_index.name}). You can drop if low cardinality",
      }
    else
      response << {
        index:  target_index,
        result: "#{target_index.name} is a left-prefix of #{source_index.name}",
      }
    end
  end
end
exclude_tables() click to toggle source
# File lib/index_shotgun/analyzer.rb, line 280
def exclude_tables
  return @exclude_tables if @exclude_tables

  # Rails default tables
  tables = %w[ar_internal_metadata schema_migrations]

  # Oracle system tables
  tables += ORACLE_SYSTEM_TABLES

  @exclude_tables = tables.map(&:downcase)
  @exclude_tables
end
perform() click to toggle source

Search duplicate index @return [IndexShotgun::Analyzer::Response]

# File lib/index_shotgun/analyzer.rb, line 22
      def perform
        tables =
          silence_deprecations do
            ActiveRecord::Base.connection.tables
          end
        tables.reject! {|table| exclude_tables.include?(table.downcase) }

        duplicate_indexes =
          tables.each_with_object([]) do |table, array|
            response = check_indexes(table)
            array.push(*response)
          end

        message =
          duplicate_indexes.each_with_object("") do |info, str|
            str << <<~MSG
              # =============================
              # #{info[:index].table}
              # =============================

              # #{info[:result]}
              # To remove this duplicate index, execute:
              ALTER TABLE `#{info[:index].table}` DROP INDEX `#{info[:index].name}`;

            MSG
          end

        total_index_count = tables.map {|table| table_indexes(table).count }.sum
        message << <<~MSG
          # ########################################################################
          # Summary of indexes
          # ########################################################################

          # Total Duplicate Indexes  #{duplicate_indexes.count}
          # Total Indexes            #{total_index_count}
          # Total Tables             #{tables.count}

        MSG

        response = Response.new
        response.duplicate_index_count = duplicate_indexes.count
        response.message               = message
        response.total_index_count     = total_index_count
        response.total_table_count     = tables.count

        response
      end
silence_deprecations() { || ... } click to toggle source
# File lib/index_shotgun/analyzer.rb, line 293
def silence_deprecations
  if ActiveSupport.version >= Gem::Version.create("7.1.0")
    ActiveSupport::Deprecation::Deprecators.new.silence do
      yield
    end
  else
    ActiveSupport::Deprecation.silence do
      yield
    end
  end
end
table_indexes(table) click to toggle source

get indexes of table @param table [String]

# File lib/index_shotgun/analyzer.rb, line 99
def table_indexes(table)
  ActiveRecord::Base.connection.indexes(table)
end