2010-05-12 3 views
2

몇 백만 개의 행 테이블에 심각한 성능 문제가있어 상당히 빠른 결과를 얻을 수 있어야합니다. 여기에 내가 무엇을의 아래로 실행이야, 나는 그것을 쿼리있어 방법, 그리고 복용 기간 :수백만 행 테이블에서 집계 함수 수행

  • 내가 SQL 서버 2008 표준을하고 있는데, 파티션은 현재 옵션

  • 되지 않도록

    지난 30 일 동안 특정 계정의 모든 인벤토리에 대한 모든보기를 집계하려고합니다.

  • 모든 뷰는 다음 표에 저장됩니다

 
CREATE TABLE [dbo].[LogInvSearches_Daily](
    [ID] [bigint] IDENTITY(1,1) NOT NULL, 
    [Inv_ID] [int] NOT NULL, 
    [Site_ID] [int] NOT NULL, 
    [LogCount] [int] NOT NULL, 
    [LogDay] [smalldatetime] NOT NULL, 
CONSTRAINT [PK_LogInvSearches_Daily] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY] 
) ON [PRIMARY] 
  • 이 테이블은 132,000,000 기록을 가지고 있으며, 4 기가 이상이다.

  • 테이블에서 10 행의 샘플 :

 
ID     Inv_ID  Site_ID  LogCount LogDay 
-------------------- ----------- ----------- ----------- ----------------------- 
1     486752  48   14   2009-07-21 00:00:00 
2     119314  51   16   2009-07-21 00:00:00 
3     313678  48   25   2009-07-21 00:00:00 
4     298863  0   1   2009-07-21 00:00:00 
5     119996  0   2   2009-07-21 00:00:00 
6     463777  534   7   2009-07-21 00:00:00 
7     339976  503   2   2009-07-21 00:00:00 
8     333501  570   4   2009-07-21 00:00:00 
9     453955  0   12   2009-07-21 00:00:00 
10     443291  0   4   2009-07-21 00:00:00 

(10 row(s) affected) 
  • 내가 LogInvSearches_Daily에서 다음 인덱스가 :
 
