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

use*_*833 9 arrays postgresql indexing ruby-on-rails ruby-on-rails-4

我在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
Run Code Online (Sandbox Code Playgroud)

通过psql以下方式验证结果

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

请注意,"标签"索引是类型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)
Run Code Online (Sandbox Code Playgroud)

确实,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
Run Code Online (Sandbox Code Playgroud)

请注意,还有另一个障碍!

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

add_index "photos", ["tags"], :name => "index_photos_on_tags"
Run Code Online (Sandbox Code Playgroud)

潜在的临时解决方法:

add_index "photos", ["tags"], :name => "index_photos_on_tags", using: :gin
Run Code Online (Sandbox Code Playgroud)

警报!

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

mon*_*esh 5

正如 paxer 提到的,您需要:sql通过在您的以下文件中添加(或更改)此行来设置模式格式config/application.rb

config.active_record.schema_format = :sql
Run Code Online (Sandbox Code Playgroud)

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

以下是 Rails 指南中的引用:

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

使用该:sql格式后,您的架构现在将被保存到structure.sql而不是schema.rb. 这两个文件可以并存,但只有structure.sql当您的格式设置为:sql.