Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Chạy các truy vấn lớn trong MS SQL nền

Theo quan điểm của tôi, máy chủ của bạn có vấn đề nghiêm trọng về hiệu suất. Ngay cả khi chúng tôi giả định rằng không có bản ghi nào trong truy vấn

select some_col with (nolock) where id_col between 57000000 and 57001000

nằm trong bộ nhớ, không nên mất 21 giây để đọc tuần tự một vài trang từ đĩa (chỉ mục nhóm của bạn trên id_col sẽ không bị phân mảnh nếu đó là danh tính tự động và bạn đã không làm điều gì đó ngu ngốc như thêm "desc" định nghĩa chỉ mục).

Nhưng nếu bạn không thể / sẽ không khắc phục được điều đó, lời khuyên của tôi là nên cập nhật trong các gói nhỏ như 100-1000 bản ghi cùng một lúc (tùy thuộc vào lượng thời gian mà hàm tra cứu tiêu tốn). Một lần cập nhật / giao dịch sẽ không quá 30 giây.

Bạn thấy mỗi bản cập nhật giữ một khóa độc quyền trên tất cả các bản ghi mà nó đã sửa đổi cho đến khi giao dịch hoàn tất. Nếu bạn không sử dụng một giao dịch rõ ràng, mỗi câu lệnh được thực thi trong một ngữ cảnh giao dịch tự động, duy nhất, do đó, các khóa sẽ được giải phóng khi câu lệnh cập nhật được thực hiện.

Nhưng bạn vẫn có thể gặp bế tắc theo cách đó, tùy thuộc vào những gì các quy trình khác thực hiện. Nếu họ cũng sửa đổi nhiều bản ghi cùng một lúc hoặc thậm chí nếu họ tập hợp và giữ các khóa đã đọc trên nhiều hàng, bạn có thể gặp phải tình trạng deadlock.

Để tránh bế tắc, câu lệnh cập nhật của bạn cần phải khóa tất cả các bản ghi mà nó sẽ sửa đổi cùng một lúc. Cách để thực hiện việc này là đặt câu lệnh cập nhật duy nhất (chỉ với một số hàng bị giới hạn bởi id_col) trong một giao dịch có thể tuần tự hóa như

IF @@TRANCOUNT > 0
  -- Error: You are in a transaction context already

SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

-- Insert Loop here to work "x" through the id range
  BEGIN TRANSACTION
    UPDATE SOMETABLE
      SET [some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column))
      WHERE [some_col] = 243 AND id_col BETWEEN x AND x+500 -- or whatever keeps the update in the small timerange
  COMMIT
-- Next loop

-- Get all new records while you where running the loop. If these are too many you may have to paginate this also:
BEGIN TRANSACTION
  UPDATE SOMETABLE
    SET [some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column))
    WHERE [some_col] = 243 AND id_col >= x
COMMIT

Đối với mỗi bản cập nhật, điều này sẽ thực hiện một khóa cập nhật / khóa phạm vi khóa độc quyền trên các bản ghi đã cho (nhưng chỉ chúng, vì bạn giới hạn cập nhật thông qua khóa chỉ mục nhóm). Nó sẽ đợi mọi cập nhật khác trên cùng một bản ghi hoàn tất, sau đó khóa nó (gây ra chặn cho tất cả các giao dịch khác, nhưng vẫn chỉ cho các bản ghi đã cho), sau đó cập nhật các bản ghi và giải phóng khóa.

Câu lệnh bổ sung cuối cùng rất quan trọng, bởi vì nó sẽ khóa phạm vi khóa lên đến "vô cùng" và do đó ngăn chặn thậm chí chèn vào cuối phạm vi trong khi câu lệnh cập nhật chạy.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sự cố sao chép giao dịch SQL Server

  2. Cách xóa các bản ghi KHÔNG VÀO

  3. Thực thi gói SSIS dưới dạng công việc SQLAgent

  4. Cách khắc phục:JSON_VALUE Trả về NULL với chuỗi dài (SQL Server)

  5. Visual Studio 2008/2010 &SQL Server 2008 trên Windows 7 Home Premium