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

Thuộc tính ACID của Báo cáo &Giao dịch

[Xem chỉ mục cho toàn bộ chuỗi]

Bất kỳ lập trình viên nào cũng sẽ nói với bạn rằng viết mã đa luồng an toàn có thể khó. Nó đòi hỏi sự cẩn thận và hiểu biết tốt về các vấn đề kỹ thuật liên quan. Là một người làm cơ sở dữ liệu, bạn có thể nghĩ rằng những loại khó khăn và phức tạp này không áp dụng khi viết T-SQL. Vì vậy, có thể hơi sốc khi nhận ra rằng mã T-SQL cũng dễ bị tổn thương bởi các loại điều kiện chủng tộc và các rủi ro toàn vẹn dữ liệu khác thường liên quan đến lập trình đa luồng. Điều này đúng cho dù chúng ta đang nói về một câu lệnh T-SQL đơn lẻ hay một nhóm câu lệnh nằm trong một giao dịch rõ ràng.

Trọng tâm của vấn đề là thực tế là các hệ thống cơ sở dữ liệu cho phép nhiều giao dịch thực hiện cùng một lúc. Đây là một trạng thái nổi tiếng (và rất đáng mong đợi), tuy nhiên rất nhiều mã T-SQL sản xuất vẫn âm thầm giả định rằng dữ liệu cơ bản không thay đổi trong quá trình thực hiện một giao dịch hoặc một câu lệnh DML đơn lẻ như SELECT , INSERT , UPDATE , DELETE hoặc MERGE .

Ngay cả khi tác giả mã nhận thức được các tác động có thể xảy ra của việc thay đổi dữ liệu đồng thời, việc sử dụng các giao dịch rõ ràng thường được cho là cung cấp nhiều bảo vệ hơn so với thực tế. Những giả định và quan niệm sai lầm này có thể là tinh vi và chắc chắn có khả năng gây hiểu lầm ngay cả những người thực hành cơ sở dữ liệu có kinh nghiệm.

Bây giờ, có những trường hợp mà những vấn đề này sẽ không quan trọng nhiều theo nghĩa thực tế. Ví dụ:cơ sở dữ liệu có thể ở chế độ chỉ đọc hoặc có thể có một số đảm bảo chính hãng khác rằng không ai khác sẽ thay đổi dữ liệu cơ bản trong khi chúng tôi đang làm việc với nó. Tương tự, hoạt động được đề cập có thể không yêu cầu kết quả chính xác sửa; người tiêu dùng dữ liệu của chúng tôi có thể hoàn toàn hài lòng với một kết quả gần đúng (ngay cả một kết quả không đại diện cho trạng thái đã cam kết của cơ sở dữ liệu tại bất kỳ đúng lúc).

Các vấn đề về tiền tệ

Câu hỏi về sự giao thoa giữa các tác vụ thực thi đồng thời là một vấn đề quen thuộc đối với các nhà phát triển ứng dụng làm việc bằng các ngôn ngữ lập trình như C # hoặc Java. Các giải pháp rất nhiều và đa dạng, nhưng thường liên quan đến việc sử dụng hoạt động nguyên tử hoặc lấy tài nguyên loại trừ lẫn nhau (chẳng hạn như khóa ) trong khi một hoạt động nhạy cảm đang diễn ra. Nếu không thực hiện các biện pháp phòng ngừa thích hợp, kết quả có thể là dữ liệu bị hỏng, lỗi hoặc thậm chí có thể là sự cố hoàn toàn.

Nhiều khái niệm giống nhau (ví dụ:hoạt động nguyên tử và khóa) tồn tại trong thế giới cơ sở dữ liệu, nhưng tiếc là chúng thường có sự khác biệt quan trọng về ý nghĩa . Hầu hết mọi người trong cơ sở dữ liệu đều biết các thuộc tính ACID của các giao dịch cơ sở dữ liệu, trong đó A là viết tắt của nguyên tử . SQL Server cũng sử dụng khóa (và các thiết bị loại trừ lẫn nhau khác trong nội bộ). Cả hai thuật ngữ này đều không có nghĩa chính xác những gì mà một lập trình viên C # hoặc Java có kinh nghiệm sẽ mong đợi một cách hợp lý và nhiều chuyên gia cơ sở dữ liệu cũng hiểu nhầm về các chủ đề này (như một tìm kiếm nhanh bằng công cụ tìm kiếm yêu thích của bạn sẽ chứng minh).

