Db'nin localhost'ta olduğu ve kullanıcılar tablosunun 100K'dan biraz fazla kayıt içerdiği bir proje ( Rails 3.0.15, ruby 1.9.3-p125-perf ) üzerinde çalışıyorum .
kullanma
RAND'ye göre sipariş ()
oldukça yavaş
User.order ( "RAND (id)"). İlk
olur
SEÇİN users
. * users
RANDA GÖRE SIRALAMA (id) SINIRI 1
ve yanıt vermesi 8 ila 12 saniye sürer !!
Rails günlüğü:
Kullanıcı Yükü (11030.8ms) SEÇİMİ users
* RANDA users
GÖRE SIRALAMA () LİMİTİ 1
mysql'in açıklamasından
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 110165 | Using temporary; Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
Hiçbir indeksin kullanılmadığını ( olası_anahtarlar = NULL ), geçici bir tablo oluşturulduğunu ve istenen değeri almak için fazladan bir geçiş gerektiğini görebilirsiniz ( ekstra = Geçici kullanma; Dosya sıralaması kullanma ).
Öte yandan, sorguyu ikiye bölerek ve Ruby kullanarak yanıt süresinde makul bir iyileşme elde ettik.
users = User.scoped.select(:id);nil
User.find( users.first( Random.rand( users.length )).last )
(; konsol kullanımı için nil)
Rails günlüğü:
Kullanıcı Yükü (25,2 ms) Kullanıcı Yükünden (0,2 ms) KİMLİĞİ users
SEÇİN
users
. * users
NEREDEN users
. id
= 106854 LİMİT 1
ve mysql açıklaması nedenini kanıtlıyor:
+----+-------------+-------+-------+---------------+--------------------------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+--------------------------+---------+------+--------+-------------+
| 1 | SIMPLE | users | index | NULL | index_users_on_user_type | 2 | NULL | 110165 | Using index |
+----+-------------+-------+-------+---------------+--------------------------+---------+------+--------+-------------+
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
artık yalnızca dizinleri ve birincil anahtarı kullanabilir ve işi yaklaşık 500 kat daha hızlı yapabiliriz!
GÜNCELLEME:
icantbecool'un yorumlarda işaret ettiği gibi, tabloda silinmiş kayıtlar varsa yukarıdaki çözümün bir kusuru vardır.
Bir geçici çözüm olabilir
users_count = User.count
User.scoped.limit(1).offset(rand(users_count)).first
iki sorguya çeviren
SELECT COUNT(*) FROM `users`
SELECT `users`.* FROM `users` LIMIT 1 OFFSET 148794
ve yaklaşık 500 ms'de çalışır.