복붙노트

[SQL] MySQL은 : ORDER BY RAND 대안 ()

SQL

MySQL은 : ORDER BY RAND 대안 ()

나는 몇 RAND BY의 MySQL의 ORDER 대안 () 함수에 대해 읽었습니다,하지만 대안의 대부분은 단일 무작위 결과를 필요한 곳에 적용됩니다.

사람이 어떻게 쿼리를 최적화하는 어떤 생각을 가지고 있는가하는 이와 같은 반환 여러 무작위 결과 :

   SELECT u.id, 
          p.photo 
     FROM users u, profiles p 
    WHERE p.memberid = u.id 
      AND p.photo != '' 
      AND (u.ownership=1 OR u.stamp=1) 
 ORDER BY RAND() 
    LIMIT 18 

해결법

  1. ==============================

    1.이 솔루션은 인덱스 컬럼을 사용하여 가장 잘 작동합니다.

    이 솔루션은 인덱스 컬럼을 사용하여 가장 잘 작동합니다.

    여기에 10 개 로우로 표시된 간단한 예 최적화 된 질의 벤치이다.

    최적화 된 :이 300ms

    SELECT 
        g.*
    FROM
        table g
            JOIN
        (SELECT 
            id
        FROM
            table
        WHERE
            RAND() < (SELECT 
                    ((4 / COUNT(*)) * 10)
                FROM
                    table)
        ORDER BY RAND()
        LIMIT 4) AS z ON z.id= g.id
    

    제한 액수에 대한 참고 사항 : 제한 4 4 / 수 (*). 4S는 같은 수 있어야합니다. 많은 당신의 반환이 그만큼 속도에 영향을주지 않는 방법 변경. 제한 4 1000 한계 기준은 동일하다. 제한 만은 600ms의로 채택했다

    에 대한 가입주의 : 단지 ID를 무작위 화하는 것은 빠른 전체 행을 무작위보다. 이 메모리에 전체 행을 복사므로 다음을 랜덤. 는 tablescans을 방지하기 위해 하위 쿼리 그것과 연결되는 모든 테이블이 될 수 있습니다 가입 할 수 있습니다.

    참고 where 절 : 무작위되는 결과의 양을 아래로 한계를 계산하는 곳. 이 결과의 비율을 소요하고 전체 테이블이 아니라 그들을 정렬합니다.

    참고 하위 쿼리 다음 일을 조인 및 추가 조항 조건이 서브 쿼리와 subsubquery에 그들 모두를 배치해야합니다. 정확한 계산을 다시 올바른 데이터를 당깁니다.

    최적화되지 않은 : 1200ms

    SELECT 
        g.*
    FROM
        table g
    ORDER BY RAND()
    LIMIT 4
    

    4 배 빠른 순서와 랜드에 의해 (). 이 솔루션은 인덱스 열이있는 테이블로 작업 할 수 있습니다.

    CONS

    그것은 복잡한 쿼리와 조금 복잡하다. 하위 쿼리에서이 개 코드베이스를 유지하기 위해 필요

  2. ==============================

    2.여기에 대안이다,하지만 여전히 RAND ()를 사용하여 기반으로합니다 :

    여기에 대안이다,하지만 여전히 RAND ()를 사용하여 기반으로합니다 :

      SELECT u.id, 
             p.photo,
             ROUND(RAND() * x.m_id) 'rand_ind'
        FROM users u, 
             profiles p,
             (SELECT MAX(t.id) 'm_id'
                FROM USERS t) x
       WHERE p.memberid = u.id 
         AND p.photo != '' 
         AND (u.ownership=1 OR u.stamp=1) 
    ORDER BY rand_ind
       LIMIT 18
    

    이것은 약간 더 복잡하지만 임의 INT 값의 더 나은 분포를 가지고 :

      SELECT u.id, 
             p.photo,
             FLOOR(1 + RAND() * x.m_id) 'rand_ind'
        FROM users u, 
             profiles p,
             (SELECT MAX(t.id) - 1 'm_id'
                FROM USERS t) x
       WHERE p.memberid = u.id 
         AND p.photo != '' 
         AND (u.ownership=1 OR u.stamp=1) 
    ORDER BY rand_ind
       LIMIT 18
    
  3. ==============================

    3.그것은 RAND () 방법으로 가장 빠르게,하지만 빠르게 다음 일반적인 ORDER되지 않습니다 :

    그것은 RAND () 방법으로 가장 빠르게,하지만 빠르게 다음 일반적인 ORDER되지 않습니다 :

    당신은 인덱스 열을 찾기 위해 그것을 사용하는 경우 ORDER BY RAND ()는 느린 없습니다. 이 같은 하나 개의 쿼리에서 모든 ID를 수행 할 수 있습니다

    SELECT id
    FROM testTable
    ORDER BY RAND();
    

    임의 ID의 시퀀스를 얻고, 다른 SELECT 또는 매개 변수를 다른 쿼리에 결과에 가입 :

    SELECT t.*
    FROM testTable t
    JOIN
        (SELECT id
        FROM `testTable`
        ORDER BY RAND()) AS z ON z.id= t.id   
    WHERE t.isVisible = 1
    LIMIT 100; 
    

    귀하의 경우에는 다음과 같습니다

    SELECT u.id, p.photo 
    FROM users u, profiles p 
    JOIN
        (SELECT id
        FROM users
        ORDER BY RAND()) AS z ON z.id = u.id   
    WHERE p.memberid = u.id 
      AND p.photo != '' 
      AND (u.ownership=1 OR u.stamp=1) 
    LIMIT 18 
    

    아주 무딘 방법 그리고 그것은 매우 큰 테이블하지 적절한 될 수 있지만, 여전히 더 빨리 일반 RAND 이상 ()입니다. 나는 20 배 빠른 속도로 거의 400000 3000 개 임의의 행을 검색 실행 시간을 얻었다.

  4. ==============================

    4.나는이 오늘로 달려 조인과 함께 'DISTINCT'사용하려고했지만, RAND는 각 가입 행 구별하기 때문에 나는 가정 중복을 얻고 있었다. 내가 조금 주위 뒤죽박죽하고 해결책을 발견,이 같은 작품 :

    나는이 오늘로 달려 조인과 함께 'DISTINCT'사용하려고했지만, RAND는 각 가입 행 구별하기 때문에 나는 가정 중복을 얻고 있었다. 내가 조금 주위 뒤죽박죽하고 해결책을 발견,이 같은 작품 :

    SELECT DISTINCT t.id, 
                    t.photo 
           FROM (SELECT  u.id, 
                         p.photo,
                         RAND() as rand
                    FROM users u, profiles p 
                     WHERE p.memberid = u.id 
                      AND p.photo != '' 
                      AND (u.ownership=1 OR u.stamp=1)
                    ORDER BY rand) t
           LIMIT 18
    
  5. ==============================

    5.열을 생성하거나 열 랜덤 (실시 예 PHP 용 생성) 번호 순서와 선택에 참여.

    열을 생성하거나 열 랜덤 (실시 예 PHP 용 생성) 번호 순서와 선택에 참여.

  6. ==============================

    6.랜드에 의해 주문 (), 큰 테이블에 매우 느립니다

    랜드에 의해 주문 (), 큰 테이블에 매우 느립니다

    나는 PHP 스크립트에서 다음 해결 방법을 찾을 수 :

    Select min(id) as min, max(id) as max from table;
    

    그리고 PHP에서 무작위로 할

    $rand = rand($min, $max);
    

    그때

    'Select * from table where id>'.$rand.' limit 1';
    

    매우 빠른 것 같다 ....

  7. ==============================

    7.내가 사용하고이 솔루션은 아래 링크에 게시됩니다 : 내가 어떻게 MySQL을의 ORDER BY RAND () 함수를 최적화 할 수 있습니다?

    내가 사용하고이 솔루션은 아래 링크에 게시됩니다 : 내가 어떻게 MySQL을의 ORDER BY RAND () 함수를 최적화 할 수 있습니다?

    난 안 후 1 기수 1의 경우 사용자 테이블, 당신의 프로파일 테이블보다 크게 될 것입니다 가정입니다.

    그렇다면, 내가 먼저 프로파일 테이블에 가입하기 전에 사용자 테이블에 임의의 선택을 할 것입니다.

    첫 번째 선택을 할 :

    SELECT *
    FROM users
    WHERE users.ownership = 1 OR users.stamp = 1
    

    그런 다음이 풀에서, 계산 가능성을 통해 임의의 행을 선택하십시오. 테이블은 M 행을 가지고 있으며, 당신이 N 임의의 행을 선택하려는 경우, 무작위 선택의 확률은 N / M해야합니다. 그 후:

    SELECT *
    FROM
    (
        SELECT *
        FROM users
        WHERE users.ownership = 1 OR users.stamp = 1
    ) as U
    WHERE 
        rand() <= $limitCount / (SELECT count(*) FROM users WHERE users.ownership = 1 OR users.stamp = 1)
    

    N은 $ limitCount이고 M은 테이블의 행 수를 계산 부질된다. 우리가 확률에 노력하고 있습니다 때문에, 반환 된 행의 $ limitCount 미만을 가질 수 있습니다. 따라서 우리는 무작위로 풀 크기를 증가시키는 요인에 의해 N을 곱해야한다.

    즉 :

    SELECT*
    FROM
    (
        SELECT *
        FROM users
        WHERE users.ownership = 1 OR users.stamp = 1
    ) as U
    WHERE 
        rand() <= $limitCount * $factor / (SELECT count(*) FROM users WHERE users.ownership = 1 OR users.stamp = 1)
    

    더 무작위 풀 크기 (예 : 1.5) 감소에 나는 보통 세트 $ 인자 = 2. 당신은 낮은 값으로 요소를 설정할 수 있습니다.

    이 시점에서, 우리는 이미 약 2N 크기 아래로 M 사이즈 테이블을 제한한다. 여기에서 우리는 다음 LIMIT 가입 할 수 있습니다.

    SELECT * 
    FROM
    (
           SELECT *
            FROM
            (
                SELECT *
                FROM users
                WHERE users.ownership = 1 OR users.stamp = 1
            ) as U
            WHERE 
                rand() <= $limitCount * $factor / (SELECT count(*) FROM users WHERE users.ownership = 1 OR users.stamp = 1)
    ) as randUser
    JOIN profiles
    ON randUser.id = profiles.memberid AND profiles.photo != ''
    LIMIT $limitCount
    

    큰 테이블에서이 쿼리는 RAND ()의 요청에 의한 정상적인 주문을 능가 할 것이다.

    도움이 되었기를 바랍니다!

  8. from https://stackoverflow.com/questions/1823306/mysql-alternatives-to-order-by-rand by cc-by-sa and MIT license