Tại sao các bảng tạm thời ghi lại thời gian bắt đầu của giao dịch?


8

Khi cập nhật một hàng trong bảng tạm thời, các giá trị cũ cho hàng được lưu trữ trong bảng lịch sử với thời gian bắt đầu giao dịch là SysEndTime. Các giá trị mới trong bảng hiện tại sẽ có thời gian bắt đầu giao dịch là SysStartTime.

SysStartTimeSysEndTimedatetime2các cột được sử dụng bởi các bảng tạm thời để ghi lại khi một hàng là phiên bản hiện tại. Thời gian bắt đầu giao dịch là thời gian giao dịch chứa các bản cập nhật bắt đầu.

BOL nói:

Thời gian được ghi trong các cột datetime2 của hệ thống được dựa trên thời gian bắt đầu của chính giao dịch. Ví dụ: tất cả các hàng được chèn trong một giao dịch sẽ có cùng thời gian UTC được ghi trong cột tương ứng với thời điểm bắt đầu của thời gian HỆ THỐNG.

Ví dụ: Tôi bắt đầu cập nhật tất cả các hàng trong bảng Đơn hàng của mình tại 20160707 11:00:00và giao dịch mất 5 phút để chạy. Điều này tạo ra một hàng trong bảng lịch sử cho mỗi hàng với SysEndTimenhư 20160707 11:00:00. Tất cả các hàng trong bảng hiện nay sẽ có một SysStartTimesố 20160707 11:00:00.

Nếu ai đó thực hiện một truy vấn tại 20160707 11:01:00(trong khi bản cập nhật đang chạy), họ sẽ thấy các giá trị cũ (giả sử mức đọc cách ly được cam kết mặc định).

Nhưng nếu có ai đó sử dụng AS OFcú pháp để truy vấn bảng tạm thời như lúc 20160707 11:01:00đó họ sẽ thấy các giá trị mới bởi vì giá trị của chúng SysStartTimesẽ là 20160707 11:00:00.

Đối với tôi điều này có nghĩa là nó không hiển thị các hàng như lúc đó. Nếu nó sử dụng thời gian kết thúc giao dịch, vấn đề sẽ không tồn tại.

Câu hỏi: Đây có phải là do thiết kế? Tui bỏ lỡ điều gì vậy?

Lý do duy nhất tôi có thể nghĩ rằng nó sử dụng thời gian bắt đầu giao dịch là vì đó là lần duy nhất 'được biết' khi giao dịch bắt đầu. Nó không biết khi nào giao dịch sẽ kết thúc khi nó bắt đầu và sẽ mất thời gian để áp dụng thời gian kết thúc vào cuối, điều đó sẽ làm mất hiệu lực thời gian kết thúc mà nó được áp dụng. Điều này có nghĩa không?

Điều này sẽ cho phép bạn tạo lại vấn đề.


1
Bạn đã trả lời câu hỏi của riêng mình, nếu bạn sử dụng thời gian kết thúc giao dịch, bạn có một bản cập nhật khác vào cuối giao dịch: Cập nhật kết thúc 20160707 11:04:58và bây giờ bạn cập nhật tất cả các hàng với dấu thời gian đó. Nhưng bản cập nhật này cũng chạy trong vài giây và kết thúc vào lúc này 20160707 11:05:02, dấu thời gian nào là kết thúc chính xác của giao dịch? Hoặc giả sử bạn đã sử dụng Read Uncommitedtại 20160707 11:05:00và đã trả lại hàng, nhưng sau đó AS OFkhông hiển thị chúng.
vào

@dnoeth Vâng Tôi đoán 'câu hỏi' này là một sự làm rõ hơn về lý thuyết của tôi.
James Anderson

Tôi đã không đi sâu vào triển khai SQL Server, nhưng Teradata có các bảng hai thời gian trong nhiều năm và tôi luôn khuyên bạn nên đọc Nghiên cứu điển hình này từ Richard Snodgrass (người đã "phát minh" các truy vấn tạm thời), dựa trên cú pháp tiền ANSI SQL của Teradata , nhưng các khái niệm là như nhau: cs.ulb.ac.be/public/_media/teaching/infoh415/ Kẻ
dnoeth

Câu trả lời:


