Prosím, přestaňte používat ORDER BY RAND()
. Přestaň. Tato operace má složitost n*log2(n)
, což znamená, že čas strávený dotazem poroste "
entries | time units
-------------------------
10 | 1 /* if this takes 0.001s */
1'000 | 300
1'000'000 | 600'000 /* then this will need 10 minutes */
Pokud chcete generovat náhodné výsledky, vytvořte uloženou proceduru, která je vygeneruje. Něco takového (kód převzat z tohoto článku , kterou byste si měli přečíst):
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 ;
A abyste jej použili, napsali byste:
CALL get_rands(10);
SELECT * FROM rands;
Pokud jde o spouštění všeho na straně PHP, měli byste přestat používat staré mysql_*
API. Je více než 10 let starý a již neudržovaný. Komunita dokonce zahájila proces
za jejich zavržení. Už by neměl být žádný nový kód napsaný pomocí mysql_*
v roce 2012. Místo toho byste měli použít CHOP
nebo MySQLi
. Pokud jde o to, jak to napsat (s 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);
}
Aktualizovat
Pokud je požadavkem získat nejen 10 náhodných výsledků, ale ve skutečnosti 10 UNIKÁTNÍCH náhodných výsledků , pak by to vyžadovalo dvě změny PROCEDURE
:
-
Dočasná tabulka by měla vynutit jedinečnost položek:
CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) UNIQUE);
Také by mohlo mít smysl shromažďovat pouze ID, nikoli hodnoty. Zvláště pokud to, co hledáte, je 10 jedinečných článků, nikoli pouze tagy.
-
Při vkládání duplicitní hodnoty je nalezen
cnt
čítač by se neměl snižovat. To lze zajistit přidánímHANDLER
(před definicíLOOP
), který by „zachytil“ zvednuté varování a upravil počítadlo:DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;