메모리가 부족하지 않으면 서 많은 인서트로 큰 스크립트를 실행하려면 어떻게해야합니까?


28

의문:

select 문에서 약 45,000 개의 삽입물이있는 스크립트가 있습니다. 시도하고 실행할 때 메모리가 부족하다는 오류 메시지가 표시됩니다. 이 스크립트를 실행하려면 어떻게해야합니까?

문맥:

  1. 클라이언트가 사용하는 다른 앱에서 앱을 멋지게 재생하기 위해 몇 가지 새로운 데이터 필드를 추가했습니다.
  2. 현재 데이터 항목을 이러한 새 필드의 값에 매핑 한 데이터로 가득 찬 클라이언트의 데이터 스프레드 시트를 얻었습니다.
  3. 문을 삽입하기 위해 스프레드 시트를 변환했습니다.
  4. 문 중 일부만 실행하면 작동하지만 전체 스크립트는 작동하지 않습니다.
  5. 아니요. 오타가 없습니다.

다른 방법이 있다면이 데이터를로드해야합니다. 나를 쫓아 알려주십시오.


SO에 대한 비슷한 질문 : ( stackoverflow.com/questions/222442/… ) 답변이 도움이되는지 확실하지 않습니다
jumpdart

답변:


17

SQL Server 2005의 최대 배치 크기는 65,536 * NPS (Network Packet Size)이며 NPS는 일반적으로 4KB입니다. 256MB까지 작동합니다. 이는 삽입 문이 각각 평균 ​​5.8KB임을 의미합니다. 그것은 옳지 않은 것처럼 보이지만 아마도 외부 공간이나 이상한 것이있을 수 있습니다.

첫 번째 제안은 모든 INSERT 문 뒤에 "GO"문을 넣는 것입니다. 이렇게하면 45,000 개의 INSERT 문의 단일 배치가 45,000 개의 개별 배치로 분할됩니다. 이것은 소화하기 쉬워야합니다. 이러한 인서트 중 하나가 고장 나면 범인을 찾기가 어려울 수 있습니다. 거래로 자신을 보호하고 싶을 수도 있습니다. 편집기에 검색 및 대치 (\ r \ n과 같은 리턴 문자를 검색하고 대체 할 수있는) 또는 매크로 기능이있는 경우 이러한 명령문을 빠르게 추가 할 수 있습니다.

두 번째 제안은 마법사를 사용하여 Excel에서 데이터를 직접 가져 오는 것입니다. 마법사는 사용자를 위해 약간의 SSIS 패키지를 빌드 한 다음 실행합니다. 이 문제는 없습니다.


2
GO모든 문? 글쎄, 다른 스크립트를 사용하여 생성하는 것이 좋습니다. 그렇지 않으면 1000 INSERT초 마다 하나씩 넣을 것 입니다. 트랜잭션을 원자화하고 트랜잭션 크기를 최소화하는 것과 관련하여 모든 행을 임시 테이블 또는 테이블 변수에로드 한 다음 거기에서 대상 테이블로 한 번에로드하지 않는 이유는 무엇입니까?
Nick Chammas

1000은 1만큼 좋지만 계산하기가 어렵습니다. 솔직히 말하면, 그는 21,500 번 문 근처의 중간 표시에서 하나의 GO 문만으로 도망 칠 수 있습니다. GO 수정 프로그램은 현재 스크립트를 복잡하게 편집하거나 INSERT 문을 계산할 필요가 없기 때문에 좋아합니다 (행 번호에 직접 매핑되지 않을 수도 있음).
darin 해협

2
분명히 1000 개의 문을 잘못 추정해도 충분합니다. :)
Nick Chammas

1
GO를 추가하는 것은 빠르고 쉬운 수정이었습니다. 25mb 스크립트는 문제없이 9 분도 채 걸리지 않습니다. 표준 패치 배포 프로세스 내에서 스크립트를 유지하면서 스크립트를 사용하고 싶었습니다.
spaghetticowboy

14

BULK INSERT또는 bcp45,000 개의 insert 문보다 더 적절한 옵션으로 보입니다.

insert 문을 고수 해야하는 경우 몇 가지 옵션을 고려할 것입니다.

A : 로그와 배치에 대한 영향을 최소화하기 위해 각각 하나에 100 또는 500 또는 1000 개의 명세서로 트랜잭션 및 랩 배치를 사용하십시오. 예 :

BEGIN TRANSACTION;
INSERT dbo.table(a, ...) SELECT 1, ...
INSERT dbo.table(a, ...) SELECT 2, ...
...
INSERT dbo.table(a, ...) SELECT 500, ...
COMMIT TRANSACTION;
GO

BEGIN TRANSACTION;
INSERT dbo.table(a, ...) SELECT 1, ...
INSERT dbo.table(a, ...) SELECT 2, ...
...
INSERT dbo.table(a, ...) SELECT 500, ...
COMMIT TRANSACTION;
GO

B : 개별 삽입 문 대신 UNION ALL한 번에 100 또는 500 문을 사용하십시오. 예 :

