2011-01-12 4 views
0

다음 스크립트를 복사 해 붙여 넣으십시오.하위 쿼리 만들기 쿼리가 느림

DECLARE @MainTable TABLE(MainTablePkId int) 
INSERT INTO @MainTable SELECT 1 
INSERT INTO @MainTable SELECT 2 

DECLARE @SomeTable TABLE(SomeIdPk int, MainTablePkId int, ViewedTime1 datetime) 
INSERT INTO @SomeTable SELECT 1, 1, DATEADD(dd, -10, getdate()) 
INSERT INTO @SomeTable SELECT 2, 1, DATEADD(dd, -9, getdate()) 
INSERT INTO @SomeTable SELECT 3, 2, DATEADD(dd, -6, getdate()) 

DECLARE @SomeTableDetail TABLE(DetailIdPk int, SomeIdPk int, Viewed INT, ViewedTimeDetail datetime) 
INSERT INTO @SomeTableDetail SELECT 1, 1, 1, DATEADD(dd, -7, getdate()) 
INSERT INTO @SomeTableDetail SELECT 2, 2, NULL, DATEADD(dd, -6, getdate()) 
INSERT INTO @SomeTableDetail SELECT 3, 2, 2, DATEADD(dd, -8, getdate()) 
INSERT INTO @SomeTableDetail SELECT 4, 3, 1, DATEADD(dd, -6, getdate()) 

SELECT m.MainTablePkId, 
     (SELECT COUNT(Viewed) FROM @SomeTableDetail), 
     (SELECT TOP 1 s2.ViewedTimeDetail FROM @SomeTableDetail s2 
               INNER JOIN @SomeTable s1 ON s2.SomeIdPk = s1.SomeIdPk 
               WHERE s1.MainTablePkId = m.MainTablePkId) 
FROM @MainTable m 

이 스크립트는 예제 일뿐입니다. 서브 쿼리에서 열의 길이가 긴 목록이 SELECT이고 약 12 ​​개 이상의 열이 있습니다. 내 From 절에는 약 8 개의 테이블이 있습니다.

전체 레코드를 가져 오려면 21 초가 걸리고 하위 쿼리를 제거하면 4 초가 걸립니다.

'데이터베이스 엔진 튜닝 관리자'를 사용하여 쿼리를 최적화하고 새로운 권장 인덱스 및 통계를 추가하려고했지만 이러한 변경으로 인해 쿼리 시간이 훨씬 나 빠졌다.

참고 :이 테스트 데이터는 내 질문에 설명하는 것입니다 언급 한 것처럼

실제 데이터 테이블의 많은 열을 조인하지만 미세 하위 쿼리 결과 우리를하지 않고있다.

도움 주시면 감사하겠습니다.

+0

SELECT COUNT (보기)부터 @SomeTableDetail이 @SomeTable 테이블의 ID와 연결되어야합니까? – Lamak

+0

'TOP 1'을'ORDER BY '하지 않고 임의의 행을 얻을 수 있음을 의미합니다. 또한,'COUNT()'부질의는 @MainTable과 상호 관련이 있는가? –

+0

두 번째 하위 쿼리에서 ORDER BY없이 TOP를 사용하고 있습니다. 어떤 ViewedTimeDetail이 정말로 반환되기를 원합니까? 가장 일찍? 최신? –

답변

2

다음은 CTE의 예입니다. 원하는 것은 아니지만 정확하게 시작할 수 있습니다.

WITH _CountViewed AS 
(
    SELECT COUNT(Viewed) AS Viewed FROM @SomeTableDetail 
), 
_SomeDate AS 
(
    SELECT MAX(s2.ViewedTimeDetail) As ChangeTime, s1.MainTablePkId FROM @SomeTableDetail s2 
               INNER JOIN @SomeTable s1 ON s2.SomeIdPk = s1.SomeIdPk 
               GROUP BY s1.MainTablePkId 
) 
SELECT sd.MainTablePkId, cv.Viewed, sd.ChangeTime FROM _SomeDate sd 
    OUTER APPLY _CountViewed cv 
+0

감사합니다 .Erin, 알겠습니다. – Kashif

2

상관 관계가있는 서브 쿼리는 row-by-agoniziong-row를 실행합니다. 본질적으로 proc에는 많은 커서가 있습니다. 이들을 조인으로 변경하십시오 (또는 파생 테이블 또는 CTE에 조인). 성능 표준의 상관 하위 쿼리를 사용하는 것은 바람직하지 않습니다. 조인, CTE 또는 파생 테이블 조인으로 항상 대체 할 수 있습니다.

+0

감사합니다. @HLGEM. 내가 이것을 조인으로 어떻게 바꿀 수 있는지 생각해 봤지만 CTE의 예를 들어 주시겠습니까? Common Table Expression에 대해 알고 있지만이 상황에서 CTE를 사용하는 방법을 알 수 없습니다. 당신의 도움을 주셔서 감사합니다. – Kashif

+2

이 매우 당신이 거기에 있었다 일을하지 않습니다하지만 좋은 선발 exampleWITH _CountViewed해야 (@SomeTableDetail 에서 볼 때 본 \t SELECT COUNT()), _SomeDate AS ( \t SELECT MAX (AS S2 ChangeTime, @SomeTableDetail S2 INNER FROM s1.MainTablePkId로서 .ViewedTimeDetail) 가입 @SomeTable S1 = ON s2.SomeIdPk s1.SomeIdPk s1.MainTablePkId ) SELECT sd.MainTablePkId, cv.Viewed, _SomeDate FROM sd.ChangeTime BY GROUP sd \t OUTER APPLY _CountViewed cv – Erin

0

줄을 조금만 읽고 빈 곳을 채우려 고 노력하고 있지만 이것이 달성하려는 목표에 더 가깝다고 생각합니다. 그들이 공식적으로 PK로 선언하지 않는 경우

SELECT m.MainTablePkId, SUM(std.Viewed), MAX(std.ViewedTimeDetail) 
    FROM @MainTable m 
     INNER JOIN @SomeTable st 
      ON m.MainTablePkId = st.MainTablePkId 
     INNER JOIN @SomeTableDetail std 
      ON st.SomeIdPk = std.SomeIdPk 
    GROUP BY m.MainTablePkId 
0

나는 s1.MainTablePkId 및 m.MainTablePkId, s2.SomeIdPk 및 s1.SomeIdPk에 인덱스를 만들 것입니다. (이미 SQL Server에 의해 인덱싱 됨)

(잠금 해제)를 추가하여 비 잠금 읽기를 수행 할 수 있으며, 테이블을 잠그지 않아도 속도가 향상됩니다.

SELECT m.MainTablePkId, 
     (SELECT COUNT(Viewed) FROM @SomeTableDetail (nolock)), 
     (SELECT TOP 1 s2.ViewedTimeDetail FROM @SomeTableDetail s2 (nolock) 
               INNER JOIN @SomeTable s1 (nolock) ON s2.SomeIdPk = s1.SomeIdPk 
               WHERE s1.MainTablePkId = m.MainTablePkId) 
FROM @MainTable m (nolock)