백만 레코드가 포함 된 데이터베이스에서 첫 번째 'n'레코드를 선택하는 방법은 무엇입니까?
-
05-07-2019 - |
문제
백만 레코드로 채워진 Oracle 데이터베이스가 있습니다. 특정 조건에 따라 데이터베이스에서 첫 번째 'N "정렬 레코드 (100 레코드)를 반환하는 SQL 쿼리를 작성하려고합니다.
SELECT *
FROM myTable
Where SIZE > 2000
ORDER BY NAME DESC
그런 다음 프로그래밍 방식으로 첫 번째 N 레코드를 선택하십시오.
이 접근법의 문제는 다음과 같습니다.
- 쿼리는 6 백만 개의 레코드로 결과를 초래하고 "이름으로 주문"은 모든 레코드가 내림차순으로 이름으로 정렬됩니다. 이 분류는 많은 시간이 걸리고 있습니다. (거의 30-40 초. 주문을 생략하면 1 초 밖에 걸리지 않습니다).
- 종류 후에 나는 첫 번째 N (100) 레코드에만 관심이 있습니다. 따라서 완전한 레코드의 정렬은 유용하지 않습니다.
내 질문은 다음과 같습니다.
- 쿼리 자체에 'n'을 지정할 수 있습니까? (따라서 정렬은 N 레코드에만 적용되며 쿼리가 더 빨라집니다).
- 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
절. 너는 볼 수있어 여기 이 문제에 관한 예와 추가 참조 링크.