백만 레코드가 포함 된 데이터베이스에서 첫 번째 'n'레코드를 선택하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1410048

문제

백만 레코드로 채워진 Oracle 데이터베이스가 있습니다. 특정 조건에 따라 데이터베이스에서 첫 번째 'N "정렬 레코드 (100 레코드)를 반환하는 SQL 쿼리를 작성하려고합니다.

SELECT * 
FROM myTable 
Where SIZE > 2000 
ORDER BY NAME DESC

그런 다음 프로그래밍 방식으로 첫 번째 N 레코드를 선택하십시오.

이 접근법의 문제는 다음과 같습니다.

  • 쿼리는 6 백만 개의 레코드로 결과를 초래하고 "이름으로 주문"은 모든 레코드가 내림차순으로 이름으로 정렬됩니다. 이 분류는 많은 시간이 걸리고 있습니다. (거의 30-40 초. 주문을 생략하면 1 초 밖에 걸리지 않습니다).
  • 종류 후에 나는 첫 번째 N (100) 레코드에만 관심이 있습니다. 따라서 완전한 레코드의 정렬은 유용하지 않습니다.

내 질문은 다음과 같습니다.

  1. 쿼리 자체에 'n'을 지정할 수 있습니까? (따라서 정렬은 N 레코드에만 적용되며 쿼리가 더 빨라집니다).
  2. SQL에서 쿼리를 개선하여 N 요소 만 정렬하고 빠른 시간에 반환하는 더 나은 방법.
도움이 되었습니까?

해결책

당신의 목적이 100 행을 찾아서 나중에 분류하는 것이라면 Lasse의 해결책 맞다. 다른 사람을 버리는 동안 처음 100 행을 이름으로 정렬하고 싶다고 생각하면 다음과 같은 쿼리를 작성할 것입니다.

SELECT * 
  FROM (SELECT * 
          FROM myTable 
         WHERE SIZE > 2000 ORDER BY NAME DESC) 
 WHERE ROWNUM <= 100

Optimizer는 Top-N 쿼리이며 이름에 인덱스를 사용할 수 있음을 이해합니다. 전체 결과 세트를 정렬 할 필요는 없으며 인덱스의 끝에서 시작하여 뒤로 읽고 100 행 후에 중지됩니다.

또한 원래 쿼리에 힌트를 추가하여 Optimizer가 첫 행에만 관심이 있다는 것을 이해하도록 할 수 있습니다. 이것은 아마도 유사한 액세스 경로를 생성 할 것입니다.

SELECT /*+ FIRST_ROWS*/* FROM myTable WHERE SIZE > 2000 ORDER BY NAME DESC

편집하다: 그냥 추가 AND rownum <= 100 Oracle Rownum에서는 쿼리가 작동하지 않습니다. ~ 전에 정렬 : 이것이 하위 쿼리를 사용해야하는 이유입니다. 서브 쿼리가 없으면 Oracle은 100 개의 임의 행을 선택한 다음 정렬합니다.

다른 팁

이것 Oracle 버전에 따라 상단 N 행을 선택하는 방법을 보여줍니다.

Oracle 9i에서 랭크 () 및 dense_rank () 함수를 사용하여 상단 N 행을 결정할 수 있습니다. 예 :

급여를 기준으로 상위 10 명의 직원을 확보하십시오

ename, sal (select ename, sal, rank () over (sal desc by sal desc) sal_rank)에서 sal_rank <= 10;

상위 10 개 급여를 만드는 직원을 선택하십시오

ename, sal (select ename, sal, dense_rank () over (sal desc by sal desc) sal_dense_rank에서 emp)를 선택하십시오. 여기서 sal_dense_rank <= 10;

둘 사이의 차이점이 설명됩니다 여기

이거 추가 해봐:

 AND rownum <= 100

당신의 where-clase에.

그러나 이것은 당신이 요구하는 일을하지 않을 것입니다.

100 개의 임의 행을 선택하고 정렬 한 다음 반환하려면 먼저 순서없이 쿼리를 공식화 한 다음 100 행으로 제한 한 다음 그 중에서 선택하고 정렬해야합니다.

이것 ~할 수 있었다 작업이지만 불행히도 테스트 할 수있는 Oracle 서버가 없습니다.

SELECT *
FROM (
    SELECT *
    FROM myTable
    WHERE SIZE > 2000
      AND rownum <= 100
    ) x
ORDER BY NAME DESC

그러나 "무작위"부분에 주목하십시오. 당신은 "크기> 2000으로 100 줄을 줘, 나는 어떤 100을 신경 쓰지 않는다"고 말합니다.

정말 당신이 원하는 것입니까?

그리고 아니요, 서버를 쿼리 할 때마다 변경 될 때마다 변경 될 것이라는 점에서 실제로 무작위 결과를 얻지 못하지만 쿼리 최적화기의 자비에 있습니다. 해당 테이블의 데이터로드 및 인덱스 통계가 시간이 지남에 따라 변경되면 어느 시점에서 이전 쿼리에서 수행 한 것과 다른 데이터를 얻을 수 있습니다.

문제는 쿼리가 실행될 때마다 정렬이 수행된다는 것입니다. 인덱스를 사용하여 정렬 작업을 제거 할 수 있습니다. 최적화는 정렬 된 열이 NULL로 선언 된 경우 인덱스를 사용하여 정렬 작업을 제거 할 수 있습니다.

(열이 무효화 할 수있는 경우 (a) 쿼리에 null 술어를 추가하거나 (b) 함수 기반 색인을 추가하고 그에 따라 순서별로 수정함으로써 가능합니다.

참조를 위해 Oracle 12C 에서이 작업을 사용하여 수행 할 수 있습니다. FETCH 절. 너는 볼 수있어 여기 이 문제에 관한 예와 추가 참조 링크.

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