Моля, спрете да използвате ORDER BY RAND()
. Просто спри. Тази операция има сложност от n*log2(n)
, което означава, че времето, прекарано в заявка, ще нарасне "
entries | time units
-------------------------
10 | 1 /* if this takes 0.001s */
1'000 | 300
1'000'000 | 600'000 /* then this will need 10 minutes */
Ако искате да генерирате произволни резултати, създайте съхранена процедура, която ги генерира. Нещо подобно (код, взет от тази статия , което трябва да прочетете):
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 ;
И за да го използвате, трябва да напишете:
CALL get_rands(10);
SELECT * FROM rands;
Що се отнася до изпълнението на всичко от страна на PHP, трябва да спрете да използвате древния mysql_*
API. Той е на повече от 10 години и вече не се поддържа. Общността дори започна процес
за отхвърлянето им. Не трябва да има повече нов код, написан с mysql_*
през 2012 г. Вместо това трябва да използвате PDO
или MySQLi
. Колкото до това как да го напиша (със 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);
}
Актуализиране
Ако изискването е да получите не само 10 произволни резултата, но всъщност 10 УНИКАЛНИ произволни резултата , тогава ще са необходими две промени в PROCEDURE
:
-
Временната таблица трябва да налага уникалността на записите:
CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) UNIQUE);
Също така може да има смисъл да събирате само идентификатори, а не стойностите. Особено ако това, което търсите, са 10 уникални статии, а не само тагове.
-
При вмъкване на дублирана стойност се намира
cnt
броячът не трябва да намалява. Това може да се гарантира чрез добавяне наHANDLER
(преди дефинирането наLOOP
), което ще „улови“ повдигнатото предупреждение и ще коригира брояча:DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;