4

Ý tưởng là để theo dõi thời gian hợp lý so với thời gian vật lý. Logic chỉ đơn giản đề cập đến những gì người dùng / ứng dụng mong đợi thời gian chèn / cập nhật / xóa. Thực tế là hoạt động DML có thể mất một lúc vì bất kỳ lý do gì, không có ý nghĩa hoặc thậm chí dễ dàng được xác định và hiểu bởi người dùng. Nếu bạn đã từng phải giải thích khóa và tranh chấp chốt với một kế toán viên (tôi có), thì đó là một tình huống tương đương.

Chẳng hạn, khi Bob "nói" với ứng dụng rằng tất cả nhân viên trong bộ phận của Bob sẽ bắt đầu kiếm được 42 đô la / phút vào lúc đó 20160707 11:00:00, Bob (và nhân viên của anh ấy) hy vọng mức lương của mọi người hiện được tính ở mức 42 đô la / phút kể từ thời điểm đó. Bob không quan tâm rằng để thực hiện được điều này, ứng dụng phải thực hiện 2 lần đọc và 6 lần ghi trên cơ sở dữ liệu cho mỗi nhân viên và các tệp nhật ký + dữ liệu của họ nằm trên một loạt các ổ đĩa RAID-5 SATA II nên mất khoảng 7 phút để hoàn thành nhiệm vụ cho tất cả 256 nhân viên của Bob. Bob, kế toán của anh ấy và người quản lý tiền lương quan tâm rằng tất cả nhân viên của anh ấy được trả 42 đô la / phút bắt đầu 20160707 11:00:00. Khác, các nhân viên đã được cập nhật tại 20160707 11:00:01sẽ hơi khó chịu trong khi những người có hồ sơ được cập nhật 20160707 11:00:07sẽ tập trung bên ngoài bộ phận biên chế.

Có các trường hợp sử dụng hợp lệ để theo dõi thời gian vật lý như gỡ lỗi và pháp y nhưng với người dùng cuối, nó thường vô nghĩa. Tlog giữ cả thông tin đặt hàng và thời gian cho từng thao tác ghi (trong số những thứ khác) để nó ở đó nếu bạn biết cách xem.


Điểm hay. Tôi đoán công nghệ này chỉ phù hợp với một số trường hợp sử dụng nhất định như trường hợp bạn đề cập. Vì những lý do tôi nêu ở trên, có vẻ như nó sẽ không phù hợp để sử dụng để theo dõi giá trị hoặc giá trị cổ phiếu có thể thay đổi trong khoảng thời gian rất ngắn.
James Anderson

Thật ra là không. Đó là một vấn đề hoàn hảo và quy mô. Các bảng tạm thời vẫn hoạt động nếu bạn cần theo dõi lịch sử thời gian của giá cổ phiếu. Bạn chỉ cần đảm bảo các hạt dao rất nhỏ và có thể hoàn thành trong một cửa sổ rất nhỏ. Khác, các thay đổi tiếp theo sẽ bị chặn và nếu tốc độ đến đủ cao, thời gian chờ xảy ra và mất dữ liệu nếu ứng dụng không thể xử lý thử lại. Nếu bạn chạy DB tắt fusion IO hoặc với các bảng được tối ưu hóa bộ nhớ, bạn có thể dễ dàng xử lý hàng chục nghìn lần chèn mỗi giây đến hơn một trăm nghìn mỗi giây.
SQLmojoe

3

Tôi tin rằng đây thực sự là một lỗ hổng thiết kế, mặc dù không dành riêng cho SQL Server 2016, vì tất cả các triển khai khác của các bảng tạm thời (theo như tôi biết) đều có cùng một lỗ hổng. Các vấn đề có thể phát sinh với các bảng thời gian vì điều này là khá nghiêm trọng; kịch bản trong ví dụ của bạn là nhẹ so với những gì có thể đi sai nói chung:

