programing

mysql의 큰 테이블에서 랜덤 행의 빠른 선택

luckcodes 2023. 1. 21. 10:15

mysql의 큰 테이블에서 랜덤 행의 빠른 선택

큰 mysql 테이블에서 랜덤 행을 빠르게 선택하는 방법은 무엇입니까?

저는 php로 작업하고 있습니다만, 다른 언어로 되어 있어도 어떤 솔루션에도 관심이 있습니다.

모든 ID를 가져와서 임의의 ID를 선택한 다음 전체 행을 가져옵니다.

ID가 구멍 없이 순차적이라는 것을 알고 있으면 최대값을 잡고 무작위로 ID를 계산할 수 있습니다.

곳곳에 구멍이 있지만 대부분 순차적인 값이 있고 약간 왜곡된 랜덤성에는 관심이 없는 경우 최대값을 잡고 id를 계산한 다음 id 이상의 id를 사용하여 첫 번째 행을 선택합니다.스큐잉의 이유는 id의 후속 홀이 다른 id의 후속 홀보다 선택될 확률이 높기 때문입니다.

무작위로 주문하면 끔찍한 테이블 스캔이 일어날 것이고, 이러한 솔루션에는 퀵이라는 단어가 적용되지 않습니다.

그렇게 하지 마세요.또한 GUID로 주문하면 같은 문제가 있습니다.

한 번의 질문으로 빠르게 할 수 있는 방법이 있어야 한다는 것을 알고 있었습니다.여기 있습니다.

외부 코드를 사용하지 않고 고속으로 할 수 있습니다.

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의 경우:랜덤 기능: 아티클이 있는 테이블에는 랜덤 번호( 아티클 작성 시 생성됨)가 있는 추가 열이 있습니다.랜덤 문서를 가져오려면 난수를 생성하고 다음으로 큰 값 또는 작은 값(어떤 문서를 기억하지 않음)이 있는 문서를 난수 열에 가져옵니다.인덱스를 사용하면 매우 빠를 수 있습니다(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

쿼리만 사용하고 rand()의 순서를 지정하지 않고 랜덤 행을 생성하는 다른 방법도 있습니다.여기에는 사용자 정의 변수가 포함됩니다.표에서 랜덤 행을 생성하는 방법 보기

테이블에서 랜덤 행을 찾으려면 ORDER BY RAND()를 사용하지 마십시오. MySQL은 전체 파일 정렬을 수행하고 필요한 제한 행 번호를 가져옵니다.이 완전한 파일 정렬을 피하려면 where 구에서만 RAND() 함수를 사용하십시오.필요한 행 수에 도달하면 바로 정지합니다.http://www.rndblog.com/how-to-select-random-rows-in-mysql/ 를 참조해 주세요.

이 표의 행을 삭제하지 않는 경우 가장 효율적인 방법은 다음과 같습니다.

(mininum id를 알고 있는 경우 생략)

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 a.* from random_data a, (select max(id)*rand() randid  from random_data) b
     where a.id >= b.randid limit 1;

여기, 아이디, 연속적일 필요 없어임의의 프라이머리 키/일치/자동 증분 컬럼이 될 수 있습니다.큰 MySQL 테이블에서 임의의 행을 선택하는 가장 빠른 방법은 다음과 같습니다.

감사합니다 질루르 - www.techinfobest.com

주어진 표에서 여러 행을 랜덤으로 선택하기 위해('단어'라고 말함) 우리 팀은 다음과 같은 장점을 생각해냈습니다.

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

기존의 "SELECT id FROM table ORDER BY RAND() LIMIT 1"은 정상입니다.

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

LIMIT row_count를 ORDER BY와 함께 사용하는 경우 MySQL은 결과 전체를 정렬하지 않고 정렬된 결과의 첫 번째 row_count 행을 찾는 즉시 정렬을 종료합니다.

주문하면 전체 스캔 테이블을 수행합니다.select count)를 실행하고 나중에 0에서 마지막 레지스트리 사이의 랜덤 rownum을 얻는 것이 가장 좋습니다.

간단하지만 느린 방법은 다음과 같습니다(작은 테이블에 적합합니다).

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키입니다.

Jan Kneschke의 링크나 SO의 답변을 봐주세요.이 두 사람 모두 같은 질문을 하고 있습니다.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

이것은 테이블에 구멍이 있는 문제를 해결하지 못한다.

하지만 여기에 라스섹스 제안에 대한 반전이 있습니다.

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()100만 행이 있는 큰 테이블에서는 얼마나 느려질까요?

나는 내 아이디가 연속되지 않는 문제에 부딪혔다.내가 이걸 생각해 낸 것.

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

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

WHERE 절을 하나 더 추가할 경우 조금 더 흥미로워집니다.할인 상품을 검색한다고 칩시다.

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

당신이 해야 할 일은 당신이 충분한 결과를 반환하고 있는지 확인하는 것입니다. 그래서 저는 100으로 설정했습니다.서브쿼리에 WHERE 디스카운트 <.2 절이 10배 느렸기 때문에 더 많은 결과와 제한을 반환하는 것이 좋습니다.

다음 쿼리를 사용하여 임의 행을 가져옵니다.

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)

더럽고 빠른 방법:

이 용도로만 테이블을 별도로 보관하십시오.또한 원래 테이블에 삽입할 때마다 이 테이블에 동일한 행을 삽입해야 합니다.전제 조건:DELETE는 없습니다.

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);

DELETE가 허용되면

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;

언급URL : https://stackoverflow.com/questions/211329/quick-selection-of-a-random-row-from-a-large-table-in-mysql