문제

큰 MySQL 테이블에서 임의의 행을 선택하는 빠른 방법은 무엇입니까?

PHP에서 일하고 있지만 다른 언어에 있더라도 모든 솔루션에 관심이 있습니다.

도움이 되었습니까?

해결책

모든 ID를 모두 잡고 임의의 ID를 선택하고 전체 행을 검색하십시오.

ID가 구멍없이 순차적이라는 것을 알고 있다면 최대를 잡고 임의의 ID를 계산할 수 있습니다.

여기저기서 구멍이 있지만 대부분 순차적 값이 있고 약간 비뚤어진 임의성에 신경 쓰지 않는 경우 최대 값을 잡고 ID를 계산 한 다음 계산 된 것과 같은 ID로 첫 번째 행을 선택하십시오. 왜곡의 이유는 ID가 그러한 구멍을 따르는 것이 다른 ID를 따르는 것보다 더 높은 기회를 가지기 때문입니다.

무작위로 주문하면 손에 끔찍한 테이블 스캔이있을 것입니다. 빠른 그러한 솔루션에는 적용되지 않습니다.

그렇게하지 말고 안내서로 주문해서는 안됩니다. 같은 문제가 있습니다.

다른 팁

나는 단일 쿼리로 빠른 방법으로 할 수있는 방법이 있어야한다는 것을 알았습니다. 그리고 여기에 있습니다 :

외부 코드가 관여하지 않고 빠른 방법, Kudos는

http://jan.kneschke.de/projects/mysql/order-by-rand/

SELECT name
  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;

MediaWiki는 흥미로운 트릭을 사용합니다 (Wikipedia의 Special : Random Feature) : 기사가있는 테이블에는 임의의 숫자가있는 추가 열이 있습니다 (기사가 생성 될 때 생성). 임의의 기사를 얻으려면 임의의 숫자를 생성하고 임의의 숫자 열에서 다음으로 크거나 작은 다음 기사를 가져옵니다. 색인을 사용하면 매우 빠를 수 있습니다. (및 MediaWiki는 PHP로 작성되었으며 MySQL을 위해 개발되었습니다.)

결과 숫자가 잘못 분포 된 경우이 접근법은 문제를 일으킬 수 있습니다. IIRC, 이것은 MediaWiki에서 고정되었으므로 이런 식으로 결정하면 코드를 살펴보고 현재 수행 방법을 확인해야합니다 (아마도 임의의 숫자 열을 주기적으로 재생성 할 수 있음).

다음은 상당히 빠르게 실행되는 솔루션이 있으며 ID 값이 인접하거나 1에서 시작하지 않고도 더 나은 임의의 분포를 얻습니다.

SET @r := (SELECT ROUND(RAND() * (SELECT COUNT(*) FROM mytable)));
SET @sql := CONCAT('SELECT * FROM mytable LIMIT ', @r, ', 1');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

어쩌면 당신은 다음과 같은 일을 할 수 있습니다.

SELECT * FROM table 
  WHERE id=
    (FLOOR(RAND() * 
           (SELECT COUNT(*) FROM table)
          )
    );

이것은 ID 번호가 모두 차이가없는 순차적이라고 가정합니다.

각 행에 계산 된 임의 값이 포함 된 열을 추가하고 주문 조항에 사용하여 선택시 하나의 결과로 제한하십시오. 이것은 테이블 스캔보다 빠르게 작동합니다. ORDER BY RANDOM() 원인.

업데이트: 발급하기 전에 여전히 임의의 값을 계산해야합니다. SELECT 물론 검색시 성명서, 예를 들어

SELECT * FROM `foo` WHERE `foo_rand` >= {some random value} LIMIT 1

쉽지만 느린 방법은 (작은 테이블에 적합)입니다.

SELECT * from TABLE order by RAND() LIMIT 1

의사 코드 :

sql "select id from table"
store result in list
n = random(size of list)
sql "select * from table where id=" + list[n]

이것은 그것을 가정합니다 id 고유 한 (1 차) 키입니다.

query 만 사용하고 Rand ()의 순서없이 임의 행을 생성하는 또 다른 방법이 있습니다. 사용자 정의 변수가 포함됩니다. 보다 테이블에서 임의 행을 생성하는 방법

