2017-03-20 1 views
1

큰 테이블 (두 개의 열을 선택하면 3m + 행, 결과 집합은 약 6-7m)에서 두 개의 열을 선택하는 쿼리를 실행하고 목록을 반환해야합니다. 그래서 저는 열을 목록에 병합하고 중복을 제거하기 위해 연합을 사용했습니다. 문제는 하나의 쿼리에서 결과를 반환 할 수 없다는 것입니다. 따라서이를 분할해야하므로 응용 프로그램 계층이 Prepared Statements를 통해 설정하는 하위 쿼리에 LIMIT ?,?을 적용했습니다.합집합 전에 중복을 제거하십시오.

SELECT val 
FROM 
(
    (SELECT fs.smr as val 
    FROM `fr_search` as fs 
    ORDER BY val LIMIT ?,?) 

    UNION 

    (SELECT fs.dmr as val 
    FROM `fr_search` as fs 
    ORDER BY val LIMIT ?,?) 
) as vals 
GROUP BY val 

문제 : 노동 조합은 중복을 제거하지만 LIMIT를 적용한 후에 만 ​​적용됩니다. 의미 두 개의 쿼리가 100 + 100 = 200 행을 반환하고 그 중 대부분이 복제본 인 경우 < 개의 200 행만 반환합니다. 이러한 쿼리에 제한을 적용하여 특정 양의 행을 반환 할 수있는 방법은 무엇입니까? (필자는 서브 쿼리 후 LIMIT를 적용하는 경우, 그것은 실행하는 데 2 ​​분 이상 걸릴 것입니다, 그래서 그것은 문제가 해결되지 않습니다.)

+0

'SELECT DISTINCT ... ' – Psi

+0

@Psi'DISTINCT '를 사용하면 무엇을 얻을 수 있습니까? 'union all' 대신에'Union'을 사용할 때와 마찬가지로, 문제는 지속됩니다. – appl3r

+0

왜 GROUP BY가 있습니까? –

답변

2

실제로이 작업에 하위 쿼리가 필요하지 않습니다. 첫 번째 100 개의 행에 대해 다음을 수행 할 수 있습니다.

(SELECT DISTINCT fs.smr as val 
    FROM `fr_search` as fs 
    ORDER BY val 
    LIMIT 100 
) 
UNION 
(SELECT DISTINCT fs.dmr as val 
    FROM `fr_search` as fs 
    ORDER BY val 
    LIMIT 100 
) 
ORDER BY val 
LIMIT 100; 

그러나 오프셋을 넣기 시작하면 더 복잡해집니다. 다음 100 행의 경우 :

(SELECT DISTINCT fs.smr as val 
    FROM `fr_search` as fs 
    ORDER BY val 
    LIMIT 200 
) 
UNION 
(SELECT DISTINCT fs.dmr as val 
    FROM `fr_search` as fs 
    ORDER BY val 
    LIMIT 200 
) 
ORDER BY val 
LIMIT 100, 100; 

두 번째 세트의 출처를 모를 경우 문제가 발생합니다.

실제로 결과 세트를 페이지해야하는 경우 임시 테이블에 임시 테이블을 저장하고 임시 테이블에서 페이지를 저장하는 것이 좋습니다.

+0

이것을 해결하기 위해 임시 테이블을 사용했습니다. 실행 중 오버 헤드가 거의없고 안정적이고 빠른 쿼리를 제공합니다. – appl3r

0

당신은 두 가지 옵션이 있습니다

을 할 수 있습니다 내부 및 외부에서 SELECT DISTINCT 쿼리 :

SELECT DISTINCT val 
FROM 
(
    (SELECT DISTINCT fs.smr as val 
    FROM `fr_search` as fs) 

    UNION ALL 

    (SELECT DISTINCT fs.dmr as val 
    FROM `fr_search` as fs) 
) as vals 
ORDER BY val LIMIT ?,?; 

또는 내부 쿼리를 그룹화 한 다음 외부 쿼리로 그룹화 할 수도 있습니다.

SELECT val 
FROM 
(
    (SELECT fs.smr as val 
    FROM `fr_search` as fs 
    GROUP BY fs.smr) 

    UNION ALL 

    (SELECT fs.dmr as val 
    FROM `fr_search` as fs 
    GROUP BY fs.dmr) 
) as vals 
GROUP BY val 
ORDER BY val LIMIT ?,?; 

