답변:
간결한 간격에서 비 균일 한 간격에 이르기까지 여러 사례를 처리하는 훌륭한 포스트입니다.
http://jan.kneschke.de/projects/mysql/order-by-rand/
가장 일반적인 경우는 다음과 같습니다.
SELECT name
FROM random AS r1 JOIN
(SELECT CEIL(RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
이것은 id의 분포가 같고 id 목록에 간격이있을 수 있다고 가정합니다. 고급 예제는 기사를 참조하십시오.
mysqli_fetch_assoc($result)
합니까? 아니면 그 10 개의 결과가 반드시 구별 될 필요는 없습니까?
SELECT column FROM table
ORDER BY RAND()
LIMIT 10
효율적인 솔루션은 아니지만 작동
ORDER BY RAND()
상대적으로 느리다
SELECT words, transcription, translation, sound FROM vocabulary WHERE menu_id=$menuId ORDER BY RAND() LIMIT 10
는 0.0010을 취하고, LIMIT 10을 사용하지 않고 0.0012를 취했습니다 (그 표에서 3500 단어).
성능 이 우수하고 간격 이있는 간단한 쿼리 :
SELECT * FROM tbl AS t1 JOIN (SELECT id FROM tbl ORDER BY RAND() LIMIT 10) as t2 ON t1.id=t2.id
200K 테이블에 대한이 쿼리는 0.08 초가 걸리고 일반 버전 (SELECT * FROM tbl ORDER BY RAND () LIMIT 10)은 내 컴퓨터에서 0.35 초가 걸립니다 .
정렬 단계는 색인화 된 ID 열만 사용하므로 빠릅니다. Explain에서이 동작을 볼 수 있습니다.
RAND () 제한 10을 기준으로 tbl 주문에서 선택 * :
t1부터 AS t1에서 선택 * t2 ON t1.id = t2.id로 (tbl ORDER BY RAND () LIMIT 10에서 id 선택)
나는 무엇입니까 빠른 쿼리 로 (약 0.5 초) 속도가 느린 CPU 400K 등록 MySQL 데이터베이스 캐시되지 않은 2 기가 바이트 크기의 10 개 임의의 행을 선택. 내 코드를 참조하십시오 : MySQL에서 임의의 행을 빠르게 선택 하십시오.
<?php
$time= microtime_float();
$sql='SELECT COUNT(*) FROM pages';
$rquery= BD_Ejecutar($sql);
list($num_records)=mysql_fetch_row($rquery);
mysql_free_result($rquery);
$sql="SELECT id FROM pages WHERE RAND()*$num_records<20
ORDER BY RAND() LIMIT 0,10";
$rquery= BD_Ejecutar($sql);
while(list($id)=mysql_fetch_row($rquery)){
if($id_in) $id_in.=",$id";
else $id_in="$id";
}
mysql_free_result($rquery);
$sql="SELECT id,url FROM pages WHERE id IN($id_in)";
$rquery= BD_Ejecutar($sql);
while(list($id,$url)=mysql_fetch_row($rquery)){
logger("$id, $url",1);
}
mysql_free_result($rquery);
$time= microtime_float()-$time;
logger("num_records=$num_records",1);
logger("$id_in",1);
logger("Time elapsed: <b>$time segundos</b>",1);
?>
ORDER BY RAND()
FLUSH STATUS; SELECT ...; SHOW SESSION STATUS LIKE 'Handler%';
그것을 볼 때 사용 하십시오.
ORDER BY RAND()
행보다 ID 만 정렬하므로 임시 테이블은 작지만 여전히 정렬해야한다는 것입니다.
매우 간단하고 한 줄로 된 쿼리입니다.
SELECT * FROM Table_Name ORDER BY RAND() LIMIT 0,10;
order by rand()
테이블이 크면 매우 느립니다
책에서 :
오프셋을 사용하여 임의의 행을 선택하십시오.
이전 대안에서 발견 된 문제점을 피하는 또 다른 기술은 데이터 세트의 행을 계산하고 0과 수 사이의 난수를 리턴하는 것입니다. 그런 다음 데이터 세트를 쿼리 할 때이 숫자를 오프셋으로 사용하십시오.
<?php
$rand = "SELECT ROUND(RAND() * (SELECT COUNT(*) FROM Bugs))";
$offset = $pdo->query($rand)->fetch(PDO::FETCH_ASSOC);
$sql = "SELECT * FROM Bugs LIMIT 1 OFFSET :offset";
$stmt = $pdo->prepare($sql);
$stmt->execute( $offset );
$rand_bug = $stmt->fetch();
연속 키 값을 가정 할 수없고 각 행에 고른 기회가 있는지 확인해야 할 때이 솔루션을 사용하십시오.
SELECT count(*)
속도가 느려집니다.
테이블에서 임의의 행을 선택하는 방법 :
여기에서 : MySQL에서 임의의 행을 선택 하십시오.
"테이블 스캔"보다 빠른 개선은 인덱스를 사용하여 임의의 ID를 선택하는 것입니다.
SELECT *
FROM random, (
SELECT id AS sid
FROM random
ORDER BY RAND( )
LIMIT 10
) tmp
WHERE random.id = tmp.sid;
PRIMARY KEY
).
키에 틈이없고 모두 숫자이면 임의의 숫자를 계산하고 해당 줄을 선택할 수 있습니다. 그러나 이것은 아마도 그렇지 않을 것입니다.
따라서 한 가지 해결책은 다음과 같습니다.
SELECT * FROM table WHERE key >= FLOOR(RAND()*MAX(id)) LIMIT 1
기본적으로 키 범위에서 임의의 숫자를 얻은 다음 다음 중 가장 큰 것을 선택합니다. 이것을 10 번해야합니다.
그러나 키가 균등하게 분배되지 않기 때문에 이것은 실제로 무작위가 아닙니다.
실제로 큰 문제이며 모든 요구 사항을 충족시키기가 쉽지 않습니다. MySQL의 rand ()는 10 개의 임의 행을 원할 때 얻을 수있는 최선입니다.
그러나 다른 솔루션은 빠르지 만 무작위성에 관해서는 트레이드 오프가 있지만 더 잘 맞을 수 있습니다. 여기에서 읽으십시오 : MySQL의 ORDER BY RAND () 함수를 어떻게 최적화 할 수 있습니까?
질문은 당신이 얼마나 랜덤해야 하는가입니다.
좀 더 설명해 주시면 좋은 해결책을 드릴 수 있습니다.
예를 들어, 내가 함께 일한 회사는 절대 무작위성이 매우 빠른 솔루션을 가지고있었습니다. 결과적으로 내림차순으로 선택한 임의의 값으로 데이터베이스를 미리 채우고 나중에 다른 임의의 값으로 설정했습니다.
거의 업데이트하지 않으면 증분 ID를 채울 수 있으므로 간격이 없으며 선택하기 전에 임의의 키를 계산할 수 있습니다 ... 사용 사례에 따라 다릅니다!
Id
및 모든 사용자의 임의 쿼리는 당신에게 하나를 반환합니다 Id
.
FLOOR(RAND()*MAX(id))
더 큰 ID를 반환하는쪽으로 편향되어 있습니다.
다소 큰 테이블에서 많은 수의 임의 행을 반환하는 쿼리가 필요했습니다. 이것이 내가 생각해 낸 것입니다. 먼저 최대 레코드 ID를 얻으십시오.
SELECT MAX(id) FROM table_name;
그런 다음 해당 값을 다음으로 대체하십시오.
SELECT * FROM table_name WHERE id > FLOOR(RAND() * max) LIMIT n;
여기서 max는 테이블의 최대 레코드 ID이고 n은 결과 집합에서 원하는 행 수입니다. 레코드 ID에 차이가 없다고 가정하지만 (있는 경우 시도하지 않은 경우) 결과에 영향을 줄 것입니다. 또한이 저장 프로 시저를보다 일반적인 것으로 만들었습니다. 반환 할 테이블 이름과 행 수를 전달하십시오. Windows 2008, 32GB, 듀얼 3GHz E5450 및 17,361,264 행이있는 테이블에서 MySQL 5.5.38을 실행 중이며 1,000,000 행을 반환하기 위해 ~ .03 초 / ~ 11 초에서 상당히 일관성이 있습니다. (시간은 MySQL Workbench 6.1에서 온 것입니다. 선호도에 따라 두 번째 select 문에서 FLOOR 대신 CEIL을 사용할 수도 있습니다)
DELIMITER $$
USE [schema name] $$
DROP PROCEDURE IF EXISTS `random_rows` $$
CREATE PROCEDURE `random_rows`(IN tab_name VARCHAR(64), IN num_rows INT)
BEGIN
SET @t = CONCAT('SET @max=(SELECT MAX(id) FROM ',tab_name,')');
PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @t = CONCAT(
'SELECT * FROM ',
tab_name,
' WHERE id>FLOOR(RAND()*@max) LIMIT ',
num_rows);
PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
$$
그때
CALL [schema name].random_rows([table name], n);
모든 최고의 답변이 이미 게시되었습니다 (주로 http://jan.kneschke.de/projects/mysql/order-by-rand/ 링크 참조 ).
또 다른 속도 향상 가능성을 캐싱 하고 싶습니다 . 임의의 행을 가져와야하는 이유를 생각해보십시오. 웹 사이트에 임의의 게시물이나 임의의 광고를 표시하려고 할 수 있습니다. 100 req / s를 얻는다면 각 방문자가 임의의 행을 가져와야합니까? 일반적으로 이러한 X 임의 행을 1 초 (또는 10 초) 동안 캐시하는 것이 좋습니다. 동일한 1 초에 100 명의 순 방문자가 동일한 임의의 게시물을 얻는다면 문제가되지 않습니다. 다음 초에 100 명의 다른 방문자가 다른 게시물을 가져 오기 때문입니다.
이 캐싱을 사용할 때 요청 / 초에 관계없이 초당 1 회만 MySQL에서 가져 오기 때문에 임의의 데이터를 가져 오기 위해 더 느린 솔루션을 사용할 수도 있습니다.
@Riedsio의 답변을 개선했습니다. 이것은 간격 이 좁고 균일하게 분산 된 큰 테이블에서 찾을 수있는 가장 효율적인 쿼리입니다 (> 2.6B 행이있는 테이블에서 1000 개의 임의 행을 가져 오는 테스트).
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max := (SELECT MAX(id) FROM table)) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1)
무슨 일이 일어나고 있는지 짐을 풀자.
@max := (SELECT MAX(id) FROM table)
MAX(id)
경우 행이 필요할 때마다 계산에 약간의 오버 헤드 가 있습니다.SELECT FLOOR(rand() * @max) + 1 as rand)
SELECT id FROM table INNER JOIN (...) on id > rand LIMIT 1
통합을 수행하면 모든 쿼리를 하나의 쿼리에 맞추는 데 도움이되므로 여러 쿼리를 수행하지 않아도됩니다. 또한 계산 오버 헤드를 줄일 수 있습니다 MAX(id)
. 응용 프로그램에 따라이 문제는 매우 중요하거나 거의 중요하지 않을 수 있습니다.
이것은 id 만 가져오고 무작위 순서로 가져옵니다. 더 진보 된 것을하고 싶다면 다음과 같이하십시오.
SELECT t.id, t.name -- etc, etc
FROM table t
INNER JOIN (
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max := (SELECT MAX(id) FROM table)) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1)
) x ON x.id = t.id
ORDER BY t.id
LIMIT 1
로 LIMIT 30
쿼리에서 사방
LIMIT 1
하는 LIMIT 30
테이블의 임의의 점에서 당신에게 연속 (30 개) 기록을 얻을 것입니다. 대신 (SELECT id FROM ....
중간에 부품의 사본 30 개가 있어야합니다 .
Riedsio
. 나는 centos 7에서 PHP 7.0.22와 MariaDB를 사용하여 초당 500 페이지의 히트를 시도했지만 Riedsio
대답은 500 + 여분의 성공적인 응답을 얻었습니다.
Riedsio가 게시 한이 http://jan.kneschke.de/projects/mysql/order-by-rand/를 사용했습니다 (하나 이상의 임의의 값을 반환하는 저장 프로 시저의 경우를 사용했습니다).
DROP TEMPORARY TABLE IF EXISTS rands;
CREATE TEMPORARY TABLE rands ( rand_id INT );
loop_me: LOOP
IF cnt < 1 THEN
LEAVE loop_me;
END IF;
INSERT INTO rands
SELECT r1.id
FROM random AS r1 JOIN
(SELECT (RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1;
SET cnt = cnt - 1;
END LOOP loop_me;
이 기사에서 그는 테이블을 유지함으로써 트리거 결과 등 을 무작위로 생성하지 않는 id 의 간격 문제를 해결 합니다 (트리거 등을 사용하여 기사 참조). 1부터 시작하여 연속적인 숫자로 채워진 다른 열을 테이블에 추가하여 문제를 해결하고 있습니다 ( 편집 : 이 열은 런타임시 하위 쿼리에 의해 생성 된 임시 테이블에 추가되며 영구 테이블에는 영향을 미치지 않습니다).
DROP TEMPORARY TABLE IF EXISTS rands;
CREATE TEMPORARY TABLE rands ( rand_id INT );
loop_me: LOOP
IF cnt < 1 THEN
LEAVE loop_me;
END IF;
SET @no_gaps_id := 0;
INSERT INTO rands
SELECT r1.id
FROM (SELECT id, @no_gaps_id := @no_gaps_id + 1 AS no_gaps_id FROM random) AS r1 JOIN
(SELECT (RAND() *
(SELECT COUNT(*)
FROM random)) AS id)
AS r2
WHERE r1.no_gaps_id >= r2.id
ORDER BY r1.no_gaps_id ASC
LIMIT 1;
SET cnt = cnt - 1;
END LOOP loop_me;
이 기사에서는 코드를 최적화하기 위해 많은 시간을 보냈습니다. 변경 사항이 성능에 영향을 미치지 만 나에게 매우 잘 작동한다면 아이디어가 없습니다.
@no_gaps_id
어떤 인덱스를 사용할 수 있습니다 당신이 보면, 그래서 EXPLAIN
당신의 쿼리에 대한, 당신은 Using filesort
하고 Using where
원래의 질의에 대비, 하위 쿼리에 대한 (인덱스 제외).
여기 많은 사람들에게 도움이 될 수있는 게임 체인저가 있습니다.
200k 개의 행이있는 테이블이 있고 순차 ID가 N 개의 임의의 행 을 선택해야 하므로 테이블에서 가장 큰 ID를 기반으로 임의의 값을 생성하도록 선택하면이 스크립트가 가장 빠른 작업인지 확인합니다.
logTime();
query("SELECT COUNT(id) FROM tbl");
logTime();
query("SELECT MAX(id) FROM tbl");
logTime();
query("SELECT id FROM tbl ORDER BY id DESC LIMIT 1");
logTime();
결과는 다음과 같습니다.
36.8418693542479
ms0.241041183472
ms0.216960906982
ms이 결과를 바탕으로 order desc는 최대 id를 얻는 가장 빠른 작업입니다.
다음은 질문에 대한 답변입니다.
SELECT GROUP_CONCAT(n SEPARATOR ',') g FROM (
SELECT FLOOR(RAND() * (
SELECT id FROM tbl ORDER BY id DESC LIMIT 1
)) n FROM tbl LIMIT 10) a
...
SELECT * FROM tbl WHERE id IN ($result);
참고하십시오 200K 테이블에서 10 개 임의의 행을 얻으려면, 그것은 나에게 1.78했다 MS (PHP는 측면에서 모든 작업을 포함하여)
LIMIT
약간 늘리는 것이 좋습니다. 복제본을 얻을 수 있습니다.
이것은 매우 빠르며 간격이 있어도 100 % 무작위입니다.
x
사용 가능한 행 수 를 계산하십시오.SELECT COUNT(*) as rows FROM TABLE
a_1,a_2,...,a_10
0과 0 사이의 10 개의 고유 난수를 선택하십시오.x
SELECT * FROM TABLE LIMIT 1 offset a_i
for i = 1, ..., 10나는이 책이 해킹 발견 SQL 안티 패턴 에서 빌 Karwin을 .
SELECT column FROM table ORDER BY RAND() LIMIT 10
O (nlog (n))에 있는 O (1)에 있습니다. 예, 이것은 빠른 해결책이며 모든 ID 배포에 작동합니다.
x
. 나는 이것이 10 행의 무작위 생성이 아니라고 주장합니다. 내 대답에 따르면 3 단계에서 10 번 쿼리를 실행해야합니다. 즉, 하나는 실행 당 하나의 행만 가져오고 오프셋이 테이블의 끝에 있는지 걱정할 필요가 없습니다.
@redsio의 대답을 임시 테이블과 결합하십시오 (600K는 그다지 크지 않습니다).
DROP TEMPORARY TABLE IF EXISTS tmp_randorder;
CREATE TABLE tmp_randorder (id int(11) not null auto_increment primary key, data_id int(11));
INSERT INTO tmp_randorder (data_id) select id from datatable;
그런 다음 @redsios Answer 버전을 가져옵니다.
SELECT dt.*
FROM
(SELECT (RAND() *
(SELECT MAX(id)
FROM tmp_randorder)) AS id)
AS rnd
INNER JOIN tmp_randorder rndo on rndo.id between rnd.id - 10 and rnd.id + 10
INNER JOIN datatable AS dt on dt.id = rndo.data_id
ORDER BY abs(rndo.id - rnd.id)
LIMIT 1;
테이블이 크면 첫 번째 부분을 체질 할 수 있습니다.
INSERT INTO tmp_randorder (data_id) select id from datatable where rand() < 0.01;
버전 : 테이블을 tmp_randorder
지속적으로 유지하고 이를 datatable_idlist라고 부를 수 있습니다. 구멍이 생길 수 있으므로 특정 간격 (일, 시간)으로 해당 테이블을 다시 작성하십시오. 테이블이 정말 커지면 구멍을 리필 할 수도 있습니다
datatable_idlist에서 l.data_id를 전체로 선택합니다. l dt.id = l.data_id에서 왼쪽 조인 datatable dt를 선택합니다.
버전 : 데이터 세트에 직접 또는 영구적 인 추가 테이블에 임의의 sort_sortorder 열을 데이터 세트에 제공하십시오 datatable_sortorder
. 해당 열을 색인화하십시오. 응용 프로그램에서 임의의 값을 생성하십시오 (이하라고 부릅니다 $rand
).
select l.*
from datatable l
order by abs(random_sortorder - $rand) desc
limit 1;
이 솔루션은 '가장자리 행'을 가장 높고 가장 낮은 random_sortorder로 구분하므로 간격 (하루에 한 번)으로 다시 정렬하십시오.
또 다른 간단한 솔루션은 행의 순위를 매기고 그중 하나를 임의로 가져 오는 것입니다.이 솔루션을 사용하면 테이블에 'Id'기반 열이 필요하지 않습니다.
SELECT d.* FROM (
SELECT t.*, @rownum := @rownum + 1 AS rank
FROM mytable AS t,
(SELECT @rownum := 0) AS r,
(SELECT @cnt := (SELECT RAND() * (SELECT COUNT(*) FROM mytable))) AS n
) d WHERE rank >= @cnt LIMIT 10;
원하는만큼 행에 액세스해야하는 경우에 따라 한계 값을 변경할 수 있지만 대부분 연속적인 값입니다.
그러나 연속적인 임의의 값을 원하지 않으면 더 큰 샘플을 가져 와서 임의로 선택할 수 있습니다. 같은 ...
SELECT * FROM (
SELECT d.* FROM (
SELECT c.*, @rownum := @rownum + 1 AS rank
FROM buildbrain.`commits` AS c,
(SELECT @rownum := 0) AS r,
(SELECT @cnt := (SELECT RAND() * (SELECT COUNT(*) FROM buildbrain.`commits`))) AS rnd
) d
WHERE rank >= @cnt LIMIT 10000
) t ORDER BY RAND() LIMIT 10;
자동 생성 된 ID가있는 경우 꽤 좋은 방법은 모듈로 연산자 '%'를 사용하는 것입니다. 예를 들어, 70,000 개 중 10,000 개의 임의 레코드가 필요한 경우 7 개 행 중 1 개가 필요하다고 말하면이를 단순화 할 수 있습니다. 이 쿼리에서이를 단순화 할 수 있습니다.
SELECT * FROM
table
WHERE
id %
FLOOR(
(SELECT count(1) FROM table)
/ 10000
) = 0;
대상 행을 사용 가능한 총계로 나눈 결과가 정수가 아닌 경우 요청한 것보다 몇 개의 추가 행이 있으므로 결과 집합을 다음과 같이 정리하는 데 도움이되도록 LIMIT 절을 추가해야합니다.
SELECT * FROM
table
WHERE
id %
FLOOR(
(SELECT count(1) FROM table)
/ 10000
) = 0
LIMIT 10000;
이것은 전체 스캔을 필요로하지만 ORDER BY RAND보다 빠르며 내 의견으로는이 스레드에서 언급 된 다른 옵션보다 이해하기가 더 간단합니다. 또한 DB에 쓰는 시스템이 배치로 행 세트를 작성하는 경우 예상 한대로 임의의 결과를 얻지 못할 수 있습니다.
하나의 임의의 레코드를 원할 경우 (ID 사이에 간격이 있는지 여부에 관계없이) :
PREPARE stmt FROM 'SELECT * FROM `table_name` LIMIT 1 OFFSET ?';
SET @count = (SELECT
FLOOR(RAND() * COUNT(*))
FROM `table_name`);
EXECUTE stmt USING @count;
나는 모든 대답을 살펴 보았지만 아무도이 가능성에 대해 언급하지 않았으며 그 이유를 모르겠습니다.
약간의 비용으로 최대한의 단순성과 속도를 원한다면 DB의 각 행에 대해 난수를 저장하는 것이 합리적입니다. 추가 열을 만들고 random_number
기본값을로 설정하십시오 RAND()
. 이 열에 색인을 작성하십시오.
그런 다음 행을 검색 할 때 코드에서 임의의 숫자 (PHP, Perl 등)를 생성하고 열과 비교하십시오.
SELECT FROM tbl WHERE random_number >= :random LIMIT 1
하나의 행에 대해 매우 깔끔하지만 OP와 같은 10 개의 행에 대해 10 개의 별도 시간을 호출해야한다고 요청했습니다 (또는 즉시 나를 탈출하는 영리한 조정을해야합니다)
다음은 빠르고 편견이 없으며 id 열과 독립적이어야합니다. 그러나 리턴 된 행 수가 요청 된 행 수와 일치한다고 보장하지는 않습니다.
SELECT *
FROM t
WHERE RAND() < (SELECT 10 / COUNT(*) FROM t)
설명 : 100 개 중 10 개의 행을 원한다고 가정하면 각 행은에 의해 달성 될 수있는 SELECTed를 얻을 확률이 1/10 WHERE RAND() < 0.1
입니다. 이 방법은 10 개의 행을 보장하지 않습니다. 그러나 쿼리가 충분한 횟수로 실행되면 실행 당 평균 행 수는 약 10이되고 테이블의 각 행은 균등하게 선택됩니다.
PREPARE stm from 'select * from table limit 10 offset ?';
SET @total = (select count(*) from table);
SET @_offset = FLOOR(RAND() * @total);
EXECUTE stm using @_offset;
where 절을 적용 할 수도 있습니다.
PREPARE stm from 'select * from table where available=true limit 10 offset ?';
SET @total = (select count(*) from table where available=true);
SET @_offset = FLOOR(RAND() * @total);
EXECUTE stm using @_offset;
600,000 행 (700MB) 테이블 쿼리 실행시 ~ 0.016 초 HDD 드라이브에서
테스트 --EDIT--
오프셋은 테이블의 끝 부분에 가까운 값을 가져 와서 select 문이 적은 행을 반환합니다. 이것을 피하기 위해 offset
선언 후 다시 확인할 수 있습니다.
SET @rows_count = 10;
PREPARE stm from "select * from table where available=true limit ? offset ?";
SET @total = (select count(*) from table where available=true);
SET @_offset = FLOOR(RAND() * @total);
SET @_offset = (SELECT IF(@total-@_offset<@rows_count,@_offset-@rows_count,@_offset));
SET @_offset = (SELECT IF(@_offset<0,0,@_offset));
EXECUTE stm using @rows_count,@_offset;
이 쿼리를 사용합니다.
select floor(RAND() * (SELECT MAX(key) FROM table)) from table limit 10
쿼리 시간 : 0.016s
이것이 최선의 방법이라고 생각합니다 ..
SELECT id, id * RAND( ) AS random_no, first_name, last_name
FROM user
ORDER BY random_no