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_*
で記述された新しいコードはもうありません。 代わりに、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個のUNIQUEランダムな結果を取得することである場合 、その後、PROCEDURE
に2つの変更が必要になります :
-
一時テーブルは、エントリの一意性を強制する必要があります:
CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) UNIQUE);
値ではなくIDだけを収集することも理にかなっているかもしれません。特に、探しているのがタグだけでなく、10個のユニークな記事である場合。
-
重複する値を挿入すると、
cnt
カウンターは減少しないはずです。これは、HANDLER
を追加することで確認できます。 (LOOP
の定義前 )、発生した警告を「キャッチ」し、カウンターを調整します:DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;