2012-01-07 2 views
2

Я очень смущен в данный момент, потому что у меня есть два индексированных столбца на отдельных таблицах. Одна из таблиц «пользователи» имеет около 400 000 записей, а другая «сообщения» содержит около 8 000 000 записей.RoR: Производительность индексированных полей

Я знаю, что эти два поля индексируются, и я подтвердил это с моей схемой:

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 быстрее?


Update:

я запустил объяснить на каждом из вызовов, и я получил следующее:

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 есть поле, которое представляет собой сериализованный набор. И я не думаю, что это вызовет проблему. но я считаю, что это возможно.


FINAL UPDATE

Так, по какой-то причине, когда я был в очень начинающий RoR разработчик, я решил, что это было бы хорошей идеей, чтобы заменить метод «find_by_username» с мой собственный, который бы удостоверился, что он искал имена пользователей, игнорируя корпус.

Это было довольно смешно .. поскольку на самом деле мне не нужно было изменять оригинальный метод, чтобы получить тот же ответ от по-разному опрашиваемых запросов.

Итак, мораль этой истории не включает следующий метод в любую модель ....

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

- лицо ладонь -

+2

Вы попробовали запустить объяснение по запросу? (в консоли MySQL) –

+0

Я только что объяснил, и я обновил свой вопрос, чтобы добавить дополнительную информацию. – BananaNeil

ответ

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

Этот запрос не использует индексы. Это невозможно. Он будет извлекать каждое имя пользователя, преобразовывать его в нижний регистр и проверять, является ли это «mickeleh».

Решение должно состоять в том, чтобы убедиться, что материал находится в нижнем регистре, когда он записывается в таблицу, а затем вы можете прочитать нижний() вызов, и он будет использовать индекс.

Я знаю, где немного о RoR, или почему он будет генерировать запросы таким образом, поэтому я не могу вам помочь.

+0

Итак, как оказалось, я могу запустить .where («username = 'MiCkElEH»), и я все равно получаю тот же результат .. (очень быстро). Я нашел проблему (я обновлю свой вопрос за две секунды), но я просто хотел сообщить вам, что мне действительно не нужно проверять, чтобы каждая вещь была помещена в нижний регистр. – BananaNeil

2

Я не уверен, где вызов lower() пришел из (? Это запрос от уникальности проверки), но это будет препятствовать MySQL с использованием индекса, заставляя его выполнять полное сканирование таблицы, как показывает вывод объяснения.

Смежные вопросы