INSERT dbo.table(a, ...)
SELECT 1, ...
UNION ALL SELECT 2, ...
...
UNION ALL SELECT 500, ...
GO

INSERT dbo.table(a, ...)
SELECT 501, ...
UNION ALL SELECT 502, ...
...
UNION ALL SELECT 1000, ...
GO

간결성을 위해 오류 처리를 남겼지 만 요점은 45,000 개의 개별 문을 단일 배치로 SQL Server에 보내려고 시도하지 않는다는 것입니다.


1
OP는 2008+ 기능인 테이블 값 생성자를 사용할 수 없습니다 . 그는 여전히 인서트를 1000 행 그룹으로 배치해야하는데, 이는 TVC와 함께 그룹화 할 수있는 최대 값입니다.
Nick Chammas

버전 태그를 볼 때까지 첫 제안이었습니다.
Aaron Bertrand

2
@NickChammas- 이들의 성능은 BTW 값 수 절에 따라 비선형 적으로 저하 됩니다. 2008 dev 인스턴스에서 컴파일 시간이 12.5 분 으로 2008 년 10 개의 열이있는 1000 개의 행을 삽입하는 repro로 연결 항목 을 제출 했습니다. 값을 삽입하는 대신 값을 비교하는 데 불필요한 작업이 많이 수행되므로 매개 변수가 있고 더 이상 볼 값이 없을 때 더 빠릅니다). 2012 년에 많이 개선되었지만 비선형 패턴은 여전히 ​​존재하며 이후 버전에서 수정되어야합니다. VARCHAR(800)
Martin Smith

9

왜 메모리 부족 오류가 발생하는지 잘 모르겠지만 더 쉬운 방법이 있습니다.

스프레드 시트의 데이터를 구분 된 형식 (예 : csv)으로 내보낼 수있는 경우 SSMS의 데이터 가져 오기 마법사를 사용하여 데이터를 삽입 할 수 있습니다.

SSMS 데이터 가져 오기 작업.


그게 도움이되지만 클라이언트 데이터베이스에 액세스 할 수 없습니다. 스크립트로 패치와 데이터로드를 준비해야합니다
spaghetticowboy

0

여러 SqlBulkCopy를 사용하여 임시 테이블을 만듭니다. 임시 테이블에 새 데이터를 삽입 한 다음 임시 테이블의 데이터를 기존 데이터에 병합하십시오. C # SqlBulkCopy.WriteToServer 메서드를 사용하는 예제 (DataTable) . 그것이 도움이되기를 바랍니다.


0

그렇습니다 . OutOfMemory 문제 를 피하기 위해 BCP (Bulk Copy Program) 접근 방식으로 시도했습니다 .

참고 : SQL Server 2014에서 시도했습니다.

BCP에서 먼저 소스 데이터베이스 데이터를 bcp 파일 (로컬 디렉토리 폴더에 있음)로 내 보낸 다음 해당 bcp 파일을 대상 데이터베이스 로 가져와야 합니다.

여기에 이미지 설명을 입력하십시오

다음은 케이크 워크 단계입니다.

노트 :

a) 대상 데이터베이스에 빈 테이블이 있는지 확인하십시오

b) C 드라이브 에 Temp 폴더가 있는지 확인하십시오

  1. 아래 표시된 명령을 사용하여 Export_Data.bat 라는 bat 파일을 만듭니다 .

    bcp.exe [Source_DataBase_Name].[dbo].[TableName] OUT "C:\Temp\TableName.bcp" -S "Computer Name" -U "SQL Server UserName" -P "SQL Server Password" -n -q 

    중지

  2. bcp 파일이 Temp 폴더에 생성 되므로 해당 bat 파일을 실행하십시오.

  3. 다음 명령 으로 Import_Data.bat 라는 다른 bat 파일을 작성하십시오 .

    bcp.exe [Destination_DataBase_Name].[dbo].[TableName] IN "C:\Temp\TableName.bcp" -S "Computer Name" -U "SQL Server UserName" -P "SQL Server Password" -n -q 

    중지

우리가 간다!


"입력, 출력 또는 형식 옵션에 유효한 테이블 이름이 필요합니다."오류 발생 데이터를 내보내려고 할 때
Sen Jacob

1
시도한 명령을 모든 속성 값으로 붙여 넣을 수 있습니다. 다음 예를 따르십시오. bcp.exe ExportDB.dbo.AddressCountry OUT "C : \ Temp \ AddressCountry.bcp"-S "IN-L20054"-U "sa" -P "sa"-n -q [ExportDB-> 소스 DB, AddressCountry-> 소스 DB에 존재하는 테이블, IN-L20054-> 머신 이름, "sa"는 DB의 사용자 이름 / 암호]
Kms

나는 지금 그것을 가지고 있지 않습니다. SSMS에서 데이터 가져 오기 기능을 사용했습니다. 그런 다음 MS OLE DB 연결을 사용하여 대상 DB (v14.0)를 소스 DB (v.15.0)에 연결했으며 수백만 행의 데이터를 가져 오는 것이 매우 빠릅니다. 감사!
Sen Jacob
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.