Plugins - find random

StarAdd to favorites

Find Random

The plugin provides a (somewhat) scalable way to select random rows from a table. It runs significantly faster than asking MySQL to "ORDER BY RAND()". Behind the scenes it grabs all ids that match the query conditions, then selects a random subset of these for which it then asks the database for the full records. The initial query is done outside of ActiveRecord to avoid needless object instantiation.

If only one result is requested a different strategy is used. First a query is done to determine the number of results, then a single result is selected using a random offset. This removes the memory inefficiency of the method used when selecting multiple results.

Usage

# select 5 random items that match the :conditions
@items = Item.random(5, :conditions => ["col1 = ? or col2 = ?", val1, val2])

# select any 5 random items
@items = Item.random(5)

Limitations

Currently this plugin only supports joins if a single result is requested. Additionally the current implementation for selecting multiple random results is somewhat memory inefficient and probably won't perform well on tables with greater than 100,000 rows. Suggestions for improvement welcome.

Benchmark

Comparing this method against ORDER BY RAND() in MySQL on a table with 30,000 rows:

$ ./script/performance/benchmarker 1 'Person.random(8)' 'Person.find(:all, :order => "RAND()", :limit => 8)'
user system total real
#1 0.030000 0.000000 0.030000 ( 0.149027)
#2 0.000000 0.000000 0.000000 ( 5.516728)

Contact

Patches very much welcome.

Ben Tucker

http://github.com/btucker/find_random/tree

git://github.com/btucker/find_random.git

Rails' (MIT)

  • Currently 5.0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Model

Tags

Comments

Add a comment
Mike Larkin 22 Jun 2008

sorry, meant to paste: if result_size < 2 find(:first, options) else find(:first, options.merge(:offset => rand(result_size))) end

Mike Larkin 22 Jun 2008

It seems to throw an error if the resultset is 0.

I added a check for that to the plugin:

if result_size < 2 find(:first) else find(:first, options.merge(:offset => rand(result_size))) end

Search Plugins

Query syntax

Plugins by Category

Sponsors

Rails Kits: Get Code. Get Moving.

Have a comment?