Trong khi viết một số truy vấn SQL cho PostgreSQL, tôi phát hiện một số hành vi bất thường, mà tôi thấy hơi đáng lo ngại.Kết quả truy vấn PostgreSQL sai với khóa rõ ràng và giao dịch đồng thời
Giả sử chúng ta có bảng "test" sau:
+----+-------+---------------------+
| id | value | created_at |
+----+-------+---------------------+
| 1 | A | 2014-01-01 00:00:00 |
| 2 | A | 2014-01-02 00:00:00 |
| 3 | B | 2014-01-03 00:00:00 |
| 4 | B | 2014-01-04 00:00:00 |
| 5 | A | 2014-01-05 00:00:00 |
| 6 | B | 2014-01-06 00:00:00 |
| 7 | A | 2014-01-07 00:00:00 |
| 8 | B | 2014-01-08 00:00:00 |
+----+-------+---------------------+
Có hai giao dịch, A và B, chạy song song.
A: begin; /* Begin transaction A */
B: begin; /* Begin transaction B */
A: select * from test where id = 1 for update; /* Lock one row */
B: select * from test where value = 'B' order by created_at limit 3 for update; /* This query returns immediately since it does not need to return row with id=1 */
B: select * from test where value = 'A' order by created_at limit 3 for update; /* This query blocks because row id=1 is locked by transaction A */
A: update test set created_at = '2014-01-09 00:00:00' where id = 1; /* Modify the locked row */
A: commit;
Ngay sau khi giao dịch A cam kết và giải phóng hàng với id = 1, truy vấn chặn giao dịch B trả về kết quả sau đây:
+----+-------+---------------------+
| id | value | created_at |
+----+-------+---------------------+
| 1 | A | 2014-01-09 00:00:00 |
| 2 | A | 2014-01-02 00:00:00 |
| 5 | A | 2014-01-05 00:00:00 |
+----+-------+---------------------+
Những hàng được chắc chắn nhất không sắp xếp theo "created_at "và hàng có id = 1 không được nằm trong số các hàng được trả lại. Thực tế là các giao dịch A và B đang chạy đồng thời, đã dẫn đến kết quả sai trong giao dịch B, điều này sẽ không xảy ra nếu các giao dịch đã được thực hiện sau giao dịch kia. Điều này có vẻ giống như một sự vi phạm giao dịch cô lập.
Đây có phải là lỗi không?
Nếu đây không phải là lỗi và những kết quả này được mong đợi, điều này có nghĩa là gì về độ tin cậy của kết quả do DB trả về? Nếu tôi có một môi trường đồng thời cao và mã tiếp theo dựa vào các hàng thực sự được sắp xếp theo ngày, sẽ có lỗi.
Tuy nhiên, nếu chúng tôi chạy cùng một chuỗi các lệnh như trên, nhưng thay thế các báo cáo cập nhật như sau:
update test set value = 'B', created_at = '2014-01-09 00:00:00' where id = 1;
... sau đó truy vấn chặn trả về kết quả chính xác:
+----+-------+---------------------+
| id | value | created_at |
+----+-------+---------------------+
| 2 | A | 2014-01-02 00:00:00 |
| 5 | A | 2014-01-05 00:00:00 |
| 7 | A | 2014-01-07 00:00:00 |
+----+-------+---------------------+
Trong trường hợp này, truy vấn bị chặn có được thực thi hai lần vì kết quả ban đầu của nó bị vô hiệu không?
Tôi quan tâm nhất đến PostgreSQL, nhưng tôi cũng muốn biết nếu đây là trường hợp với RDBMS khác hỗ trợ khóa cấp hàng, chẳng hạn như Oracle, SQL Server và MySQL.
Trong MySQL, lựa chọn đầu tiên trong Phiên b đã bị chặn và đợi cho đến phiên A cam kết hoặc cuộn lại. Trong Oracle, điều này khó tái tạo vì không có mệnh đề 'LIMIT' và cách tiếp cận thông thường sử dụng một bảng dẫn xuất với' rownum' và thứ tự bằng cách thay đổi hoàn toàn ý nghĩa của truy vấn. –