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로 해시됩니다.
제가 화상을 식별하는 GUID를 생성 코드imageGUID
imageURL
가 전체 URL이다 (이는 색인 이상으로 사용되지만, 지금 I 인덱스로서이 항목을 생략 한) 이미지 (최대 2000 자)showCount
이미지가 표시되는 횟수이며,이 특정 이미지가 표시 될 때마다 증가합니다.
450 개 문자로 제한 계산 된 열입니다,이 날 I가 선택해야 할 이미지 URL에서 텍스트 검색을 수행 할 수 있습니다,imageURLIndex
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
이 인덱싱되면 우리는 이보다 더 빠른 탐색 시간을 기대해야합니까?
도움을 주시면 감사하겠습니다.
감사합니다.
안녕하세요,이 크게 일을 개선하는 것, 나는 몇 가지 테스트를 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
다른 관찰은 디스크 및 메모리 사용량을 줄이고, 바이트 단위로 이동할 수 있습니다 (예 : 트랜잭션 로그). 그리고 Optimizer가 메모리를 효율적으로 할당하도록 도와줍니다. – gbn
제안 된 변경 사항을 수행 한 후에도 여전히 성능이 저하됩니다. 70 초 이상 지속되는 병합이 있습니다. 주어진 인덱스/PK를 변경했다면 병합을 호출 할 때 무슨 일이 일어나는지 설명 할 수 있습니까? 분명히 imageSHAID 독립형 고유 인덱스에 대한 인덱스를 사용하고 있습니다.이 인덱스는 빠른 아니야? – user989056