Tham chiếu khóa ngoại bị hỏng : Giả sử chúng ta có hai bảng tạm thời, với bảng A có tham chiếu khóa ngoại đến bảng B. Bây giờ giả sử chúng ta có hai giao dịch, cả hai đều chạy ở mức cách ly READ CAMITED: giao dịch 1 bắt đầu trước giao dịch 2, giao dịch 2 chèn một hàng vào bảng B và cam kết, sau đó giao dịch 1 chèn một hàng trong bảng A với tham chiếu đến hàng mới được thêm vào của B. Vì việc thêm hàng mới vào B đã được cam kết, ràng buộc khóa ngoại được thỏa mãn và giao dịch 1 có thể cam kết thành công. Tuy nhiên, nếu chúng ta xem cơ sở dữ liệu "NHƯ VẬY" vào khoảng thời gian giữa khi giao dịch 1 bắt đầu và khi giao dịch 2 bắt đầu, thì chúng ta sẽ thấy bảng A có tham chiếu đến một hàng B không tồn tại. Vì vậy, trong trường hợp này,bảng tạm thời cung cấp một cái nhìn không nhất quán về cơ sở dữ liệu . Tất nhiên đây không phải là mục đích của tiêu chuẩn SQL: 2011, trong đó nêu rõ,

Các hàng hệ thống lịch sử trong một bảng được phiên bản hệ thống tạo thành các ảnh chụp nhanh bất biến của quá khứ. Bất kỳ ràng buộc nào có hiệu lực khi hàng hệ thống lịch sử được tạo sẽ được kiểm tra khi hàng đó là hàng hệ thống hiện tại, do đó không bao giờ cần phải thực thi các ràng buộc trên các hàng hệ thống lịch sử.

Khóa chính không phải là duy nhất : Giả sử chúng ta có một bảng có khóa chính và hai giao dịch, cả hai đều ở mức cách ly READ CAMEDED, trong đó xảy ra các trường hợp sau: Sau khi giao dịch 1 bắt đầu nhưng trước khi chạm vào bảng này, giao dịch 2 sẽ xóa một số nhất định hàng của bảng và cam kết. Sau đó, giao dịch 1 chèn một hàng mới có cùng khóa chính với hàng đã bị xóa. Điều này diễn ra tốt đẹp, nhưng khi bạn nhìn vào bảng NHƯ một khoảng thời gian giữa khi giao dịch 1 bắt đầu và khi giao dịch 2 bắt đầu, chúng ta sẽ thấy hai hàng có cùng khóa chính.

Lỗi về các cập nhật đồng thời : Giả sử chúng ta có một bảng và hai giao dịch cả hai cập nhật cùng một hàng trong đó, một lần nữa ở mức cô lập ĐỌC. Giao dịch 1 bắt đầu trước, nhưng giao dịch 2 là lần đầu tiên cập nhật hàng. Giao dịch 2 sau đó cam kết và giao dịch 1 sau đó thực hiện cập nhật khác trên hàng và cam kết. Tất cả đều ổn, ngoại trừ nếu đây là bảng tạm thời, khi thực hiện cập nhật trong giao dịch 1 khi hệ thống chèn hàng yêu cầu vào bảng lịch sử, SysStartTime được tạo sẽ là thời gian bắt đầu giao dịch 2, trong khi SysEndTime sẽ là thời gian bắt đầu của giao dịch 1, không phải là khoảng thời gian hợp lệ vì SysEndTime sẽ ở trước SysStartTime. Trong trường hợp này, SQL Server sẽ đưa ra lỗi và khôi phục giao dịch (ví dụ: xemthảo luận này ). Điều này rất khó chịu, vì ở cấp độ cách ly READ CAMITED, người ta sẽ không mong đợi rằng các vấn đề tương tranh sẽ dẫn đến những thất bại hoàn toàn, điều đó có nghĩa là các ứng dụng không nhất thiết phải được chuẩn bị để thử lại. Cụ thể, điều này trái với "bảo đảm" trong tài liệu của Microsoft:

Hành vi này đảm bảo rằng các ứng dụng cũ của bạn sẽ tiếp tục hoạt động khi bạn bật phiên bản hệ thống trên các bảng sẽ được hưởng lợi từ phiên bản. ( liên kết )

