Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Ausführen einer While / Schleife, um 10 zufällige Ergebnisse zu erhalten

Bitte beenden Sie die Verwendung von ORDER BY RAND() . Hör einfach auf. Diese Operation hat eine Komplexität von n*log2(n) , was bedeutet, dass die für die Abfrage aufgewendete Zeit zunehmen würde "

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

Wenn Sie zufällige Ergebnisse generieren möchten, erstellen Sie eine gespeicherte Prozedur, die sie generiert. Etwa so (Code aus diesem Artikel ). , die Sie lesen sollten):

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 ;

Und um es zu verwenden, würden Sie schreiben:

CALL get_rands(10);
SELECT * FROM rands;

Um das alles auf PHP-Seite auszuführen, sollten Sie aufhören, das alte mysql_* zu verwenden API. Es ist über 10 Jahre alt und wird nicht mehr gewartet. Die Community hat sogar einen Prozess begonnen dafür, sie abzulehnen. Es sollte kein neuer Code mehr mit mysql_* geschrieben werden im Jahr 2012. Stattdessen sollten Sie PDO verwenden oder MySQLi . Wie man es schreibt (mit 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);
}

Aktualisieren

Wenn die Anforderung darin besteht, nicht nur 10 zufällige Ergebnisse zu erhalten, sondern tatsächlich 10 EINZIGARTIGE zufällige Ergebnisse , dann wären zwei Änderungen am PROCEDURE erforderlich :

  1. Die temporäre Tabelle soll die Eindeutigkeit der Einträge erzwingen:

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

    Es kann auch sinnvoll sein, nur IDs und nicht die Werte zu sammeln. Vor allem, wenn Sie nach 10 einzigartigen Artikeln suchen, nicht nur nach Tags.

  2. Beim Einfügen wird ein doppelter Wert gefunden, der cnt Der Zähler sollte nicht sinken. Dies kann durch Hinzufügen eines HANDLER sichergestellt werden (vor der Definition von LOOP ), die die ausgelöste Warnung „abfangen“ und den Zähler anpassen würden:

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