sql >> Database >  >> RDS >> Mysql

Een while/loop doen om 10 willekeurige resultaten te krijgen

Alsjeblieft, stop met het gebruik van ORDER BY RAND() . Stop gewoon. Deze bewerking heeft een complexiteit van n*log2(n) , wat betekent dat de tijd die aan zoekopdrachten wordt besteed zou toenemen "

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

Als u willekeurige resultaten wilt genereren, maakt u een opgeslagen procedure die ze genereert. Iets als dit (code overgenomen uit dit artikel , die u moet lezen):

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 ;

En om het te gebruiken, zou je schrijven:

CALL get_rands(10);
SELECT * FROM rands;

Wat betreft het uitvoeren van alles aan PHP-kant, moet je stoppen met het gebruik van de oude mysql_* API. Hij is meer dan 10 jaar oud en wordt niet meer onderhouden. Community heeft zelfs een proces begonnen om ze af te wijzen. Er mag geen nieuwe code meer worden geschreven met mysql_* in 2012. In plaats daarvan moet u BOB gebruiken of MySQLi . Wat betreft hoe het te schrijven (met 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);
}

Bijwerken

Als de vereiste is om niet alleen 10 willekeurige resultaten te krijgen, maar eigenlijk 10 UNIEKE willekeurige resultaten , dan zijn er twee wijzigingen nodig in de PROCEDURE :

  1. De tijdelijke tabel moet de uniciteit van de gegevens afdwingen:

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

    Het kan ook zinvol zijn om alleen ID's te verzamelen en niet de waarden. Vooral als je op zoek bent naar 10 unieke artikelen, niet alleen tags.

  2. Wanneer het invoegen van een dubbele waarde wordt gevonden, wordt de cnt teller mag niet afnemen. Dit kan worden gegarandeerd door een HANDLER . toe te voegen (vóór de definitie van LOOP ), die de verhoogde waarschuwing zou "vangen", en de teller zou aanpassen:

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


  1. Hoe dit te doen in Laravel, subquery waar in

  2. Aankondiging van ClusterControl 1.7.2:verbeterde PostgreSQL-back-up en ondersteuning voor TimescaleDB en MySQL 8.0

  3. Kerndumpbestand en foutopsporingscodes toevoegen in het uitvoerbare programma voor Oracle Apps

  4. Hoe een tabel te vinden waarin statistieken zijn vergrendeld