2012-10-03 2 views
5

잘못 사용하면 하위 쿼리가 성능에 악영향을 준다는 것을 알고 있습니다. 사용자가 필터링 된 레코드 집합을 테이블에서 검색해야하는 매우 특정한 시나리오가 있습니다. 다양한 필터를 사용할 수 있으며 구성을 지원해야합니다. 또한 새로운 필터는 개발자 그룹에 의해 정기적으로 만들어집니다.FROM 절의 SQL 하위 쿼리

총체적인 매개 변수가있는 단일 성장 SQL 쿼리에 대한 아이디어가 마음에 들지 않습니다. 나는 똑같은 SELECT 문과 다양한 WHERE 절을 가진 자율적 인 SQL 쿼리에 대한 아이디어를 좋아하지 않는다. 동적 SQL 쿼리에 대한 아이디어가 마음에 들지만 어떤 구조를 사용해야하는지 잘 모르겠습니다.

  1. "내부 조인"(내가 부족 것을 더가있는 경우, 다음을 제안 주시기 바랍니다) : 나는 4 기본 옵션을 생각할 수 INNER를 통해 필터를 연결하여 결과를 필터링하기 위해 결합합니다.
  2. "FROM subqueries": FROM 문에서 하위 쿼리를 통해 필터를 스택합니다.
  3. "WHERE subqueries": WHERE 절의 하위 쿼리를 통해 필터를 연결합니다.
  4. "INNER JOIN 하위 쿼리": wierd 하이브리드.

내가 보여 (및 프로필)하는 SQL 바이올린을 만든 그들 :

http://sqlfiddle.com/#!3/4e17b/9

아래 내가 '무엇의 아이디어를 제공하기 위해 바이올린에서 발췌 한 것입니다 m에 대해 말하기 :

------------------------------------------------------------------------ 
--THIS IS AN EXCERPT FROM THE SQL FIDDLE -- IT IS NOT MEANT TO COMPILE-- 
------------------------------------------------------------------------ 

-- 
--"INNER JOIN" test 
     SELECT COUNT(*) 
     FROM 
      @TestTable Test0 
      INNER JOIN @TestTable Test1 ON Test1.ID=Test0.ID AND Test1.ID % @i = 0 
      INNER JOIN @TestTable Test2 ON Test2.ID=Test0.ID AND Test2.ID % @j = 0 
      INNER JOIN @TestTable Test3 ON Test3.ID=Test0.ID AND Test3.ID % @k = 0 

-- 
--"FROM subqueries" test 
     SELECT COUNT(*) FROM (
      SELECT * FROM (
        SELECT * FROM (
         SELECT * FROM @TestTable Test3 WHERE Test3.ID % @k = 0 
       ) Test2 WHERE Test2.ID % @j = 0 
      ) Test1 WHERE Test1.ID % @i = 0 
    ) Test0 

-- 
--"WHERE subqueries" test 
     SELECT COUNT(*) 
     FROM @TestTable Test0 
     WHERE 
      Test0.ID IN (SELECT ID FROM @TestTable Test1 WHERE Test1.ID % @i = 0) 
      AND Test0.ID IN (SELECT ID FROM @TestTable Test2 WHERE Test2.ID % @j = 0) 
      AND Test0.ID IN (SELECT ID FROM @TestTable Test3 WHERE Test3.ID % @k = 0) 

-- 
--"INNER JOIN subqueries" test 
    SELECT COUNT(*) 
    FROM 
     TestTable Test0 
     INNER JOIN (SELECT ID FROM TestTable WHERE ID % @i = 0) Test1 ON Test1.ID=Test0.ID 
     INNER JOIN (SELECT ID FROM TestTable WHERE ID % @j = 0) Test2 ON Test2.ID=Test0.ID 
     INNER JOIN (SELECT ID FROM TestTable WHERE ID % @k = 0) Test3 ON Test3.ID=Test0.ID 

-- 
--"EXISTS subqueries" test 
    SELECT COUNT(*) 
    FROM TestTable Test0 
    WHERE 
     EXISTS (SELECT 1 FROM TestTable Test1 WHERE Test1.ID = Test0.ID AND Test1.ID % @i = 0) 
     AND EXISTS (SELECT 1 FROM TestTable Test2 WHERE Test2.ID = Test0.ID AND Test2.ID % @j = 0) 
     AND EXISTS (SELECT 1 FROM TestTable Test3 WHERE Test3.ID = Test0.ID AND Test3.ID % @k = 0) 