/****** Object: Index [IX_LogInvSearches_Daily_LogDay] Script Date: 05/12/2010 11:08:22 ******/ 
CREATE NONCLUSTERED INDEX [IX_LogInvSearches_Daily_LogDay] ON [dbo].[LogInvSearches_Daily] 
(
    [LogDay] ASC 
) 
INCLUDE ([Inv_ID], 
[LogCount]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
  • 내가 재고를 당겨야 특정 계정 ID에 대한 인벤토리에서만 제공됩니다. 재고 목록에도 색인이 있습니다.

다음 쿼리를 사용하여 데이터를 집계하고 상위 5 개 레코드를 제공합니다. 이 쿼리는 현재 5 개 행 반환 24 초 걸리는 :

 
StmtText 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
SELECT TOP 5 
    Sum(LogCount) AS Views 
    , DENSE_RANK() OVER(ORDER BY Sum(LogCount) DESC, Inv_ID DESC) AS Rank 
    , Inv_ID 
FROM LogInvSearches_Daily D (NOLOCK) 
WHERE 
    LogDay > DateAdd(d, -30, getdate()) 
    AND EXISTS(
     SELECT NULL FROM propertyControlCenter.dbo.Inventory (NOLOCK) WHERE Acct_ID = 18731 AND Inv_ID = D.Inv_ID 
    ) 
GROUP BY Inv_ID 


(1 row(s) affected) 

StmtText 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
    |--Top(TOP EXPRESSION:((5))) 
     |--Sequence Project(DEFINE:([Expr1007]=dense_rank)) 
      |--Segment 
       |--Segment 
         |--Sort(ORDER BY:([Expr1006] DESC, [D].[Inv_ID] DESC)) 
          |--Stream Aggregate(GROUP BY:([D].[Inv_ID]) DEFINE:([Expr1006]=SUM([LOALogs].[dbo].[LogInvSearches_Daily].[LogCount] as [D].[LogCount]))) 
           |--Sort(ORDER BY:([D].[Inv_ID] ASC)) 
            |--Nested Loops(Inner Join, OUTER REFERENCES:([D].[Inv_ID])) 
              |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1011], [Expr1012], [Expr1010])) 
              | |--Compute Scalar(DEFINE:(([Expr1011],[Expr1012],[Expr1010])=GetRangeWithMismatchedTypes(dateadd(day,(-30),getdate()),NULL,(6)))) 
              | | |--Constant Scan 
              | |--Index Seek(OBJECT:([LOALogs].[dbo].[LogInvSearches_Daily].[IX_LogInvSearches_Daily_LogDay] AS [D]), SEEK:([D].[LogDay] > [Expr1011] AND [D].[LogDay] < [Expr1012]) ORDERED FORWARD) 
              |--Index Seek(OBJECT:([propertyControlCenter].[dbo].[Inventory].[IX_Inventory_Acct_ID]), SEEK:([propertyControlCenter].[dbo].[Inventory].[Acct_ID]=(18731) AND [propertyControlCenter].[dbo].[Inventory].[Inv_ID]=[LOA 

(13 row(s) affected) 
내가 그들을 먼저 행을 선택하고 집계하는 CTE를 사용하여 시도

을하지만 더 빨리 실행되지 않았고, 본질적으로 같은 날 제공 실행 계획.

 

(1 row(s) affected) 
StmtText 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
--SET SHOWPLAN_TEXT ON; 
WITH getSearches AS (
     SELECT 
      LogCount 
--   , DENSE_RANK() OVER(ORDER BY Sum(LogCount) DESC, Inv_ID DESC) AS Rank 
      , D.Inv_ID 
     FROM LogInvSearches_Daily D (NOLOCK) 
      INNER JOIN propertyControlCenter.dbo.Inventory I (NOLOCK) ON Acct_ID = 18731 AND I.Inv_ID = D.Inv_ID 
     WHERE 
      LogDay > DateAdd(d, -30, getdate()) 
--  GROUP BY Inv_ID 
) 

SELECT Sum(LogCount) AS Views, Inv_ID 
FROM getSearches 
GROUP BY Inv_ID 


(1 row(s) affected) 

StmtText 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 
    |--Stream Aggregate(GROUP BY:([D].[Inv_ID]) DEFINE:([Expr1004]=SUM([LOALogs].[dbo].[LogInvSearches_Daily].[LogCount] as [D].[LogCount]))) 
     |--Sort(ORDER BY:([D].[Inv_ID] ASC)) 
      |--Nested Loops(Inner Join, OUTER REFERENCES:([D].[Inv_ID])) 
       |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1008], [Expr1009], [Expr1007])) 
       | |--Compute Scalar(DEFINE:(([Expr1008],[Expr1009],[Expr1007])=GetRangeWithMismatchedTypes(dateadd(day,(-30),getdate()),NULL,(6)))) 
       | | |--Constant Scan 
       | |--Index Seek(OBJECT:([LOALogs].[dbo].[LogInvSearches_Daily].[IX_LogInvSearches_Daily_LogDay] AS [D]), SEEK:([D].[LogDay] > [Expr1008] AND [D].[LogDay] < [Expr1009]) ORDERED FORWARD) 
       |--Index Seek(OBJECT:([propertyControlCenter].[dbo].[Inventory].[IX_Inventory_Acct_ID] AS [I]), SEEK:([I].[Acct_ID]=(18731) AND [I].[Inv_ID]=[LOALogs].[dbo].[LogInvSearches_Daily].[Inv_ID] as [D].[Inv_ID]) ORDERED FORWARD) 

(8 row(s) affected) 


(1 row(s) affected) 

그래서 나는 좋은 지수를 얻고 있습니다. 실행 계획에서 Seeks를 찾으십시오.이 실행 속도를 높이려면 어떻게해야합니까?

