是否可以通过Rails / ActiveRecord迁移添加基于函数的数据库无关索引?

时间:2010-08-03 15:33:07

标签: ruby-on-rails database activerecord indexing

我有一个像这样的ActiveRecord模型:

create_table "books" do |t|
  t.string "title"
end

class Book < ActiveRecord::Base
  default_scope :order => 'lower(title) DESC'
end

正如您所看到的,我希望按title属性的小写形式排序,但这会在数据库级别上造成性能损失。可以使用不同的数据库以不同的方式纠正此命中。例如,在PostgreSQL或Oracle中,您可以创建基于函数的索引:

CREATE INDEX lowercase_book_title_index ON book (lower(title));

SQLite3没有基于函数的索引,因此您必须指定排序规则:

CREATE INDEX lowercase_book_title_index ON book (title COLLATE NOCASE);

我没有研究过你是如何使用MySQL的,但我确定有一种方法(整理?虚拟列?)。

无论如何,我想以正确的Rails方式进行数据库无关的迁移。我当然可以创建一个这样的简单索引:

add_index :books, :title

但是这个生成的索引区分大小写。我意识到我可以编写一个依赖于数据库的迁移,但它不是很优雅。它也不实用 - 我经常发现自己在我的开发工作站上使用SQLite3,在生产中使用PostgreSQL。 add_index的可用选项处理索引名称,唯一性和长度。我是否忽略了一种方法来完成我在这里要做的事情?

2 个答案:

答案 0 :(得分:1)

简答:不是

答案很长:不是,因为并非所有数据库引擎都支持Rails支持的内容,或者采用非常不同的方式。如果您确定所有数据库引擎都支持它,那么请为ActiveRecord开发人员提交功能请求。

请记住:在ActiveRecord迁移中,您只能执行所有数据库引擎支持的操作,特定于数据库的内容需要从迁移中分离初始化。

我建议在db:migrate之后运行的分离的rake任务中设置此排序规则。在我更大的应用程序中,我使用rake setup我可以执行这些特定步骤。

答案 1 :(得分:0)

我从未对这种排序有任何问题。基本上,你想要的是结果以这种方式排序:

"A bad title"
"A better title"
"a good title"
"An excellent title"

如果这是正确的并且你要使用mysql,你可以在database.yml中指定一个排序规则,试试:

production:
  adapter: mysql2 # or mysql for rails < 3
  host: ...
  database: ...
  username: ...
  encoding: utf8 # or whatever you are using
  collation: utf8_general_ci # or whatever fits your language and encoding

utf8_general_ci表示“以与语言无关的方式与utf8进行整理并且不区分大小写”。

这应该可以解决问题。