2012-01-07 142 views
2

的性能,我此刻很困惑,因爲我有不同的表中兩個索引列。其中一個表格'用戶'擁有約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 

沒有工作


我才意識到一件事這可能會導致問題.. users表有一個字段是一個序列化的Set ..我不認爲這會導致問題。但我認爲這是可能的。


最後更新

所以,出於某種原因,當我還是一個非常新手RoR的開發者,我決定將它與替換「find_by_username」的方法是個好主意我自己的,這將確保它搜索用戶名忽略外殼。

這是非常荒謬的。至於我其實沒有需要改變原來的方法從不同的套管查詢同樣的反應。

所以這個故事的寓意是不包括在任何模型下面的方法....

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

- 臉手掌 -

+2

你試過在查詢上運行解釋嗎? (在MySQL控制檯中) – 2012-01-07 21:54:46

+0

我只是跑瞭解釋,我更新了我的問題以包含額外的信息。 – BananaNeil 2012-01-08 07:15:59

回答

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

此查詢不使用索引。它不能。它將檢索每個用戶名,將其轉換爲小寫,並檢查它是否是'mickeleh'。

解決的辦法是確保東西寫入表格時小寫,然後讀取lower()調用,並使用索引。

我知道RoR很少,或者它爲什麼會以這種方式生成查詢,所以我無法幫到你。

+0

所以,事實證明,我可以運行.where(「username ='MiCkElEH'」),我仍然會得到相同的結果..(很快)。我發現了這個問題(我會在兩秒內更新我的問題),但我只是想讓你知道我並不需要確保每件事情都是小寫。 – BananaNeil 2012-01-08 09:34:33

2

我不知道在哪裏調用lower()從何而來(?這是從唯一性驗證查詢),但會阻止MySQL的使用索引,如解釋輸出所示,迫使它執行全表掃描。