Để nhắc lại, đôi khi những vấn đề này sẽ không phải là một mối quan tâm thực tế. Nếu bạn viết một truy vấn để đếm số lượng đơn đặt hàng đang hoạt động trong hệ thống cơ sở dữ liệu, điều quan trọng là nó như thế nào nếu số lượng bị lệch một chút? Hoặc nếu nó phản ánh trạng thái của cơ sở dữ liệu tại một thời điểm nào đó khác?

Các hệ thống thực thường phải đánh đổi giữa tính đồng thời và tính nhất quán (ngay cả khi nhà thiết kế không nhận thức được điều đó vào thời điểm đó - đã thông báo đánh đổi có lẽ là một động vật hiếm hơn). Các hệ thống thực thường hoạt động đủ tốt , với bất kỳ dị thường nào tồn tại trong thời gian ngắn hoặc được coi là không quan trọng. Người dùng nhìn thấy trạng thái không nhất quán trên một trang web thường sẽ giải quyết vấn đề bằng cách làm mới trang. Nếu sự cố được báo cáo, rất có thể sự cố sẽ bị đóng là Không thể tái tạo. Tôi không nói rằng đây là một trạng thái mong muốn, chỉ cần nhận ra rằng nó xảy ra.

Tuy nhiên, rất hữu ích khi hiểu các vấn đề đồng thời ở cấp độ cơ bản. Nhận thức được chúng cho phép chúng tôi viết đúng (hoặc đã thông báo đúng-đủ) T-SQL khi hoàn cảnh yêu cầu. Quan trọng hơn, nó cho phép chúng tôi tránh viết T-SQL có thể ảnh hưởng đến tính toàn vẹn logic của dữ liệu của chúng tôi.

Nhưng, SQL Server cung cấp đảm bảo ACID!

Đúng, nó có, nhưng chúng không phải lúc nào cũng như bạn mong đợi, và chúng không bảo vệ mọi thứ. Thường xuyên hơn không, con người đọc nhiều hơn về ACID hơn là chính đáng.

Các thành phần thường bị hiểu lầm nhất của từ viết tắt ACID là các từ Nguyên tử, Nhất quán và Cô lập - chúng ta sẽ đến với những từ này trong giây lát. Cái còn lại, Bền , đủ trực quan miễn là bạn nhớ nó chỉ áp dụng cho kiên trì (có thể phục hồi) người dùng dữ liệu.

Với tất cả những gì đã nói, SQL Server 2014 bắt đầu làm mờ đi phần nào ranh giới của thuộc tính Durable với việc giới thiệu độ bền bị trì hoãn chung và độ bền chỉ dùng lược đồ OLTP trong bộ nhớ. Tôi đề cập đến chúng chỉ cho đầy đủ, chúng ta sẽ không thảo luận thêm về các tính năng mới này. Hãy để chúng tôi chuyển sang các thuộc tính ACID có vấn đề hơn:

Thuộc tính nguyên tử

Nhiều ngôn ngữ lập trình cung cấp hoạt động nguyên tử có thể được sử dụng để bảo vệ khỏi các điều kiện chủng tộc và các hiệu ứng đồng thời không mong muốn khác, nơi nhiều luồng thực thi có thể truy cập hoặc sửa đổi cấu trúc dữ liệu được chia sẻ. Đối với nhà phát triển ứng dụng, hoạt động nguyên tử đi kèm với đảm bảo rõ ràng về sự cách ly hoàn toàn khỏi các tác động của quá trình xử lý đồng thời khác trong chương trình đa luồng.

Một tình huống tương tự nảy sinh trong thế giới cơ sở dữ liệu, nơi nhiều truy vấn T-SQL đồng thời truy cập và sửa đổi dữ liệu được chia sẻ (tức là cơ sở dữ liệu) từ các luồng khác nhau. Lưu ý rằng chúng ta không nói về các truy vấn song song ở đây; các truy vấn đơn luồng thông thường thường được lên lịch chạy đồng thời trong SQL Server trên các luồng nhân viên riêng biệt.

Thật không may, thuộc tính nguyên tử của các giao dịch SQL chỉ đảm bảo rằng các sửa đổi dữ liệu được thực hiện trong một giao dịch thành công hay thất bại với tư cách là một đơn vị . Không có gì hơn thế. Chắc chắn không có gì đảm bảo về việc cách ly hoàn toàn khỏi các tác động của quá trình xử lý đồng thời khác. Cũng lưu ý rằng tài sản giao dịch nguyên tử không nói gì về bất kỳ đảm bảo nào về việc đọc dữ liệu.

Các câu lệnh đơn