Các triển khai khác của bảng tạm thời đã xử lý tình huống này (hai giao dịch đồng thời cập nhật cùng một hàng) bằng cách cung cấp tùy chọn tự động "điều chỉnh" dấu thời gian nếu chúng không hợp lệ (xem tại đâytại đây ). Đây là một cách giải quyết xấu, vì nó có hậu quả đáng tiếc là phá vỡ tính nguyên tử của các giao dịch, vì các báo cáo khác trong cùng một giao dịch sẽ không được điều chỉnh dấu thời gian theo cùng một cách; tức là, với cách giải quyết này, nếu chúng ta xem cơ sở dữ liệu "NHƯ" một số điểm nhất định thì chúng ta có thể thấy các giao dịch được thực hiện một phần.

Giải pháp: Bạn đã đề xuất giải pháp rõ ràng, đó là cho việc triển khai sử dụng thời gian kết thúc giao dịch (tức là thời gian cam kết) thay vì thời gian bắt đầu. Đúng, khi chúng tôi thực hiện một tuyên bố ở giữa một giao dịch, không thể biết thời gian cam kết sẽ là bao nhiêu (vì trong tương lai, hoặc thậm chí có thể không tồn tại nếu giao dịch được thực hiện trở lại). Nhưng điều này không có nghĩa là giải pháp không thể thực hiện được; nó chỉ phải được thực hiện theo một cách khác Ví dụ: khi thực hiện câu lệnh CẬP NHẬT hoặc XÓA, khi tạo hàng lịch sử, hệ thống chỉ có thể đặt ID giao dịch hiện tại thay vì thời gian bắt đầu và sau đó ID có thể được chuyển đổi thành dấu thời gian sau đó bởi hệ thống sau khi giao dịch được thực hiện .

Trong ngữ cảnh của loại triển khai này, tôi sẽ đề xuất rằng trước khi giao dịch được thực hiện, bất kỳ hàng nào được thêm vào bảng lịch sử sẽ không hiển thị cho người dùng. Từ góc độ người dùng, đơn giản là các hàng này sẽ được thêm vào (với dấu thời gian cam kết) tại thời điểm cam kết. Đặc biệt, nếu giao dịch không bao giờ cam kết thành công thì nó sẽ không bao giờ xuất hiện trong lịch sử. Tất nhiên, điều này không phù hợp với tiêu chuẩn SQL: 2011 mô tả các phần chèn vào lịch sử (bao gồm cả dấu thời gian) xảy ra tại thời điểm các câu lệnh CẬP NHẬT và XÓA (trái ngược với thời điểm cam kết). Nhưng tôi không nghĩ rằng điều này thực sự quan trọng, xem xét rằng tiêu chuẩn chưa bao giờ được thực hiện đúng (và có thể không bao giờ được thực hiện) do các vấn đề được mô tả ở trên,

Từ quan điểm hiệu suất, có vẻ như hệ thống không mong muốn phải quay lại và xem lại các hàng lịch sử để điền vào dấu thời gian cam kết. Nhưng tùy thuộc vào cách thực hiện, chi phí có thể khá thấp. Tôi không thực sự quen thuộc với cách SQL Server hoạt động bên trong, nhưng PostgreQuery chẳng hạn sử dụng nhật ký ghi trước, điều này làm cho nó nếu nhiều bản cập nhật được thực hiện trên cùng một phần của bảng, thì các bản cập nhật đó được hợp nhất để dữ liệu chỉ cần được ghi một lần vào các trang bảng vật lý - và điều đó thường được áp dụng trong kịch bản này. Trong bất kỳ trường hợp nào,

Tất nhiên, vì (theo như tôi biết) loại hệ thống này chưa bao giờ được triển khai, tôi không thể nói chắc chắn rằng nó sẽ hoạt động - có thể tôi đang thiếu thứ gì đó - nhưng tôi không thấy lý do nào cả tại sao nó không thể làm việc


0

Tại thời điểm bạn cam kết giao dịch, tất cả dữ liệu phải được ghi bên trong các trang dữ liệu (trong bộ nhớ và trên đĩa trong tệp nhật ký). Bao gồm SysStartTimeSysEndTimecột. Làm thế nào bạn có thể biết thời gian kết thúc giao dịch trước khi nó thực sự hoàn thành?

Trừ khi bạn có thể dự đoán tương lai, sử dụng thời gian bắt đầu giao dịch là lựa chọn duy nhất, ngay cả khi nó có thể ít trực quan hơn.

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.