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
:
-
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.
-
Wanneer het invoegen van een dubbele waarde wordt gevonden, wordt de
cnt
teller mag niet afnemen. Dit kan worden gegarandeerd door eenHANDLER
. toe te voegen (vóór de definitie vanLOOP
), die de verhoogde waarschuwing zou "vangen", en de teller zou aanpassen:DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;