이 두 시나리오는 본 시나리오에서 본질적으로 동일한 작업을 수행합니다. 그러나 두 가지 모두에서 공용체를 모두 사용해야하므로 UNION 부분이 독자적으로 작업을 수행하지 않으며 레코드 그룹화 방법에 대해 명시 적으로 설명합니다. 또한 제한 절을 외부 쿼리로 이동합니다.

+0

하위 쿼리에서 DISTINCT 또는 GROUP BY를 사용하는 것처럼 보이지만 하위 쿼리를 실행하는 것과 같은 시간이 걸립니다 제한없이 사용하고 나중에 적용합니다. – appl3r

+0

고유 한 값을 원하기 때문에 쿼리가 전체 테이블 스캔을 수행 할 것입니다. 나는 당신이 이것을 최적화 할 수있는 방법이 있는지 의심 스럽다. 질문의 목적은 올바른 결과를 얻는 방법 이었습니까? 아니면 쿼리를 더 빨리 만드는 방법 이었습니까? –

+0

둘 다, 각 호출마다 분이 걸리는 쿼리를 사용할 수 없습니다. 나는 이것을 위해 임시 테이블을 조사 할 필요가있다. – appl3r

1

쿼리 최적화에는 항상 솔루션의 두 부분이 있습니다. 그리고 때때로 시도, 측정 및 비교의 반복적 인 과정입니다.

  1. 엔진이 효율적으로 실행할 수있는 좋은 (그리고 정확한) 쿼리를 작성하십시오.
  2. 옵티마이 저가 올바른 실행 계획을 선택할 수 있도록 적절한 인덱스가 사용 가능한지 확인하십시오.

    가 효율적으로 실행하기 위해
    SELECT v.val 
    FROM (
         SELECT fs.smr as val 
         FROM `fr_search` as fs 
         UNION 
         SELECT fs.dmr as val 
         FROM `fr_search` as fs 
         ) as v 
    ORDER BY v.val LIMIT ?,?; 
    

    , 당신은이 인덱스를 할 것입니다 :

    • 하나에 fr_search.smr

가장 좋은 쿼리는 가장 가능성이 - 정직하고 간단합니다

  • 기타 fr_search.dmr

  • 옵티마이 저가 위를 처리 할 수없는 경우 인덱스 힌트를 사용하여 인덱스를 사용하도록하십시오.

     
    Page 1: 100, 100, 100, 0 
    Page 2: 200, 200, 100, 100 
    Page 3: 300, 300, 100, 200 
    Page 4: 400, 400, 100, 300 
    etc. 
    

    이유는 : 당신이 다음과 같이 문제를 강제로 시도 할 수 극단적 인 핀치에서

    : 다음과 같이 대체가 (100 페이지 가정)

    SELECT v.val 
    FROM (
         SELECT DISTINCT fs.smr as val 
         FROM `fr_search` as fs 
         ORDER BY fs.smr LIMIT ? 
         UNION 
         SELECT DISTINCT fs.dmr as val 
         FROM `fr_search` as fs 
         ORDER BY fs.dmr LIMIT ? 
         ) as v 
    ORDER BY v.val LIMIT ?,?; 
    

    참고해야한다 두 테이블 중 하나를 선호하는 교차 열 정렬의 가능한 불균형을 해결해야합니다. 예를 들어 4 페이지 :

    • 각 열의 키로 정렬 된 상위 400 개의 별개 행을 가져옵니다.
    • 병합 된 데이터의 301부터 400 행을 반환합니다.
    • 이것은 서브 쿼리 중 하나의 마지막 400 행일 수 있습니다. 하지만 150 행 표시 위의 각 하위 쿼리에서 약 50 개의 행을 반환 할 가능성이 큽니다.
    +0

    두 색인은 모두 이미 설정되어 있지만 표의 크기는 1,2GB입니다. – appl3r

    +0

    엄청난 수의 중복이 없으면 옵티마이 저는 _ 적절한 _ 인덱스로 이것을 처리 할 수 ​​있어야합니다. 그러나 많은 페이지를 탐색 한 후에는 어려울 수 있습니다. –

    +0

    @ appl3r 인덱스가 사용되는 경우 테이블의 크기는 중요하지 않습니다. 나는 오라클을 가지고 있지 않지만 SQL Server에서 : 500 만 개의 행을 가진 테이블에 대한 위 쿼리는 0 ms CPU 시간과 1 ms 경과 시간으로 처음 100 개의 행을 반환합니다. 실행 계획은 각 인덱스에 대해 50 개가 넘는 행을 선택하여 첫 번째 100의 최종 출력에 병합합니다. –

    관련 문제