add_index
- 1.0.0 (0)
- 1.1.6 (18)
- 1.2.6 (0)
- 2.0.3 (0)
- 2.1.0 (1)
- 2.2.1 (0)
- 2.3.8 (19)
- 3.0.0 (0)
- 3.0.9 (-3)
- 3.1.0 (0)
- 3.2.1 (-2)
- 3.2.8 (0)
- 3.2.13 (0)
- 4.0.2 (38)
- 4.1.8 (0)
- 4.2.1 (0)
- 4.2.7 (3)
- 4.2.9 (0)
- 5.0.0.1 (0)
- 5.1.7 (0)
- 5.2.3 (32)
- 6.0.0 (17)
- 6.1.3.1 (11)
- 6.1.7.7 (0)
- 7.0.0 (-1)
- 7.1.3.2 (12)
- 7.1.3.4 (0)
- What's this?
add_index(table_name, column_name, options = {})
public
Adds a new index to the table. column_name can be a single Symbol, or an Array of Symbols.
The index will be named after the table and the first column name, unless you pass :name as an option.
When creating an index on multiple columns, the first column is used as a name for the index. For example, when you specify an index on two columns [:first, :last], the DBMS creates an index for both columns as well as an index for the first column :first. Using just the first name for this index makes sense, because you will never have to create a singular index with this name.
Examples
Creating a simple index
add_index(:suppliers, :name)
generates
CREATE INDEX suppliers_name_index ON suppliers(name)
Creating a unique index
add_index(:accounts, [:branch_id, :party_id], :unique => true)
generates
CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
Creating a named index
add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
generates
CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
Creating an index with specific key length
add_index(:accounts, :name, :name => 'by_name', :length => 10)
generates
CREATE INDEX by_name ON accounts(name(10)) add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :length => {:name => 10, :surname => 15})
generates
CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
Note: SQLite doesn’t support index length
add index with :quiet=>true option for indices that are possibly already added
# Allows you to specify indices to add in a migration that will only be created if they do not # already exist, or to remove indices only if they already exist with :quiet=>true module ActiveRecord::ConnectionAdapters::SchemaStatements
def add_index_with_quiet(table_name, column_names, options = {}) quiet = options.delete(:quiet) add_index_without_quiet table_name, column_names, options rescue raise unless quiet and $!.message =~ /^Mysql::Error: Duplicate key name/i puts "Failed to create index #{table_name} #{column_names.inspect} #{options.inspect}" end alias_method_chain :add_index, :quiet def remove_index_with_quiet(table_name, column_names, options = {}) quiet = options.delete(:quiet) raise "no options allowed for remove_index, except quiet with this hack #{__FILE__}:#{__LINE__}" unless options.empty? remove_index_without_quiet table_name, column_names rescue raise unless quiet and $!.message =~ /^Mysql::Error: Can't DROP/i puts "Failed to drop index #{table_name} #{column_names.inspect}" end alias_method_chain :remove_index, :quiet
end
If your add_index is being ignored in your migration, see this
My add_index command was producing no change in my MySQL 5.0 database:
add_index :designations, [ :scope_type, :scope_id, :role_id, :user_id ], :unique => true
By just adding an index name, the problem was solved:
add_index :designations, [ :scope_type, :scope_id, :role_id, :user_id ], :unique => true, :name => 'my_index'
This happens when the autogenerated index name gets too long. For more info see:
migration example
def self.up create_table :regs do |t|
t.column :login, :string, :limit=>'10' t.column :pass, :string, :limit=>'10' t.column :email, :string, :limit=>'20' t.column :fio, :string, :limit=>'30' t.column :born, :date t.column :phone_code, :integer, :limit=>'3' t.column :phone_post, :integer, :limit=>'7' t.column :password, :string, :limit=>'20' t.column :pass_when, :date t.column :pass_who, :string,:limit=>'30' t.column :wmid, :integer, :limit=>12 t.column :wmr, :integer, :limit=>12 t.column :wmz, :integer, :limit=>12 end
add_index :regs, [:login, :wmr, :wmz], :unique => true end
Adding index with other operator classes (PostgreSQL)
To perform on search by LIKE:
SQL Query:
SELECT users.* FROM users WHERE name LIKE 'Doug%';
Explain:
# Without index Seq Scan on users (cost=0.00..82183.32 rows=98524 width=418) Filter: ((name)::text ~~ 'Doug%'::text)
Adding index with operator class ‘varchar_pattern_ops’
add_index :users, :name, order: {name: :varchar_pattern_ops} execute 'ANALYZE users;'
New Explain:
# With index Bitmap Heap Scan on users (cost=2444.46..56020.97 rows=98524 width=418) Filter: ((name)::text ~~ 'Doug%'::text) -> Bitmap Index Scan on index_users_on_name (cost=0.00..2419.83 rows=75940 width=0) Index Cond: ((name)::text ~>=~ 'Doug'::text)
Gotcha: index name must be a string, not a symbol
Using rails 2.3.8 I kept getting an exception when i tried:
add_index :widgets, [:colour, :weight], :name => :index_by_colour_weight
it’s solved by using:
add_index :widgets, [:colour, :weight], :name => 'index_by_colour_weight'