Laravel Query Builder: Select N Random Rows the Right Way

Updated: January 16, 2024 By: Guest Contributor Post a comment

Introduction

If you’ve been using Laravel for web development, you’re likely familiar with Eloquent ORM, a powerful and fluent Object-Relational Mapper. But there are times when the Query Builder, which offers a less opinionated and direct access to the database, is more suitable for certain tasks. One such task is the selection of a number of random rows from a database table. This tutorial guides you through different methods to achieve this using Laravel’s Query Builder, starting from basic to more advanced techniques.

Before we dive into the examples, ensure you have a Laravel project set up and a database configured. We will work with a hypothetical users table that has a primary key of id. Our goal is to select N random users from this table.

Basic Random Selection

To start with the basics, Laravel offers a simple way to get random rows:

$randomUsers = DB::table('users')->inRandomOrder()->limit(5)->get();

This query will return 5 random users from the users table. The method inRandomOrder() is responsible for the randomization, and limit() specifies the count of rows you wish to retrieve.

Intermediate – Seeding the Randomness

When you need repeatable results – for instance, during testing or generating recommendations – it would be beneficial to seed your random query:

$randomUsers = DB::table('users')
    ->inRandomOrder('seed')->limit(5)->get();

By providing a seed value, you ensure the randomness is the same across multiple calls, given the data in the database remains constant.

Performance Considerations

Selecting random rows using inRandomOrder() is not always performance-friendly, especially with large datasets. Each database engine handles randomization differently, and it may be resource-intensive. In cases where performance is crucial, you may need to use database-specific queries or more complex logic.

Advanced Techniques

In a MySQL database, for example, you could optimize random selection by using RAND() combined with a WHERE condition to limit the scope of randomization:

$randomUsers = DB::table('users')
    ->whereRaw('RAND() < (SELECT ((1 / COUNT(*)) * 10) FROM users)')
    ->limit(5)
    ->get();

This creates a random selection efficiently; however, it assumes even distribution of records and may not be as random as you like for smaller datasets. Another way is to pre-calculate a random set of identifiers and then retrieve rows with those identifiers:

$userCount = DB::table('users')->count();
$randomIds = collect(range(1, $userCount))->random(5);
$randomUsers = DB::table('users')->whereIn('id', $randomIds)->get();

While this technique avoids heavy database lifting for randomization, it makes the assumption that IDs are sequential and without large gaps, which might not always be the case.

Pagination and Randomness

What if you want to combine random row selection with pagination? The Laravel Query Builder allows you to paginate results. However, combining randomness with pagination can be challenging since pagination relies on predictable and consistent ordering. To solve this issue, you could cache the randomized identifiers for the pagination duration:

CachedRandomPagination::make('users.random', function() {
    return DB::table('users')->inRandomOrder()->pluck('id');
}, 5, true);

This hypothetical CachedRandomPagination class could handle the storing of randomly ordered identifiers and serve them consistently across paginated requests.

Conclusion

In conclusion, Laravel provides a couple of simple to advanced methods to select a random set of rows using the Query Builder. The most straightforward method is to use inRandomOrder(), while advanced methods can be adopted for higher performance with larger datasets or specific randomness constraints. Choosing the right technique depends on your application’s requirements and the size of your data.