Theo như tôi có thể nói với bạn, bạn có thể tối ưu hóa một phần chèn hàng loạt theo cách rất giống với cách bạn tối ưu hóa một phần chèn thông thường. Thông thường, một kế hoạch truy vấn cho một chèn đơn giản không có nhiều thông tin vì vậy đừng lo lắng về việc không có kế hoạch. Tôi sẽ xem xét một số cách tối ưu hóa phần chèn nhưng hầu hết trong số chúng có thể không áp dụng cho phần chèn bạn đã chỉ định trong câu hỏi. Tuy nhiên, chúng có thể hữu ích nếu trong tương lai bạn cần tải lượng dữ liệu lớn hơn.
1. Chèn dữ liệu theo thứ tự khóa cụm
SQL Server sẽ thường sắp xếp dữ liệu trước khi chèn nó vào một bảng có chỉ mục được nhóm. Đối với một số bảng và ứng dụng, bạn có thể cải thiện hiệu suất bằng cách sắp xếp dữ liệu trong tệp phẳng và cho SQL Server biết rằng dữ liệu được sắp xếp thông qua ORDER
đối số BULK INSERT
:
ĐẶT HÀNG ({cột [ASC | DESC]} [, ... n])
Chỉ định cách sắp xếp dữ liệu trong tệp dữ liệu. Hiệu suất nhập hàng loạt được cải thiện nếu dữ liệu được nhập được sắp xếp theo chỉ mục được nhóm trên bảng, nếu có.
Vì bạn đang sử dụng một IDENTITY
cột làm khóa cụm, bạn không cần phải lo lắng về điều này.
2. Sử dụng TABLOCK
nếu có thể
Nếu bạn được đảm bảo chỉ có một phiên chèn dữ liệu vào bảng của mình, bạn có thể chỉ định TABLOCK
đối số cho BULK INSERT
. Điều này có thể làm giảm sự tranh chấp khóa và có thể dẫn đến đăng nhập tối thiểu trong một số tình huống. Tuy nhiên, bạn đang chèn vào một bảng có chỉ mục được nhóm chứa dữ liệu để bạn sẽ không nhận được ghi nhật ký tối thiểu mà không có cờ theo dõi 610 được đề cập sau trong câu trả lời này.
Nếu TABLOCK
không thể, bởi vì bạn không thể thay đổi mã , không phải tất cả hy vọng đều bị mất. Cân nhắc sử dụng sp_table_option
:
EXEC [sys].[sp_tableoption]
@TableNamePattern = N'dbo.BulkLoadTable' ,
@OptionName = 'table lock on bulk load' ,
@OptionValue = 'ON'
Một tùy chọn khác là bật cờ theo dõi 715 .
3. Sử dụng cỡ lô thích hợp
Đôi khi bạn sẽ có thể điều chỉnh các phần chèn bằng cách thay đổi kích thước lô.
ROWS_PER_BATCH = rows_per_batch
Cho biết số lượng hàng dữ liệu gần đúng trong tệp dữ liệu.
Theo mặc định, tất cả dữ liệu trong tệp dữ liệu được gửi đến máy chủ dưới dạng một giao dịch và số lượng hàng trong lô không xác định đối với trình tối ưu hóa truy vấn. Nếu bạn chỉ định ROWS_PER_BATCH (có giá trị> 0), máy chủ sẽ sử dụng giá trị này để tối ưu hóa hoạt động nhập hàng loạt. Giá trị được chỉ định cho ROWS_PER_BATCH sẽ xấp xỉ bằng số lượng hàng thực tế. Để biết thông tin về các cân nhắc về hiệu suất, xem "Ghi chú", sau trong chủ đề này.
Đây là trích dẫn từ sau trong bài viết:
Nếu số lượng trang được xóa trong một lô vượt quá ngưỡng bên trong, có thể quét toàn bộ nhóm bộ đệm để xác định trang nào sẽ bị xóa khi lô được thực hiện. Quét toàn bộ này có thể làm tổn thương hiệu suất nhập hàng loạt. Một trường hợp có khả năng vượt quá ngưỡng nội bộ xảy ra khi nhóm bộ đệm lớn được kết hợp với hệ thống con I / O chậm. Để tránh tràn bộ đệm trên các máy lớn, không sử dụng gợi ý TABLOCK (sẽ loại bỏ tối ưu hóa hàng loạt) hoặc sử dụng kích thước lô nhỏ hơn (bảo tồn tối ưu hóa hàng loạt).
Vì máy tính khác nhau, chúng tôi khuyên bạn nên kiểm tra các kích cỡ lô khác nhau với tải dữ liệu của mình để tìm ra cách nào phù hợp nhất với bạn.
Cá nhân tôi sẽ chỉ chèn tất cả 695 hàng trong một lô. Điều chỉnh kích thước lô có thể tạo ra sự khác biệt lớn khi chèn nhiều dữ liệu.
4. Hãy chắc chắn rằng bạn cần IDENTITY
cột
Tôi không biết gì về mô hình dữ liệu hoặc yêu cầu của bạn, nhưng đừng rơi vào cái bẫy thêm IDENTITY
cột vào mỗi bảng. Aaron Bertrand có một bài viết về điều này được gọi là thói quen xấu để đá: đặt một cột IDENTITY trên mỗi bàn . Để rõ ràng, tôi không nói rằng bạn nên xóa IDENTITY
cột khỏi bảng này. Tuy nhiên, nếu bạn xác định rằng IDENTITY
cột là không cần thiết và loại bỏ nó có thể cải thiện hiệu suất chèn.
5. Vô hiệu hóa các chỉ mục hoặc các ràng buộc
Nếu bạn đang tải một lượng lớn dữ liệu vào một bảng so với những gì bạn đã có thì có thể nhanh hơn để vô hiệu hóa các chỉ mục hoặc các ràng buộc trước khi tải và để bật chúng sau khi tải. Đối với lượng dữ liệu lớn, SQL Server thường không hiệu quả hơn khi xây dựng một chỉ mục cùng một lúc thay vì dữ liệu được tải vào bảng. Có vẻ như bạn đã chèn 695 hàng vào một bảng có 11500 hàng, vì vậy tôi không khuyến nghị kỹ thuật này.
6. Xem xét TF 610
Trace Flag 610 cho phép đăng nhập tối thiểu trong một số tình huống bổ sung. Đối với bảng của bạn có IDENTITY
khóa được nhóm, bạn sẽ có được ghi nhật ký tối thiểu cho bất kỳ trang dữ liệu mới nào miễn là mô hình khôi phục của bạn đơn giản hoặc được ghi nhật ký hàng loạt. Tôi tin rằng tính năng này không được bật theo mặc định vì nó có thể làm giảm hiệu suất trên một số hệ thống. Bạn sẽ cần phải kiểm tra cẩn thận trước khi bật cờ theo dõi này. Tham chiếu được đề xuất của Microsoft vẫn xuất hiện là Hướng dẫn hiệu suất tải dữ liệu
Tác động I / O của việc ghi nhật ký tối thiểu theo cờ dấu vết 610
Khi bạn cam kết giao dịch tải hàng loạt được ghi lại tối thiểu, tất cả các trang được tải phải được xóa vào đĩa trước khi cam kết hoàn thành. Bất kỳ trang bị xóa nào không được bắt bởi một thao tác điểm kiểm tra trước đó có thể tạo ra rất nhiều I / O ngẫu nhiên. Tương phản điều này với một hoạt động được ghi lại đầy đủ, tạo ra I / O tuần tự trên ghi nhật ký thay vào đó và không yêu cầu các trang được tải phải được xóa vào đĩa tại thời điểm cam kết.
Nếu kịch bản tải của bạn là các thao tác chèn nhỏ trên btrees không vượt qua ranh giới điểm kiểm tra và bạn có hệ thống I / O chậm, sử dụng ghi nhật ký tối thiểu thực sự có thể làm chậm tốc độ chèn.
Theo như tôi có thể nói điều này không liên quan gì đến cờ dấu vết 610, mà là với bản ghi nhật ký tối thiểu. Tôi tin rằng trích dẫn trước đây về ROWS_PER_BATCH
điều chỉnh đã nhận được cùng một khái niệm.
Tóm lại, có lẽ bạn không thể làm gì nhiều để điều chỉnh BULK INSERT
. Tôi sẽ không quan tâm đến số lượng đọc mà bạn quan sát thấy với phần chèn của bạn. SQL Server sẽ báo cáo đọc bất cứ khi nào bạn chèn dữ liệu. Hãy xem xét những điều sau đây rất đơn giản INSERT
:
DROP TABLE IF EXISTS X_TABLE;
CREATE TABLE X_TABLE (
VAL VARCHAR(1000) NOT NULL
);
SET STATISTICS IO, TIME ON;
INSERT INTO X_TABLE WITH (TABLOCK)
SELECT REPLICATE('Z', 1000)
FROM dbo.GetNums(10000); -- generate 10000 rows
Đầu ra từ SET STATISTICS IO, TIME ON
:
Bảng 'X_TABLE'. Quét số 0, logic đọc 11,28
Tôi có 11,28 báo cáo đọc nhưng đó không phải là thông tin hành động. Đôi khi số lần đọc được báo cáo có thể được giảm bằng cách ghi nhật ký tối thiểu, nhưng tất nhiên sự khác biệt không thể được dịch trực tiếp thành mức tăng hiệu suất.