Cũng không có gì đặc biệt về một câu lệnh duy nhất trong SQL Server. Nơi có giao dịch rõ ràng (BEGIN TRAN...COMMIT TRAN ) không tồn tại, một câu lệnh DML duy nhất vẫn thực thi trong một giao dịch tự động gửi. Các đảm bảo ACID tương tự áp dụng cho một tuyên bố duy nhất và các giới hạn tương tự cũng áp dụng. Đặc biệt, một tuyên bố duy nhất không có đảm bảo đặc biệt rằng dữ liệu sẽ không thay đổi trong khi nó đang được xử lý.

Hãy xem xét truy vấn AdventureWorks đồ chơi sau:

SELECT
    TH.TransactionID,
    TH.ProductID,
    TH.ReferenceOrderID,
    TH.ReferenceOrderLineID,
    TH.TransactionDate,
    TH.TransactionType,
    TH.Quantity,
    TH.ActualCost
FROM Production.TransactionHistory AS TH
WHERE TH.ReferenceOrderID =
(
    SELECT TOP (1) 
        TH2.ReferenceOrderID
    FROM Production.TransactionHistory AS TH2
    WHERE TH2.TransactionType = N'P'
    ORDER BY 
        TH2.Quantity DESC,
        TH2.ReferenceOrderID ASC
);

Truy vấn nhằm mục đích hiển thị thông tin về Đơn hàng được xếp hạng đầu tiên theo Số lượng. Kế hoạch thực hiện như sau:

Các hoạt động chính trong kế hoạch này là:

  1. Quét bảng để tìm các hàng có loại giao dịch bắt buộc
  2. Tìm ID đơn hàng sắp xếp cao nhất theo đặc điểm kỹ thuật trong truy vấn con
  3. Tìm các hàng (trong cùng một bảng) với ID đặt hàng đã chọn bằng cách sử dụng chỉ mục không phân biệt
  4. Tra cứu dữ liệu cột còn lại bằng cách sử dụng chỉ mục được phân nhóm

Bây giờ, hãy tưởng tượng rằng một người dùng đồng thời sửa đổi Đơn đặt hàng 495, thay đổi Loại giao dịch của nó từ P thành W và cam kết thay đổi đó với cơ sở dữ liệu. May mắn thay, sửa đổi này được thực hiện trong khi truy vấn của chúng tôi đang thực hiện thao tác sắp xếp (bước 2).

Khi quá trình sắp xếp hoàn tất, chỉ mục tìm kiếm ở bước 3 sẽ tìm các hàng có ID đơn đặt hàng đã chọn (xảy ra là 495) và Tra cứu khóa ở bước 4 tìm nạp các cột còn lại từ bảng cơ sở (trong đó Loại giao dịch bây giờ là W) .

Chuỗi sự kiện này có nghĩa là truy vấn của chúng tôi tạo ra một kết quả dường như không thể xảy ra:

Thay vì tìm các đơn đặt hàng có loại giao dịch P như truy vấn đã chỉ định, kết quả hiển thị loại giao dịch W.

Nguyên nhân gốc rễ rất rõ ràng:truy vấn của chúng tôi mặc nhiên cho rằng dữ liệu không thể thay đổi trong khi truy vấn câu lệnh đơn của chúng tôi đang diễn ra. Cửa sổ cơ hội trong trường hợp này tương đối lớn do loại chặn, nhưng nói chung, cùng một loại điều kiện chủng tộc có thể xảy ra ở bất kỳ giai đoạn thực thi truy vấn nào. Đương nhiên, rủi ro thường cao hơn khi mức độ sửa đổi đồng thời tăng lên, các bảng lớn hơn và nơi các toán tử chặn xuất hiện trong kế hoạch truy vấn.

Một huyền thoại dai dẳng khác trong cùng một lĩnh vực chung là MERGE được ưu tiên hơn INSERT riêng biệt , UPDATEDELETE câu lệnh vì câu lệnh đơn MERGE là nguyên tử. Đó là điều vô nghĩa, tất nhiên. Chúng ta sẽ quay lại với kiểu lý luận này ở phần sau của loạt bài.

Thông báo chung tại thời điểm này là trừ khi các bước rõ ràng được thực hiện để đảm bảo ngược lại, các hàng dữ liệu và mục nhập chỉ mục có thể thay đổi, di chuyển vị trí hoặc biến mất hoàn toàn bất kỳ lúc nào trong quá trình thực thi. Một bức tranh tinh thần về sự thay đổi liên tục và ngẫu nhiên trong cơ sở dữ liệu là điều tốt cần ghi nhớ khi viết các truy vấn T-SQL.

Thuộc tính nhất quán

