sql >> Databasteknik >  >> RDS >> Mysql

Gör en stund/loop för att få 10 slumpmässiga resultat

Vänligen sluta använda ORDER BY RAND() . Bara sluta. Denna operation har komplexiteten n*log2(n) , vilket innebär att tiden som spenderas på frågan skulle växa "

    entries  |  time units
  -------------------------
         10  |         1     /* if this takes 0.001s */
      1'000  |       300
  1'000'000  |   600'000     /* then this will need 10 minutes */

Om du vill generera slumpmässiga resultat, skapa en lagrad procedur som genererar dem. Något liknande detta (koden hämtad från denna artikel , som du bör läsa):

DELIMITER $$
DROP PROCEDURE IF EXISTS get_rands$$
CREATE PROCEDURE get_rands(IN cnt INT)
BEGIN
  DROP TEMPORARY TABLE IF EXISTS rands;
  CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) );

loop_me: LOOP
    IF cnt < 1 THEN
      LEAVE loop_me;
    END IF;

    SET cnt = cnt - 1;

    INSERT INTO rands
       SELECT tags.tagname
         FROM tags 
         JOIN (SELECT (RAND()*(SELECT MAX(tags.id) FROM tags)) AS id) AS choices
        WHERE tags.id >= choices.id
        LIMIT 1;

  END LOOP loop_me;
END$$
DELIMITER ;

Och för att använda det skulle du skriva:

CALL get_rands(10);
SELECT * FROM rands;

När det gäller att köra allt på PHP-sidan, bör du sluta använda den gamla mysql_* API. Den är mer än 10 år gammal och underhålls inte längre. Community har till och med startat processen för att avvisa dem. Det borde inte finnas någon mer ny kod skriven med mysql_* 2012. Istället bör du använda PDO eller MySQLi . När det gäller hur man skriver det (med PDO):

// creates DB connection
$connection = new PDO('mysql:host=localhost;dbname=mydb;charset=UTF-8', 
                      'username', 'password');
$connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

// executes the procedure and creates select statement
$connection->exec('CALL get_rands(10)');
$statement = $connection->query('SELECT * FROM rands');

// performs query and collects all the info
if ($statement->execute())
{
    $tags = $statement->fetchAll(PDO::FETCH::ASSOC);
}

Uppdatera

Om kravet är att få inte bara 10 slumpmässiga resultat, utan faktiskt 10 UNIKA slumpmässiga resultat , då skulle det krävas två ändringar av PROCEDURE :

  1. Den temporära tabellen bör upprätthålla det unika med poster:

    CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) UNIQUE);
    

    Det kan också vara vettigt att bara samla ID:n och inte värdena. Speciellt om det du letar efter är 10 unika artiklar, inte bara taggar.

  2. När du infogar ett dubblettvärde hittas cnt räknaren bör inte minska. Detta kan säkerställas genom att lägga till en HANDLER (före definition av LOOP ), som skulle "fånga" den upphöjda varningen och justera räknaren:

    DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;
    


  1. Databas endast backuper i WHM

  2. MySQL Master To Master Replikering

  3. Hur listar jag tillägg installerade i en databas med psql?

  4. Hur SQLite Random() fungerar