테이블에서 임의 행을 찾으려면 MySQL이 전체 파일 정렬을 수행하고 필요한 제한 행 번호를 검색하기 때문에 Rand ()의 순서를 사용하지 마십시오. 이 전체 파일 정렬을 피하려면 rand () 함수를 WHERE 절에서만 사용하십시오. 필요한 행에 도달하자마자 멈출 것입니다. 보다http://www.rndblog.com/how-to-selct-random-rows-in-mysql/

이 테이블에서 행을 삭제하지 않으면 가장 효율적인 방법은 다음과 같습니다.

(미니 늄 이드를 알고 있다면 그냥 건너 뛰십시오)

SELECT MIN(id) AS minId, MAX(id) AS maxId FROM table WHERE 1

$randId=mt_rand((int)$row['minId'], (int)$row['maxId']);

SELECT id,name,... FROM table WHERE id=$randId LIMIT 1

주어진 테이블 ( '단어')에서 여러 개의 임의 행을 선택하기 위해 우리 팀은이 아름다움을 생각해 냈습니다.

SELECT * FROM
`words` AS r1 JOIN 
(SELECT  MAX(`WordID`) as wid_c FROM `words`) as tmp1
WHERE r1.WordID >= (SELECT (RAND() * tmp1.wid_c) AS id) LIMIT n

고전적인 "Rand () Limit 1"의 테이블 주문에서 선택한 ID 선택은 실제로 괜찮습니다.

MySQL 매뉴얼에서 발췌 한 다음 발췌문을 참조하십시오.

Order와 함께 Limit Row_Count를 사용하면 MySQL은 전체 결과를 정렬하지 않고 정렬 된 결과의 첫 번째 Row_Count 행을 발견하자마자 정렬을 종료합니다.

주문과 함께 YO는 전체 스캔 테이블을 수행합니다. 선택 카운트 (*)를 수행하고 나중에 0과 마지막 레지스트리 사이에 임의의 행 = rownum을 얻는 경우 최고입니다.

보세요 이 링크 Jan Kneschke 또는 이렇게 대답합니다 둘 다 같은 질문에 대해 논의 할 때. SO 답변은 다양한 옵션을 다루며 필요에 따라 좋은 제안이 있습니다. Jan은 각각의 다양한 옵션과 각각의 성능 특성을 극복합니다. 그는 MySQL 선택 내 에서이 작업을 수행 할 수있는 가장 최적화 된 방법으로 다음으로 끝납니다.

SELECT name
  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;

HTH,

-디핀

나는 SQL에 약간 새로운 것이지만 PHP에서 무작위 숫자를 생성하고 사용하는 것은 어떻습니까?

SELECT * FROM the_table WHERE primary_key >= $randNr

이것은 테이블의 구멍에 문제를 해결하지 못합니다.

그러나 여기 Lassevks 제안에 대한 비틀기가 있습니다.

SELECT primary_key FROM the_table

php에서 mysql_num_rows () 사용 위의 결과를 기반으로 임의의 숫자를 만듭니다.

SELECT * FROM the_table WHERE primary_key = rand_number

부수적으로 얼마나 느린 지 SELECT * FROM the_table:
그에 따라 임의의 숫자를 만듭니다 mysql_num_rows() 그런 다음 데이터 포인터를 해당 지점으로 이동합니다 mysql_data_seek(). 백만 행이있는 큰 테이블에 얼마나 느리게 이루어질까요?

나는 내 ID가 순차적이지 않은 문제에 부딪쳤다. 내가 이것을 생각해 낸 것.

SELECT * FROM products WHERE RAND()<=(5/(SELECT COUNT(*) FROM products)) LIMIT 1

반환 된 행은 약 5이지만 1로 제한합니다.

위치가 다른 곳을 추가하고 싶다면 조금 더 흥미로워집니다. 할인 된 제품을 검색하고 싶다고 가정 해 봅시다.

SELECT * FROM products WHERE RAND()<=(100/(SELECT COUNT(*) FROM pt_products)) AND discount<.2 LIMIT 1

당신이해야 할 일은 충분한 결과를 반환하는 것인지 확인하는 것입니다. 그래서 내가 100으로 설정 한 이유입니다. 서브 쿼리의 할인 <.2 절은 10 배 느려서 더 많은 결과를 반환하고 제한하는 것이 좋습니다.

여기에 많은 해결책이 있습니다. 하나 또는 둘은 괜찮아 보이지만 다른 솔루션에는 약간의 제약이 있습니다. 그러나 다음 솔루션은 모든 상황에서 작동합니다

select a.* from random_data a, (select max(id)*rand() randid  from random_data) b
     where a.id >= b.randid limit 1;