Từ thứ hai từ từ viết tắt ACID cũng có một loạt các cách hiểu có thể xảy ra. Trong cơ sở dữ liệu SQL Server, tính nhất quán có nghĩa là chỉ rằng một giao dịch rời khỏi cơ sở dữ liệu ở trạng thái không vi phạm bất kỳ ràng buộc hoạt động nào. Điều quan trọng là phải đánh giá đầy đủ mức độ giới hạn của tuyên bố đó:ACID duy nhất đảm bảo tính toàn vẹn của dữ liệu và tính nhất quán logic là những điều kiện được cung cấp bởi các ràng buộc hoạt động.

SQL Server cung cấp một số ràng buộc hạn chế để thực thi tính toàn vẹn logic, bao gồm PRIMARY KEY , FOREIGN KEY , CHECK , UNIQUENOT NULL . Tất cả những điều này đều được đảm bảo hài lòng tại thời điểm giao dịch được cam kết. Ngoài ra, SQL Server đảm bảo vật lý tất nhiên là tính toàn vẹn của cơ sở dữ liệu mọi lúc.

Các ràng buộc tích hợp không phải lúc nào cũng đủ để thực thi tất cả các quy tắc kinh doanh và toàn vẹn dữ liệu mà chúng tôi muốn. Chắc chắn là có thể sáng tạo với các phương tiện tiêu chuẩn, nhưng chúng nhanh chóng trở nên phức tạp và có thể dẫn đến việc lưu trữ dữ liệu trùng lặp.

Do đó, hầu hết các cơ sở dữ liệu thực đều chứa ít nhất một số quy trình T-SQL được viết để thực thi các quy tắc bổ sung, ví dụ như trong các thủ tục và trình kích hoạt được lưu trữ. Trách nhiệm đảm bảo mã này hoạt động chính xác hoàn toàn thuộc về tác giả - thuộc tính Nhất quán không cung cấp biện pháp bảo vệ cụ thể nào.

Để nhấn mạnh điểm này, các ràng buộc giả được viết trong T-SQL phải hoạt động chính xác cho dù có thể xảy ra những sửa đổi đồng thời nào. Một nhà phát triển ứng dụng có thể bảo vệ một hoạt động nhạy cảm như vậy bằng một câu lệnh khóa. Điều gần nhất mà các lập trình viên T-SQL có được với cơ sở đó cho thủ tục lưu trữ rủi ro và mã kích hoạt là sp_getapplock tương đối hiếm khi được sử dụng hệ thống lưu trữ thủ tục. Điều đó không có nghĩa là nó là lựa chọn duy nhất hoặc thậm chí được ưu tiên, chỉ là nó tồn tại và có thể là lựa chọn đúng trong một số trường hợp.

Thuộc tính cách ly

Đây là đặc tính giao dịch ACID dễ bị hiểu nhầm nhất.

Về nguyên tắc, một hoàn toàn biệt lập giao dịch thực thi như là tác vụ duy nhất thực thi đối với cơ sở dữ liệu trong suốt thời gian tồn tại của nó. Các giao dịch khác chỉ có thể bắt đầu sau khi giao dịch hiện tại kết thúc hoàn toàn (tức là đã cam kết hoặc quay trở lại). Được thực hiện theo cách này, một giao dịch sẽ thực sự là một hoạt động nguyên tử , theo nghĩa chặt chẽ rằng một người không sử dụng cơ sở dữ liệu sẽ mô tả cụm từ này.

Trong thực tế, các giao dịch cơ sở dữ liệu hoạt động thay thế với mức độ cô lập được chỉ định bởi mức cô lập giao dịch hiệu quả hiện tại (áp dụng tương tự cho các câu lệnh độc lập, hãy nhớ). Thỏa hiệp này ( mức độ của sự cô lập) là hệ quả thực tế của sự đánh đổi giữa tính đồng thời và tính đúng đắn đã được đề cập trước đó. Một hệ thống xử lý từng giao dịch theo đúng nghĩa đen, không có sự chồng chéo về thời gian, sẽ cung cấp sự cô lập hoàn toàn nhưng thông lượng tổng thể của hệ thống có thể sẽ kém.

Lần tới

Phần tiếp theo của loạt bài này sẽ tiếp tục kiểm tra các vấn đề đồng thời, thuộc tính ACID và cách ly giao dịch với một cái nhìn chi tiết về mức cách ly có thể tuần tự hóa, một ví dụ khác về điều gì đó có thể không có nghĩa như bạn nghĩ.

[Xem chỉ mục cho toàn bộ chuỗi]


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Poker, Blackjack, Belot và Préférence có liên quan gì với Cơ sở dữ liệu?

  2. Hình dung điểm tới hạn với Plan Explorer

  3. Vấn đề Halloween - Phần 2

  4. Bất ngờ về hiệu suất và giả định:BẬT SỐ KHOẢN

  5. KNIME