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 :
-
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.
-
Når der er fundet en dubletværdi, vises
cnttælleren bør ikke falde. Dette kan sikres ved at tilføje enHANDLER(før definition afLOOP), som ville "fange" den hævede advarsel og justere tælleren:DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;