Class: RuboCop::Cop::Spbtv::Postgres::AddIndex

Inherits:
RuboCop::Cop
  • Object
show all
Defined in:
lib/rubocop/cop/spbtv/postgres/add_index.rb

Overview

Do not add an index.

Normally PostgreSQL locks the table to be indexed against writes and performs the entire index build with a single scan of the table. Other transactions can still read the table, but not to insert, update, or delete rows until the index build is finished.

To overcome this issue you may specify the CONCURRENTLY option of CREATE INDEX. When this option is used, PostgreSQL must perform two scans of the table, and in addition it must wait for all existing transactions that could potentially modify or use the index to terminate.

If a problem arises while scanning the table, such as a uniqueness violation in a unique index, the CREATE INDEX command will fail but leave behind an “invalid” index.

The recommended recovery method in such cases is to drop the index and try again to perform CREATE INDEX CONCURRENTLY.

Another difference is that a regular CREATE INDEX command can be performed within a transaction block, but CREATE INDEX CONCURRENTLY cannot.

Examples:

@bad
class AddIndexToAsksActive < ActiveRecord::Migration
  def change
    add_index :asks, :active
  end
end

@good
class AddIndexToAsksActive < ActiveRecord::Migration
  disable_ddl_transaction!
  def change
    add_index :asks, :active, algorithm: :concurrently
  end
end

See Also:

Constant Summary collapse

MSG =
'Do not add an index.'.freeze

Instance Method Summary collapse

Instance Method Details

#on_class(node) ⇒ Object



65
66
67
# File 'lib/rubocop/cop/spbtv/postgres/add_index.rb', line 65

def on_class(node)
  @disable_ddl_transaction = disable_ddl_transaction?(node)
end

#on_send(node) ⇒ Object



69
70
71
72
73
74
75
76
77
78
# File 'lib/rubocop/cop/spbtv/postgres/add_index.rb', line 69

def on_send(node)
  if add_index_without_options?(node)
    add_offense(node, :expression)
  elsif (options = add_index_with_options?(node))
    has_concurrently = options.detect { |pair| concurrently?(pair) }
    unless has_concurrently && @disable_ddl_transaction
      add_offense(node, :expression)
    end
  end
end