여기, ID, 순차적 일 필요는 없습니다. 기본 키/고유/자동 증분 열일 수 있습니다. 다음을 참조하십시오 큰 MySQL 테이블에서 임의 행을 선택하는 가장 빠른 방법

감사합니다 Zillur- www.techinfobest.com

아래 쿼리를 사용하여 임의의 행을 얻으십시오

SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails 
GROUP BY usr_fk_id 
ORDER BY cnt ASC  
LIMIT 1

제 경우에는 내 테이블에 ID가 기본 키로 ID가 있고 차이가없는 자동 증가에있어서 사용할 수 있습니다. COUNT(*) 또는 MAX(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 ms
  • 맥스 : 0.241041183472 ms
  • 주문하다: 0.216960906982 ms

주문 방법으로 답변 :

SELECT FLOOR(RAND() * (
    SELECT id FROM tbl ORDER BY id DESC LIMIT 1
)) n FROM tbl LIMIT 1

...
SELECT * FROM tbl WHERE id = $result;

나는 이것을 사용했고 작업은 여기

SELECT * FROM myTable WHERE RAND()<(SELECT ((30/COUNT(*))*10) FROM myTable) ORDER BY RAND() LIMIT 30;

이 작업을 수행 할 수있는 기능을 만들 가능성이 가장 높고 가장 빠른 답변이 여기에서 가장 빠른 답변을 작성하십시오!

프로 - 틈과 매우 빠르게 작동합니다.

<?

$sqlConnect = mysqli_connect('localhost','username','password','database');

function rando($data,$find,$max = '0'){
   global $sqlConnect; // Set as mysqli connection variable, fetches variable outside of function set as GLOBAL
   if($data == 's1'){
     $query = mysqli_query($sqlConnect, "SELECT * FROM `yourtable` ORDER BY `id` DESC LIMIT {$find},1");

     $fetched_data = mysqli_fetch_assoc($query);
      if(mysqli_num_rows($fetched_data>0){
       return $fetch_$data;
      }else{
       rando('','',$max); // Start Over the results returned nothing
      }
   }else{
     if($max != '0'){
        $irand = rand(0,$max); 
        rando('s1',$irand,$max); // Start rando with new random ID to fetch
     }else{

        $query = mysqli_query($sqlConnect, "SELECT `id` FROM `yourtable` ORDER BY `id` DESC LIMIT 0,1");
        $fetched_data = mysqli_fetch_assoc($query);
        $max = $fetched_data['id'];
        $irand = rand(1,$max);
        rando('s1',$irand,$max); // Runs rando against the random ID we have selected if data exist will return
     }
   }
 }

 $your_data = rando(); // Returns listing data for a random entry as a ASSOC ARRAY
?>

이 코드는 테스트되지 않았지만 간격으로도 임의의 항목을 반환하는 작업 개념입니다. 간격이로드 시간 문제를 일으킬 정도로 충분히 크지 않은 한.

빠르고 더러운 방법 :

SET @COUNTER=SELECT COUNT(*) FROM your_table;

SELECT PrimaryKey
FROM your_table
LIMIT 1 OFFSET (RAND() * @COUNTER);

첫 번째 쿼리의 복잡성은 MyISAM 테이블의 O (1)입니다.

두 번째 쿼리는 표 전체 스캔과 함께 제공됩니다. 복잡성 = O (n)

더럽고 빠른 방법 :

이 목적을 위해 별도의 테이블을 보관하십시오. 원래 테이블에 삽입 할 때 마다이 테이블에 동일한 행을 삽입해야합니다. 가정 : 삭제 없음.

CREATE TABLE Aux(
  MyPK INT AUTO_INCREMENT,
  PrimaryKey INT
);

SET @MaxPK = (SELECT MAX(MyPK) FROM Aux);
SET @RandPK = CAST(RANDOM() * @MaxPK, INT)
SET @PrimaryKey = (SELECT PrimaryKey FROM Aux WHERE MyPK = @RandPK);

삭제가 허용되는 경우

SET @delta = CAST(@RandPK/10, INT);

SET @PrimaryKey = (SELECT PrimaryKey
                   FROM Aux
                   WHERE MyPK BETWEEN @RandPK - @delta AND @RandPK + @delta
                   LIMIT 1);

전반적인 복잡성은 O (1)입니다.

SELECT DISTINCT * FROM yourTable WHERE 4 = 4 LIMIT 1;

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top