순위 (테스트 실행 시간)

01 23,516,

SQL 바이올린 :

|INNER JOIN|FROM SUBQUERIES|WHERE SUBQUERIES|INNER JOIN SUBQUERIES|EXISTS SUBQUERIES| 
------------------------------------------------------------------------------------- 
|  5174 |   777 |   7240 |    5478 |   7359 | 

지역 환경 : (아무 캐시 : 모든 테스트 전에 취소 버퍼)

|INNER JOIN|FROM SUBQUERIES|WHERE SUBQUERIES|INNER JOIN SUBQUERIES|EXISTS SUBQUERIES| 
------------------------------------------------------------------------------------- 
|  3281 |   2851 |   2964 |    3148 |   3071 | 

로컬 환경 (캐시 : 실행 쿼리를 두 번 연속과하면을 기록 두 번째 실행 시간)

|INNER JOIN|FROM SUBQUERIES|WHERE SUBQUERIES|INNER JOIN SUBQUERIES|EXISTS SUBQUERIES| 
------------------------------------------------------------------------------------- 
|  284 |   50 |   3334 |     278 |    408 | 

각 솔루션마다 장점/단점이 있습니다. WHERE 절의 하위 쿼리는 꽤 심각한 성능을 보입니다. FROM 절의 하위 쿼리는 성능이 뛰어납니다 (실제로는 일반적으로 최상의 성능을 나타냄) (참고 :이 방법이 인덱스의 이점을 무효화 할 것이라고 생각합니다). INNER JOIN은 하위 쿼리와 달리 동일한 상황 (테이블 별칭의 충돌을 피하기 위해 중간 시스템이 있어야 함)에서 작동하기 때문에 몇 가지 흥미로운 범위 지정 문제를 도입하지만 꽤 좋은 성능을 제공합니다.

전반적으로 가장 깨끗한 솔루션은 FROM 절에서 하위 쿼리라고 생각합니다. 필터는 (INNER JOIN과 달리 문맥/기본 쿼리를 제공 할 필요가 없기 때문에) 작성하고 테스트하기 쉽습니다.

생각하십니까? 서브 쿼리 또는 재난이 발생하기를 기다리는 유효한 사용법입니까?

UPDATE (2012년 10월 4일) : 방법을

  • 추가 성능 SQL 바이올린에서 테스트 및 지역 환경을 "EXISTS"에 대한 테스트를 포함하는 SQL 바이올린 업데이트

  • 답변

    0

    하는 경우 당신은 언제나 "and 논리를 적용 할 것입니다. 내부 조인은 아마도 좋은 접근법 일 것입니다. (저는 일반화하고 있습니다 만, 테이블 크기와 인덱스 등 많은 요인에 따라 달라질 것입니다). "and"또는 "or"필터링을 적용하려면 다른 솔루션 중 하나를 사용해야합니다. 은 "EXISTS"방법에 대한

    SELECT COUNT(*) 
         FROM @TestTable Test0 
         WHERE 
          EXISTS (SELECT 1 FROM @TestTable Test1 WHERE Test0.ID = Test1.ID AND Test1.ID % @i = 0) 
          EXISTS (SELECT 1 FROM @TestTable Test2 WHERE Test0.ID = Test2.ID AND Test2.ID % @j = 0) 
          EXISTS (SELECT 1 FROM @TestTable Test3 WHERE Test0.ID = Test3.ID AND Test3.ID % @k = 0) 
    
    +0

    추가 시험 :

    또한, 사용 성능을 테스트해야하는 조항이 존재한다. "SELECT *"와 "SELECT 1"(확실히 통제 된 테스트는 아니지만 확실한 변형이 있음) 사이의 차이점을 보았지만 놀랍게도 팩의 끝 부분에 위치합니다. 일반적인 방법론은 다양한 테이블에 적용되므로 크기와 인덱스를 미리 예측하기가 어렵습니다. 나는 기본적으로 "가장 친절한 샌드 박스"를 찾고 있습니다. – makerplays