UPDATE :

여기에 동일한 쿼리 실행이 DENSE_RANK (없이입니다)하고 실행하는 동일한 24초 소요되며, 나에게 동일한 기본 쿼리 계획을 제공합니다

 
StmtText 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
--SET SHOWPLAN_TEXT ON 
SELECT TOP 5 
    Sum(LogCount) AS Views 
    , Inv_ID 
FROM LogInvSearches_Daily D (NOLOCK) 
WHERE 
    LogDay > DateAdd(d, -30, getdate()) 
    AND EXISTS(
     SELECT NULL FROM propertyControlCenter.dbo.Inventory (NOLOCK) WHERE Acct_ID = 18731 AND Inv_ID = D.Inv_ID 
    ) 
GROUP BY Inv_ID 
ORDER BY Views, Inv_ID 
(1 row(s) affected) 

StmtText 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
    |--Sort(TOP 5, ORDER BY:([Expr1006] ASC, [D].[Inv_ID] ASC)) 
     |--Stream Aggregate(GROUP BY:([D].[Inv_ID]) DEFINE:([Expr1006]=SUM([LOALogs].[dbo].[LogInvSearches_Daily].[LogCount] as [D].[LogCount]))) 
      |--Sort(ORDER BY:([D].[Inv_ID] ASC)) 
       |--Nested Loops(Inner Join, OUTER REFERENCES:([D].[Inv_ID])) 
         |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1010], [Expr1011], [Expr1009])) 
         | |--Compute Scalar(DEFINE:(([Expr1010],[Expr1011],[Expr1009])=GetRangeWithMismatchedTypes(dateadd(day,(-30),getdate()),NULL,(6)))) 
         | | |--Constant Scan 
         | |--Index Seek(OBJECT:([LOALogs].[dbo].[LogInvSearches_Daily].[IX_LogInvSearches_Daily_LogDay] AS [D]), SEEK:([D].[LogDay] > [Expr1010] AND [D].[LogDay] < [Expr1011]) ORDERED FORWARD) 
         |--Index Seek(OBJECT:([propertyControlCenter].[dbo].[Inventory].[IX_Inventory_Acct_ID]), SEEK:([propertyControlCenter].[dbo].[Inventory].[Acct_ID]=(18731) AND [propertyControlCenter].[dbo].[Inventory].[Inv_ID]=[LOALogs].[dbo].[LogInvS 

(9 row(s) affected) 


감사합니다,

나는 아직 전체 질문을 읽어 적이 없다

+0

보고 싶은 출력의 예를 제공 할 수 있습니까? 왜 DENSE_RANK가 필요한지는 명확하지 않습니다. –

+0

난 그냥 상위 5가 필요합니다. DENSE_RANK()의 유무에 관계없이 정확히 동일한 성능을 보여주는 업데이트를 게시했습니다. –

답변

1

는 (나는 곧 그에게 올 것이다) 그러나 초기 코멘트에 대답 : 당신 을 수보기 SQL Server 2008 표준 버전에서 사용할 수 있습니다. Enterprise 버전으로 제한된 개의 테이블 (허용 범위가 더 넓습니다)이 분할되어 있습니다.

로 분할 된이 보는 정보 : 난 당신이 정말 거기에 DENSE_RANK 필요한 경우 알고 싶습니다 넓은 질문에 http://msdn.microsoft.com/en-us/library/ms190019.aspx

. DENSE_RANK 내부의 ORDER BY와 쿼리 자체의 ORDER BY 사이에 혼란 스러울 지 궁금합니다. SQL Server는 ORDER BY 절이 지정되지 않은 경우 레코드에 대한 순서를 보장하지 않으므로 TOP 5는 5 이 정의되지 않은 레코드를 반환합니다. ORDER BY를 DENSE_RANK에서 전체 ORDER BY로 ORDER BY로 이동하면 원하는대로 생각할 수있는 레코드가 나오고 값 비싼 DENSE_RANK 집계 함수가 필요하지 않게됩니다.

SELECT TOP 5 
    SUM([LogCount]) AS [Views], 
    [Inv_ID] 
FROM [LogInvSearches_Daily] D (NOLOCK) 
WHERE 
    [LogDay] > DateAdd(d, -30, getdate()) 
    AND EXISTS(
     SELECT * 
     FROM Inventory (NOLOCK) 
     WHERE Acct_ID = 18731 
      AND Inv_ID = D.Inv_ID 
    ) 
GROUP BY 
    Inv_ID 
ORDER BY 
    [Views] DESC, 
    [Inv_ID] 

업데이트 :

시간은 아마 여기에 사용되는 :

CREATE NONCLUSTERED INDEX [IX_LogInvSearches_Daily_Perf] ON [dbo].[LogInvSearches_Daily] 
(
    [Inv_ID] ASC, 
    [LogDay] ASC 
) 
INCLUDE 
(
    [LogCount] 
) 

참고 :

|--Sort(ORDER BY:([D].[Inv_ID] ASC)) 

당신은 이와 같은 커버링 인덱스를 만드는 시도 할 수 ORDER BY를 약간 변경했습니다 (Inv_ID가 이제 너무 DESC가 아닌 ASC). 이 변경이 문제가되는 방식으로 결과에 영향을 미치지는 않지만 그룹화 된 순서와 동일한 순서로 행을 반환하기 때문에 성능에 도움이 될 수 있습니다 (비록 관련이 없지만!).

+0

DENSE_RANK()가 아니라도 결과는 여전히 느립니다. 나는 그것을 두 가지 방법으로 시도해 봤지만 24 초보다 빨리로드 할 수는 없습니다. DENSE_RANK()가없는 동일한 쿼리에 대한 쿼리 계획 및 시간 표시로 업데이트되었습니다. –

+0

인덱스 제안으로 내 대답을 업데이트했습니다. –

+0

인덱스가 트릭을 수행 할 것으로 생각합니다. 이제 전체 서버를 다운시키지 않고 인덱스를 생성하는 방법을 알아 내야 만합니다 ... –

1

는 파티션 옆으로, 당신보다 더 큰 테이블과의 경험을 바탕으로

, 우리는에 임시 테이블 (테이블하지 변수) 및 집합으로 데이터를 추출합니다. 모든 검색어가 아니라 더 복잡한 검색어입니다. 그 외에는

, 나는

+0

글쎄요, 이것은 집계 테이블입니다 ... 우리는 ms 테이블을 가지고 있습니다. 그러면이 모든 요청이 롤백됩니다. 일. 나는 지금 어떤 질문을하려고합니다. 나는 이것들보다 더 많은 것을 깨뜨릴 수 없다. 왜냐하면 이것들은 동적 인 쿼리들이 그들의 계정에 대한 요구에 따라 사용자에 의해 실행되기 때문이다. –

0
(아마도 DESC 정렬에 포함되지 않음) 가 나는 또한 색인에 [LogCount], [Inv_ID] 이동에 대해 생각하는 것

이 DENSE_RANK

에 대한 다니엘 렌쇼의 관찰에 동의

Acct_ID가 인벤토리 테이블에 있으며 자체에 대한 인덱스 (IX_Inventory_Acct_ID)가있는 것으로 보입니다. 아마도 Inventory가 (Acct_Id, Inv_Id)에 대한 색인을 갖고 LogInvSearches_Daily이 (Inv_Id, LogDay) 주위에 클러스터되었거나 (적어도 색인이 생성 된 경우), 운이 더 좋을 것입니다.

현재, LogInvSearches_Daily.ID의 현재 클러스터링 색인이 사용자를 구입할 것으로 추정됩니다. 디스크에 가까이있는 ID를 가진 레코드를 가져 오는 이유는 무엇입니까?

관련 문제