Author: admin

  • MySQL – Stored Procedure that returns random rows from a table

    [adsense id=”0514458240″ width=”468″ height=”60″]

    I have seen lots of requests for ways of returning a set of random rows from a table. Based on the analysis performed by Akinas where he analyzed the performance impact of obtaining random rows using a variety of methods, their conclusion was that performing the request using two requests delivered the best overall performance.

    Using this method we have come up with some code for a stored procedure which takes two parameters:

    • A table name
    • Number of rows to be returned

    Here is the code for the stored procedure which is called sp_random(table, rows).

    DROP PROCEDURE IF EXISTS sp_random;
    
    DELIMITER $$
    CREATE PROCEDURE sp_random(IN pTableName VARCHAR(64), IN pLimit SMALLINT UNSIGNED) 
    NOT DETERMINISTIC
    SQL SECURITY INVOKER
    COMMENT 'A procedure that returns a random set of rows from a table'
    BEGIN
    	DECLARE lCount INT UNSIGNED;
    
    	SET @uQuery := CONCAT('SELECT COUNT(1) INTO @uCount FROM ', pTableName);
    	PREPARE stmt FROM @uQuery;
    	EXECUTE stmt;
    
    	IF @uCount <= pLimit THEN
    		-- Return all values
    		SET @query := CONCAT('SELECT * FROM ', pTableName);
    	ELSE
    		-- Return limited number of entries
    		SET @offset := ROUND((@uCount - pLimit) * RAND(),0);
    		SET @query := CONCAT('SELECT * FROM ', pTableName, ' LIMIT ', @offset, ',', pLimit);
    	END IF;
    
    	PREPARE stmt FROM @query;
    	EXECUTE stmt;
    	DEALLOCATE PREPARE stmt;
    END;
    $$
    DELIMITER ;
    

    Viewing this in action we have a table with countries defined and we will have a look at returning random rows:

    mysql> select * from countries;
    +----+-------------+
    | id | country     |
    +----+-------------+
    |  1 | Spain       |
    |  2 | Ireland     |
    |  3 | Andorra     |
    |  4 | Italy       |
    |  5 | Belgium     |
    |  6 | France      |
    |  7 | Germany     |
    |  8 | Netherlands |
    |  9 | Luxembourg  |
    | 10 | Poland      |
    | 11 | Finland     |
    | 12 | Sweden      |
    | 13 | Norway      |
    | 14 | Denmark     |
    +----+-------------+
    14 rows in set (0.00 sec)
    
    mysql> call sp_random('countries',3);
    +----+---------+
    | id | country |
    +----+---------+
    | 10 | Poland  |
    | 11 | Finland |
    | 12 | Sweden  |
    +----+---------+
    3 rows in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> call sp_random('countries',3);
    +----+---------+
    | id | country |
    +----+---------+
    | 11 | Finland |
    | 12 | Sweden  |
    | 13 | Norway  |
    +----+---------+
    3 rows in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> call sp_random('countries',3);
    +----+---------+
    | id | country |
    +----+---------+
    | 12 | Sweden  |
    | 13 | Norway  |
    | 14 | Denmark |
    +----+---------+
    3 rows in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> call sp_random('countries',3);
    +----+---------+
    | id | country |
    +----+---------+
    |  3 | Andorra |
    |  4 | Italy   |
    |  5 | Belgium |
    +----+---------+
    3 rows in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> call sp_random('countries',3);
    +----+---------+
    | id | country |
    +----+---------+
    | 11 | Finland |
    | 12 | Sweden  |
    | 13 | Norway  |
    +----+---------+
    3 rows in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> call sp_random('countries',3);
    +----+---------+
    | id | country |
    +----+---------+
    |  1 | Spain   |
    |  2 | Ireland |
    |  3 | Andorra |
    +----+---------+
    3 rows in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> call sp_random('countries',3);
    +----+---------+
    | id | country |
    +----+---------+
    |  5 | Belgium |
    |  6 | France  |
    |  7 | Germany |
    +----+---------+
    3 rows in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)