Làm cách nào để chạy tập lệnh lớn với nhiều phần chèn mà không hết bộ nhớ?


28

Câu hỏi:

Tôi có một tập lệnh với khoảng 45 nghìn chèn từ các câu lệnh được chọn. Khi tôi thử và chạy nó, tôi nhận được một thông báo lỗi nói rằng tôi đã hết bộ nhớ. Làm thế nào tôi có thể có được kịch bản này để chạy?

Bối cảnh:

  1. Đã thêm một số trường dữ liệu mới để làm cho ứng dụng phát tốt với ứng dụng khác mà khách hàng sử dụng.
  2. Có một bảng tính dữ liệu từ máy khách chứa đầy dữ liệu ánh xạ các mục dữ liệu hiện tại thành các giá trị cho các trường mới này.
  3. Chuyển đổi bảng tính để chèn báo cáo.
  4. Nếu tôi chỉ chạy một số câu lệnh thì nó hoạt động nhưng toàn bộ tập lệnh thì không.
  5. Không. Không có lỗi chính tả.

Nếu có một cách khác tôi nên tải dữ liệu này, vui lòng trừng phạt tôi và cho tôi biết.


Câu hỏi tương tự trên SO: ( stackoverflow.com/questions/222442/ trên ) Không chắc câu trả lời có giúp ích không
jumpdart

Câu trả lời:


17

Kích thước lô tối đa cho SQL Server 2005 là 65.536 * Kích thước gói mạng (NPS), trong đó NPS thường là 4KB. Nó hoạt động tới 256 MB. Điều đó có nghĩa là các câu lệnh chèn của bạn sẽ trung bình 5,8 KB mỗi câu. Điều đó có vẻ không đúng, nhưng có thể có không gian bên ngoài hoặc có gì đó bất thường trong đó.

Đề xuất đầu tiên của tôi sẽ là đặt câu lệnh "GO" sau mỗi câu lệnh INSERT. Điều này sẽ chia lô 45.000 câu lệnh INSERT duy nhất của bạn thành 45.000 lô riêng biệt. Điều này sẽ dễ tiêu hóa hơn. Hãy cẩn thận, nếu một trong những lần chèn đó thất bại, bạn có thể gặp khó khăn trong việc tìm ra thủ phạm. Bạn có thể muốn tự bảo vệ mình bằng một giao dịch. Bạn có thể nhanh chóng thêm các câu lệnh đó nếu trình soạn thảo của bạn có một tìm kiếm và thay thế tốt (điều đó sẽ cho phép bạn tìm kiếm và thay thế các ký tự trả về như \ r \ n) hoặc một cơ sở macro.

Gợi ý thứ hai là sử dụng Trình hướng dẫn để nhập dữ liệu trực tiếp từ Excel. Trình hướng dẫn xây dựng một gói SSIS nhỏ cho bạn, đằng sau hậu trường, và sau đó chạy nó. Nó sẽ không có vấn đề này.


2
A GOsau mỗi tuyên bố? Chà, tôi đoán là nếu bạn tạo chúng bằng cách sử dụng tập lệnh khác thì không sao. Mặt khác, tôi chỉ đặt một cái sau mỗi 1000 INSERTgiây. Liên quan đến việc tạo nguyên tử giao dịch và giảm thiểu kích thước của giao dịch, tại sao không tải tất cả các hàng vào một bảng tạm thời hoặc biến bảng và sau đó tải chúng trong một lần bắn từ đó vào bảng đích?
Nick Chammas

1000 chỉ tốt bằng 1, nhưng khó đếm hơn. Thành thật mà nói, anh ta có thể thoát khỏi chỉ với một tuyên bố GO, ở nửa đường, gần tuyên bố 21.500. Tôi thích bản sửa lỗi GO vì nó không yêu cầu chỉnh sửa tập lệnh hiện tại phức tạp hoặc đếm các câu lệnh INSERT (có thể không ánh xạ trực tiếp đến số dòng).
eo biển darin

2
Chắc chắn, ngay cả một xấp xỉ xấu của 1000 báo cáo là đủ tốt. :)
Nick Chammas

1
Thêm GOs là một sửa chữa nhanh chóng và dễ dàng .. Tập lệnh 25mb chạy trong ít hơn 9 phút mà không gặp vấn đề gì. Muốn có nó như một kịch bản để giữ nó trong quy trình triển khai bản vá tiêu chuẩn của chúng tôi khi nó ra ngoài.
spaghetticowboy

14

BULK INSERThoặc bcpcó vẻ tùy chọn phù hợp hơn 45.000 câu lệnh chèn.

Nếu bạn cần phải tuân theo các câu lệnh chèn, tôi sẽ xem xét một vài lựa chọn:

Trả lời: Sử dụng các giao dịch và gói các lô 100 hoặc 500 hoặc 1000 câu lệnh trong mỗi câu lệnh để giảm thiểu tác động lên nhật ký và lô. ví dụ

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: Thay vì các câu lệnh chèn riêng lẻ, hãy sử dụng UNION ALLcho 100 hoặc 500 câu lệnh cùng một lúc, ví dụ:

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

Tôi đã để lại lỗi xử lý cho ngắn gọn, nhưng vấn đề là tôi sẽ không bao giờ cố gắng gửi một lô 45.000 câu lệnh riêng lẻ đến SQL Server.


1
Quá tệ, OP không thể sử dụng các hàm tạo giá trị bảng , một tính năng 2008+. Anh ấy vẫn phải gộp các phần chèn thành các nhóm 1000 hàng, đây là mức tối đa bạn có thể nhóm cùng với một TVC.
Nick Chammas

Đó sẽ là đề xuất đầu tiên của tôi cho đến khi tôi nhìn thấy thẻ phiên bản.
Aaron Bertrand

2
@NickChammas - Hiệu suất của những suy giảm không tuyến tính với số lượng các mệnh đề BTW . Tôi đã gửi một mục kết nối với một repro chèn 1000 hàng với 10 VARCHAR(800)cột vào năm 2008 với thời gian biên dịch là 12,5 phút trong ví dụ dev năm 2008 của tôi vì nó thực hiện rất nhiều công việc không cần thiết so sánh các giá trị thay vì chỉ bắt đầu với việc chèn chúng (thực hiện nhiều nhanh hơn khi tham số hóa và không có giá trị để xem xét). Mặc dù đã được cải thiện rất nhiều vào năm 2012, nhưng mô hình phi tuyến tính vẫn tồn tại và sẽ được sửa trong phiên bản sau.
Martin Smith

9

Tôi không chắc tại sao bạn lại thoát khỏi lỗi bộ nhớ, nhưng có một cách tiếp cận dễ dàng hơn.

Nếu bạn có thể xuất dữ liệu từ bảng tính sang định dạng được phân tách (ví dụ: csv), bạn có thể sử dụng trình hướng dẫn nhập dữ liệu trong SSMS để chèn dữ liệu cho bạn:

Nhiệm vụ nhập dữ liệu SSMS.


đó là hữu ích nhưng tôi không có quyền truy cập vào cơ sở dữ liệu khách hàng. Tôi phải chuẩn bị các bản vá và tải dữ liệu trong các tập lệnh
spaghetticowboy


0

Có, chúng tôi có thể làm điều đó, tôi đã thử với phương pháp BCP (Chương trình sao chép hàng loạt) để tránh sự cố OutOfMemory .

Lưu ý : Đã thử trên SQL Server 2014.

Trong BCP, trước tiên chúng ta cần xuất dữ liệu cơ sở dữ liệu nguồn sang tệp bcp (trong thư mục thư mục cục bộ) và sau đó cần nhập tệp bcp đó vào cơ sở dữ liệu đích.

nhập mô tả hình ảnh ở đây

Dưới đây là các bước đi bộ bánh:

Chú thích:

a) Đảm bảo bảng trống có trong cơ sở dữ liệu đích

b) Đảm bảo thư mục Temp có trong ổ C

  1. Tạo một tập tin bat có tên là Export_Data.bat bằng lệnh được hiển thị bên dưới:

    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 

    tạm ngừng

  2. Chạy tệp bat đó, do đó tệp bcp sẽ được tạo trong thư mục Temp

  3. Sau đó, tạo một tệp dơi khác có tên là Import_Data.bat bằng lệnh sau:

    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 

    Tạm ngừng

Và chúng ta đi đây!


Bắt lỗi "Tên bảng hợp lệ là bắt buộc cho các tùy chọn vào, ra hoặc định dạng." khi cố gắng xuất dữ liệu.
Sen Jacob

1
Bạn có thể dán lệnh bạn đã thử với tất cả giá trị thuộc tính không. Vui lòng làm theo ví dụ dưới đây: bcp.exe ExportDB.dbo.AddressCountry OUT "C: \ Temp \ addressCountry.bcp" -S "IN-L20054" -U "sa" -P "sa" -n -q Trong đó [ExportDB -> Nguồn DB, Địa chỉCountry-> Bảng có trong Nguồn DB, IN-L20054 -> Tên máy, "sa" là tên người dùng / pwd của DB]
Kms

Tôi không có nó bây giờ. Tôi đã kết thúc bằng cách sử dụng tính năng nhập dữ liệu trong SSMS. Sau đó, kết nối DB đích (v14.0) với DB nguồn (v.15.0) bằng kết nối MS OLE DB và việc nhập hàng triệu hàng dữ liệu khá nhanh. Cảm ơn!
Sen Jacob
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.