Tôi đang làm việc trên một dự án ( Rails 3.0.15, ruby 1.9.3-p125-perf ) trong đó db nằm trong localhost và bảng người dùng có hơn 100 nghìn bản ghi .
Sử dụng
đặt hàng bởi RAND ()
khá chậm
User.order ("RAND (id)"). Đầu tiên
trở thành
CHỌN users
. * TỪ users
ĐẶT HÀNG THEO RAND (id) GIỚI HẠN 1
và mất từ 8 đến 12 giây để trả lời !!
Nhật ký đường ray:
Tải người dùng (11030.8ms) CHỌN users
. * TỪ users
ĐẶT HÀNG B RNG RAND () GIỚI HẠN 1
từ lời giải thích của mysql
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
| 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 |
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
Bạn có thể thấy rằng không có chỉ mục nào được sử dụng ( ossible_keys = NULL ), một bảng tạm thời được tạo và yêu cầu thêm một lượt để tìm nạp giá trị mong muốn ( thêm = Sử dụng tạm thời; Sử dụng tệp ).
Mặt khác, bằng cách chia truy vấn thành hai phần và sử dụng Ruby, chúng tôi có sự cải thiện hợp lý về thời gian phản hồi.
users = User.scoped.select(:id);nil
User.find( users.first( Random.rand( users.length )).last )
(; không cho sử dụng bàn điều khiển)
Nhật ký đường ray:
Tải người dùng (25,2ms) CHỌN id TỪ users
Tải người dùng (0,2ms) CHỌN
users
. * TỪ users
ĐÂU users
. id
= 106854 GIỚI HẠN 1
và lời giải thích của mysql chứng minh tại sao:
+----+-------------+-------+-------+---------------+--------------------------+---------+------+--------+-------------+
| 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 | |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
bây giờ chúng ta chỉ có thể sử dụng các chỉ mục và khóa chính và thực hiện công việc nhanh hơn khoảng 500 lần!
CẬP NHẬT:
như được chỉ ra bởi icantbecool trong các bình luận, giải pháp trên có một lỗ hổng nếu có các bản ghi bị xóa trong bảng.
Một cách giải quyết trong đó có thể là
users_count = User.count
User.scoped.limit(1).offset(rand(users_count)).first
có nghĩa là hai truy vấn
SELECT COUNT(*) FROM `users`
SELECT `users`.* FROM `users` LIMIT 1 OFFSET 148794
và chạy trong khoảng 500ms.