2013-08-09 2 views
3

500 만 개의 행이있는 데이터베이스 테이블이 있습니다. 클러스터 된 인덱스는 자동 증가 ID 열입니다. PK는 URL의 SHA256 해시 인 256 바이트 VARCHAR 코드를 생성합니다. 이는 테이블의 클러스터되지 않은 색인입니다.SQL Server : MERGE 성능

CREATE TABLE [dbo].[store_image](
    [imageSHAID] [nvarchar](256) NOT NULL, 
    [imageGUID] [uniqueidentifier] NOT NULL, 
    [imageURL] [nvarchar](2000) NOT NULL, 
    [showCount] [bigint] NOT NULL, 
    [imageURLIndex] AS (CONVERT([nvarchar](450),[imageURL],(0))), 
    [autoIncID] [bigint] IDENTITY(1,1) NOT NULL, 
CONSTRAINT [PK_imageSHAID] PRIMARY KEY NONCLUSTERED 
(
    [imageSHAID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 

CREATE CLUSTERED INDEX [autoIncPK] ON [dbo].[store_image] 
(
    [autoIncID] ASC 
)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] 
GO 
  • imageSHAID 예컨대 화상의 URL SHA256 해시이다 : 다음

    테이블은 "http://blah.com/image1.jpg"이면 길이가 256 인 varchar로 해시됩니다.

  • imageGUID

    제가 화상을 식별하는 GUID를 생성 코드

  • imageURL가 전체 URL이다 (이는 색인 이상으로 사용되지만, 지금 I 인덱스로서이 항목을 생략 한) 이미지 (최대 2000 자)

  • showCount 이미지가 표시되는 횟수이며,이 특정 이미지가 표시 될 때마다 증가합니다.

  • imageURLIndex

    450 개 문자로 제한 계산 된 열입니다,이 날 I가 선택해야 할 이미지 URL에서 텍스트 검색을 수행 할 수 있습니다,

  • autoIncID는 클러스터입니다 (다시 인덱스가 간결하게 생략) 색인입니다 인덱스를 사용하면 데이터를 더 빠르게 삽입 할 수 있습니다.

주기적으로 임시 테이블에서 store_image 테이블로 병합합니다. 임시 테이블 구조합니다 (store_image 테이블과 매우 유사) 다음과 같습니다

using (SqlBulkCopy bulk = new SqlBulkCopy(storeConn, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.KeepNulls, null)) 
{ 
    bulk.DestinationTableName = "[dbo].[store_image_temp]"; 
    bulk.WriteToServer(imageTableUpsetDataTable); 
} 

:

병합 프로세스가 실행
CREATE TABLE [dbo].[store_image_temp](
    [imageSHAID] [nvarchar](256) NULL, 
    [imageURL] [nvarchar](2000) NULL, 
    [showCount] [bigint] NULL, 
) ON [PRIMARY] 

GO 

, 나는 다음과 같은 코드를 사용하여 임시 테이블에 DataTable 쓰기 그런 다음 병합 명령을 실행하여 imageSHAID을 기반으로 임시 테이블에서 병합하여 store_image 테이블의 showCount을 업데이트합니다. 이미지가 현재 store_image 테이블에 존재하지 않는 경우, 나는 그것을 만들 :

merge into store_image as Target using [dbo].[store_image_temp] as Source 
on Target.imageSHAID=Source.imageSHAID 
when matched then update set 
Target.showCount=Target.showCount+Source.showCount 
when not matched then insert values (Source.imageSHAID,NEWID(), Source.imageURL, Source.showCount); 

나는 일반적으로 하나 병합 프로세스에서 store_image 테이블에 임시 테이블에서 2K-5K 행을 병합하기 위해 노력하고있어.

이 DB를 SSD (연결된 SATA 1 만)에서 실행하는 데 사용되어 매우 빠릅니다 (200 밀리 초 미만). SSD에서 공간이 부족하여 DB를 1TB 7200 캐시 디스크로 교체 했으므로 완료 시간이 6-100 초 (6000 - 100000MS)를 넘기 때문에 디스크를 교체했습니다. 대량 삽입이 실행 중일 때 약 1MB-2MB/초의 디스크 활동, 낮은 CPU 사용량을 볼 수 있습니다.

이 데이터 양에 대한 일반적인 쓰기 시간입니까? 느린 성능을 일으키는 것은 나에게 조금 느린 것 같습니다. 확실히 imageSHAID이 인덱싱되면 우리는 이보다 더 빠른 탐색 시간을 기대해야합니까?

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

감사합니다.

답변

3

MERGEshowCount에있는 UPDATE 조항. 이를 위해서는 클러스터 된 인덱스에서 키 조회가 필요합니다.

그러나 클러스터 된 인덱스도 고유하지 않은 것으로 선언됩니다. 기본 컬럼이 고유하더라도 옵티 마이저에 정보를 제공합니다.

그래서, 이러한 변화

  • 클러스터 된 기본 키가 autoIncID
  • imageSHAID의 현재 PK 독립 고유 인덱스가 될 수 있도록 (제약 조건 없음)과는 showCount에 대한 INCLUDE 추가 할 것입니다.

    • 당신은 해시 또는 URL 열에 대한 nvarchar을 필요로하지 않습니다 수 없습니다 고유 제약

    더 많은 관측을 포함한다. 이것들은 유니 코드가 아닙니다.

  • 해시도 고정 길이이므로 char(64) (SHA2-512) 일 수 있습니다.
  • 열의 길이는 쿼리에 할당 할 메모리 양을 정의합니다. 이상이를 참조하십시오 is there an advantage to varchar(500) over varchar(8000)?
+0

안녕하세요,이 크게 일을 개선하는 것, 나는 몇 가지 테스트를 RNU하고 병합 시간이 더 낮은 것 같다 : 3.7K (24) @ 초 2.6k를 2.4 초 11초 @ 2.8k @ 1.3k @ 1.1 초 2.6k @ 2.5 초 2.1k @ 2.6 초이 병합 시간이 적절한 것처럼 보입니까? "다른 관찰"을 수정하는 것이 더 나아질까요? 나는 2-3k 행 병합이 항상 500ms보다 짧을 것이라고 생각했다. – user989056

+0

다른 관찰은 디스크 및 메모리 사용량을 줄이고, 바이트 단위로 이동할 수 있습니다 (예 : 트랜잭션 로그). 그리고 Optimizer가 메모리를 효율적으로 할당하도록 도와줍니다. – gbn

+0

제안 된 변경 사항을 수행 한 후에도 여전히 성능이 저하됩니다. 70 초 이상 지속되는 병합이 있습니다. 주어진 인덱스/PK를 변경했다면 병합을 호출 할 때 무슨 일이 일어나는지 설명 할 수 있습니까? 분명히 imageSHAID 독립형 고유 인덱스에 대한 인덱스를 사용하고 있습니다.이 인덱스는 빠른 아니야? – user989056