Per favore, smetti di usare ORDER BY RAND()
. Semplicemente fermati. Questa operazione ha una complessità di n*log2(n)
, il che significa che il tempo dedicato alla query aumenterebbe "
entries | time units
-------------------------
10 | 1 /* if this takes 0.001s */
1'000 | 300
1'000'000 | 600'000 /* then this will need 10 minutes */
Se vuoi generare risultati casuali, crea una stored procedure che li generi. Qualcosa del genere (codice tratto da questo articolo , che dovresti leggere):
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 ;
E per usarlo dovresti scrivere:
CALL get_rands(10);
SELECT * FROM rands;
Per quanto riguarda l'esecuzione sul lato PHP, dovresti smettere di usare l'antico mysql_*
API. Ha più di 10 anni e non è più mantenuto. La community ha persino iniziato il processo
per averli deprecati. Non dovrebbe esserci più nuovo codice scritto con mysql_*
nel 2012. Invece dovresti usare PDO
o MySQLi
. Quanto a come scriverlo (con 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);
}
Aggiorna
Se il requisito è ottenere non solo 10 risultati casuali, ma in realtà 10 risultati casuali UNICI , quindi richiederebbe due modifiche alla PROCEDURE
:
-
La tabella temporanea dovrebbe rafforzare l'unicità delle voci:
CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) UNIQUE);
Potrebbe anche avere senso raccogliere solo ID e non i valori. Soprattutto se quello che stai cercando sono 10 articoli unici, non solo tag.
-
Quando si inserisce un valore duplicato viene trovato il
cnt
contatore non dovrebbe diminuire. Questo può essere garantito aggiungendo unHANDLER
(prima della definizione diLOOP
), che "cattura" l'avviso sollevato e regola il contatore:DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;