RoR:索引字段的性能

时间:2012-01-07 21:46:27

标签: mysql ruby-on-rails database performance

我现在很困惑,因为我在不同的表上有两个索引列。其中一个表“用户”有大约400,000个条目,另一个“帖子”有大约8,000,000个条目。

我知道这两个字段已编入索引,我已使用我的架构确认了它:

add_index "users", ["username"], :name => "index_users_on_username", :unique => true
add_index "posts", ["tag"], :name => "index_posts_on_tag", :unique => true

但不知何故,当我运行以下内容时,需要10到13秒:

User.find_by_username("mickeleh")

当我在帖子上运行基本相同的东西时,它只需不到一秒钟!

Post.find_by_tag("En-SKKB67Cg")

有人可以向我解释为什么会发生这种情况吗? 和/或我如何能够让我的User.find_by_username方法运行得更快?


更新

我对每个电话都进行了解释,我得到了以下内容:

mysql> explain SELECT `users`.* FROM `users` WHERE (lower(username) = 'mickeleh');
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | users | ALL  | NULL          | NULL | NULL    | NULL | 304548 | Using where |
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+

mysql> explain SELECT `posts`.* FROM `posts` WHERE `posts`.`tag` = 'En-SKKB67Cg' LIMIT 1;
+----+-------------+--------+-------+---------------------+---------------------+---------+-------+------+-------+
| id | select_type | table  | type  | possible_keys       | key                 | key_len | ref   | rows | Extra |
+----+-------------+--------+-------+---------------------+---------------------+---------+-------+------+-------+
|  1 | SIMPLE      | posts | const | index_posts_on_tag | index_posts_on_tag | 258     | const |    1 |       |
+----+-------------+--------+-------+---------------------+---------------------+---------+-------+------+-------+

我不确定如何阅读返回的内容,所以非常感谢一些帮助。

我还创建了一个新的迁移来“重置”用户用户名列上的索引,如下所示:

remove_index :users, :column => :username
add_index :users, :username, :unique => true

它不起作用


我刚刚意识到可能导致问题的另一件事..用户表有一个字段是一个序列化的集..我不认为这会导致问题。但我认为这是可能的。


最终更新

所以,出于某种原因,当我是 非常 新手RoR开发人员时,我认为用自己的方法替换'find_by_username'方法是个好主意这将确保它搜索忽略外壳的用户名。

这非常荒谬..因为我实际上并不需要改变原始方法来从不同的查询中获得相同的响应。

故事的寓意是在任何模型中都不包括以下方法....

def self.find_by_username(name)
   User.where("lower(username) = '#{name.downcase}'")[0]
end

- 面掌 -

2 个答案:

答案 0 :(得分:2)

我不确定lower()的调用来自哪里(这是来自唯一性验证的查询吗?)但是这会阻止mysql使用索引,强制它执行全表扫描,如解释输出显示。

答案 1 :(得分:2)

SELECT `users`.* FROM `users` WHERE (lower(username) = 'mickeleh');

此查询未使用索引。它不能。它将检索每个用户名,将其转换为小写,并检查它是否为'mickeleh'。

解决方案是确保在写入表中时填充小写,然后你可以读取lower()调用,它将使用索引。

我知道RoR很少,或者为什么会以这种方式生成查询,所以我无法帮助你。