sql >> Database teknologi >  >> RDS >> Mysql

Gør et stykke tid / loop for at få 10 tilfældige resultater

Venligst stop med at bruge ORDER BY RAND() . Bare stop. Denne operation har kompleksiteten n*log2(n) , hvilket betyder, at tiden brugt på forespørgslen ville vokse "

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

Hvis du vil generere tilfældige resultater, skal du oprette en lagret procedure, som genererer dem. Noget som dette (kode taget fra denne artikel , som du bør læse):

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 ;
 

Og for at bruge det, ville du skrive:

CALL get_rands(10);
SELECT * FROM rands;
 

Med hensyn til at udføre det hele på PHP-siden, bør du stoppe med at bruge den gamle mysql_* API. Den er mere end 10 år gammel og vedligeholdes ikke længere. Fællesskabet har endda begyndt processen for at afvise dem. Der skulle ikke være mere ny kode skrevet med mysql_* i 2012. I stedet skal du bruge PDO eller MySQLi . Med hensyn til hvordan 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);
}
 

Opdater

Hvis kravet er at få ikke kun 10 tilfældige resultater, men faktisk 10 UNIKKE tilfældige resultater , så ville det kræve to ændringer af PROCEDURE :

  1. Den midlertidige tabel skal håndhæve det unikke ved indgange:

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

    Det kan også give mening kun at indsamle ID'er og ikke værdierne. Især hvis det, du leder efter, er 10 unikke artikler, ikke kun tags.

  2. Når der er fundet en dubletværdi, vises cnt tælleren bør ikke falde. Dette kan sikres ved at tilføje en HANDLER (før definition af LOOP ), som ville "fange" den hævede advarsel og justere tælleren:

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


  1. JSON_VALUE() Funktion i Oracle

  2. Bruger samme kolonne flere gange i WHERE-sætning

  3. Gruppevist maksimum

  4. Korrekthed og begrænsninger