2013-07-04 5 views
3

나는 이것이 일반적인 질문이며 몇 가지 다른 게시물과 논문을 읽었으나 색인 된 필드와 두 쿼리가 반환 할 수있는 레코드의 볼륨을 고려하지 못했습니다.중첩 된 선택의 성능

제 질문은 간단합니다. 다음 두 가지 중 성능에있어서 SQL과 유사한 구문으로 작성된 것이 좋습니다.

첫 번째 쿼리 :

Select * 
from someTable s 
where s.someTable_id in 
        (Select someTable_id 
        from otherTable o 
        where o.indexedField = 123) 

두 번째 쿼리

Select * 
from someTable 
where someTable_id in 
        (Select someTable_id 
        from otherTable o 
        where o.someIndexedField = s.someIndexedField 
        and o.anotherIndexedField = 123) 

나의 이해 번째 쿼리는 첫 번째 쿼리 평가 곳에 외부 쿼리가 반환하는 모든 튜플에 대한 데이터베이스를 조회하는 것입니다 내부를 먼저 선택하고 필터를 외부 쿼리에 적용하십시오.

이제 두 번째 쿼리는 someIndexedField 필드가 인덱싱되지만 수천 또는 수백만 개의 레코드가 있다고 가정 할 때 초고속 쿼리를 사용하여 데이터베이스를 쿼리 할 수 ​​있습니다.

참고 : Oracle 데이터베이스. 첫 번째 쿼리에 대해

+1

. . 일반적으로 데이터베이스를 지정하지 않은 성능 문제는 의미가 없습니다. SQL은 절차 언어가 아닌 설명 적 언어이므로 옵티 마이저 (엔진의 일부)는 주어진 쿼리에 가장 적합한 쿼리 계획을 자유롭게 선택할 수 있습니다. –

+0

@GordonLinoff 좋은 지적. 데이터베이스는 Oracle 데이터베이스입니다. 언어는 정말로 SQL과 같은 문법으로 작성했다고 생각하면 안됩니다. – mixkat

+1

. . 톰 카이트에 따르면, 오라클 최적화 http://asktom.oracle.com/pls/apex/f?p=100:11:0::NO (상관 하위 쿼리를 인식하고 적절한 조인로 바꿀 수 똑똑 :: P11_QUESTION_ID : 3167884300346662300). 오라클은 매우 좋은 최적화 도구를 가지고 있습니다. 흥미로운 점은 첫 번째 버전이 MySQL에서 완전히 끔찍한 성능을 가지고 있다는 것입니다. . . 문제를 수정 한 버전 5.6까지. –

답변

2

:

첫 번째 쿼리는 내부 선택 첫째을 평가 한 후 외부 쿼리에 필터를 적용합니다.

그렇게 간단하지 않습니다.

SQL에서는 대부분 먼저 실행될 내용과 나중에 실행될 내용을 알 수 없습니다.

SQL - 선언적 언어입니다.

"중첩 된 선택 물"은 시각적으로 만 기술적 인 것이 아닙니다.

예 1 - "someTable"에는 "otherTable"- 10000 개의 행이 있습니다.

대부분의 경우 데이터베이스 최적화 프로그램은 먼저 "someTable"을 읽고 otherTable에 일치하는지 확인합니다. 그것을 위해, 또는 상황에 따라 색인을 사용하지 않을 수도 있습니다, 그 경우에 필자는 "indexedField"색인을 사용할 것입니다.

예 2 - "someTable"에는 "otherTable"- 10 행의 10000 개의 행이 있습니다.

대부분의 경우 데이터베이스 최적화 프로그램은 메모리의 "otherTable"에서 모든 행을 읽고이를 123으로 필터링하며 someTable PK (someTable_id) 색인에서 일치하는 것을 찾을 것입니다. 결과적으로 "otherTable"에서 색인이 사용되지 않습니다. 두 번째 질의에 대해

:

처음부터 그것은 완전히 다른. 그래서 나는 그것들을 비교하는 방법을 모른다 :

  • 첫 번째 쿼리는 한 쌍씩 두개의 테이블을 연결한다 : s.someTable_id = o.s.someTable_id = o.someTable_id 및 o.someIndexedField = s.someIndexedField : 두 쌍의
  • 두 번째 쿼리 링크 두 테이블을 someTable_id.

첫 번째 쿼리는 두 테이블을 연결하는 일반적인 방법입니다. 그러나 o.someTable_id에 대한 색인을 생성해야합니다.

그래서 일반적인 규칙은 다음과 같습니다 모든 PK

    • - 색인해야한다가 (그들은 기본적으로 색인) (WHERE 부분에 사용 등) 필터링
    • 모든 컬럼 인덱스해야
    • 테이블 간의 일치를 제공하는 데 사용되는 모든 열 (IN, JOIN 등 포함) - 또한 필터링되므로 인덱싱해야합니다.
    • 는 DB 엔진 자체 최고 주문 작업 (또는 병렬)을 선택합니다. 대부분의 경우이를 확인할 수 없습니다.
    • 사용 오라클은 실제 데이터에 다른 쿼리의 실행 계획을 비교하는 계획을 (비슷한 대부분의 DB에 존재)에 대해 설명합니다.
  • 4

    중첩 된 선택 항목이 같은 테이블에있는 경우 쿼리 실행 시간이 지옥 일 수 있습니다.

    의 MySQL의 성능을 향상하는 좋은 방법은 중첩 된 선택을위한 임시 테이블을 만들고이 테이블에 대해 주요 선택을 적용합니다. 예를 들어

    : 나는 많은 양의 데이터에 대한 성능에 대한 확실하지 않다

    create temporary table 'temp_table' as (
        Select someTable_id 
        from someTable s2 
        where s2.Field = 123 
    ); 
    
    Select * 
    from someTable s1 
    where s1.someTable_id in 
            (Select someTable_id 
            from tempTable s2); 
    

    :

    Select * 
    from someTable s1 
    where s1.someTable_id in 
            (Select someTable_id 
            from someTable s2 
            where s2.Field = 123); 
    

    가와 더 나은 성능을 가질 수 있습니다.