为什么使用'gin'的add_index会创建一个'btree'索引呢?

时间:2014-04-20 17:23:14

标签: ruby-on-rails arrays postgresql ruby-on-rails-4 indexing

我在PostgreSQL 9.3.4Rails 4.0.4

我添加了一个“标签”列和相应的gin索引(或者,至少我要求一个)。

class AddTagsToPhotos < ActiveRecord::Migration
  def change
    add_column :photos, :tags, :text, array: true, null: false, default: []
    add_index :photos, :tags, using: 'gin'
  end
end

通过psql验证结果:

psql=# \d photos
...
tags  | text[]  | not null default '{}'::text[]
Indexes:
    "index_photos_on_tags" btree (tags)

请注意,“tags”索引的类型为btree - 而我要求gin

现在手动创建一个索引以显示gin可用:

psql=# create index index_photos_on_tags2 on photos using gin(tags) ;

psql=# \d photos
Indexes:
    "index_photos_on_tags" btree (tags)
    "index_photos_on_tags2" gin (tags)

确实,gin可用。

目前我正在将此解决方法与原始SQL一起使用,但想了解上述典型方法失败的原因:

class AddTagsToPhotos < ActiveRecord::Migration
  def up
    add_column :photos, :tags, :text, array: true, null: false, default: []
    ActiveRecord::Base.connection.execute('create index index_photos_on_tags on photos using gin(tags) ;')
  end
  def down
    ActiveRecord::Base.connection.execute('drop index index_photos_on_tags')
    remove_column :photos, :tags
  end
end

请注意还有另一个问题!

事实证明,db/schema.rb不会将gin设置为索引类型:

add_index "photos", ["tags"], :name => "index_photos_on_tags"

潜在的临时解决方法:

add_index "photos", ["tags"], :name => "index_photos_on_tags", using: :gin

警报!

在修复此错误之前,您必须在运行迁移时查看对db/schema.rb的更改,因为将来的所有迁移都会从using: :gin行中删除add_index

1 个答案:

答案 0 :(得分:4)

正如paxer所提到的,您需要通过在:sql中添加(或更改)此行来将架构格式设置为config/application.rb

config.active_record.schema_format = :sql

正如Rails Migrations guide中所解释的那样,原因是GIN索引特定于Postgres。当您使用特定于数据库的项目时,schema.rb将无法重新创建它们。

以下是Rails指南的引用:

  

但是需要权衡:db / schema.rb无法表示特定于数据库的项目,例如触发器或存储过程。在迁移中,您可以执行自定义SQL语句,但架构转储程序无法从数据库重新构建这些语句。如果您使用这样的功能,那么您应该将架构格式设置为:sql。

使用:sql格式后,您的架构现在将保存到structure.sql而不是schema.rb。这两个文件可以并排生效,但当您的格式设置为structure.sql时,应用只会:sql更新并使用{{1}}。