"Không thể commit index" hoặc cách bơm dữ liệu từ cơ sở dữ liệu được khôi phục một phần (không nhất quán)
Alexey Kovyazin, cập nhật lần cuối 30-Tháng 3-2014
Sau khi sửa lỗi hỏng dữ liệu, thường gặp lỗi “Cannot commit index” ở bước khôi phục. Trong Firebird 2.0 trở lên, điều này xuất hiện như một cảnh báo và cơ sở dữ liệu sẽ không được đưa trực tuyến; trong Firebird 1.0-1.5 và InterBase, điều này xảy ra như một lỗi rất khó chịu làm dừng quá trình khôi phục (thật ấn tượng khi thấy lỗi này ở cuối quá trình khôi phục cơ sở dữ liệu 200Gb).
Nguyên nhân của lỗi “Cannot commit index..” là rõ ràng: sự hỏng hóc ảnh hưởng đến tính toàn vẹn tham chiếu của cơ sở dữ liệu, và các bản ghi biến mất một cách kỳ diệu (từ quan điểm của máy chủ).
Ví dụ, bạn có bảng “Customers” và bảng liên quan “Orders” được tham chiếu bởi khóa ngoại. Nếu không có sự hỏng hóc, không thể vi phạm khóa ngoại và xóa bản ghi từ Customers mà không xóa trước tất cả các đơn hàng tham chiếu đến khách hàng cụ thể đó. Sự hỏng hóc ảnh hưởng đến tệp cơ sở dữ liệu ở mức thấp và xóa trực tiếp các bản ghi. Thật là một bất ngờ thú vị cho máy chủ khi thấy các liên kết chưa được giải quyết đến các bản ghi chính từ các bản ghi khóa ngoại.
Ở đây tôi cần thêm một mẹo về quá trình khôi phục: engine khôi phục tất cả các bảng với chỉ mục chưa được kích hoạt (điều này làm cho việc điền các bảng với bản ghi nhanh hơn nhiều), và sau đó bắt đầu kích hoạt (tức là, xây dựng) các chỉ mục từng cái một. Điều đó có nghĩa là tất cả dữ liệu đã có trong cơ sở dữ liệu khi quá trình khôi phục bắt đầu bước tạo chỉ mục và bạn thấy lỗi “Cannot commit index..”.
Chà, mong muốn đầu tiên khi bạn thấy lỗi “Cannot commit index” là xóa ràng buộc khóa ngoại tương ứng để cho phép khôi phục hoàn tất. Câu hỏi là chúng ta sẽ làm gì với cơ sở dữ liệu không nhất quán nhưng đã khôi phục thành công: khóa ngoại bị xóa có thể là một phần quan trọng của logic kinh doanh.
Có 2 cách tiếp cận ở đây: tái tạo dữ liệu bị thiếu hoặc loại bỏ dữ liệu không nhất quán. Hãy xem điều đó có nghĩa là gì trong ví dụ Customers-Orders ở trên.
Tái tạo dữ liệu bị thiếu
Vì vậy, bạn đã quyết định rằng bạn cần tái tạo các Customers bị thiếu cho các Orders không nhất quán. Theo cách này, bạn cần xác định các ID bị mất. Thông thường tôi sử dụng truy vấn SQL như thế này (tôi nghĩ sẽ dễ dàng để điều chỉnh cho phù hợp):
SELECT O.Customer_ID FROM ORDERS O WHERE NOT EXISTS ( SELECT C.Customer_ID FROM CUSTOMERS C WHERE O.Customer_ID=C.Customer_ID)
Sau đó, bạn có thể chèn thủ công các bản ghi với danh sách các khóa chính bị thiếu, và chạy sao lưu/khôi phục lại.
Bơm dữ liệu nhất quán
Nếu bạn nghĩ rằng việc mất các bản ghi không nhất quán là chấp nhận được, bạn có thể bơm tất cả dữ liệu từ cơ sở dữ liệu đã khôi phục một phần sang cơ sở dữ liệu trống và chỉ bỏ qua các bản ghi không nhất quán, sử dụng cách tiếp cận sau:
-
Tải xuống công cụ miễn phí IBDataPump http://www.clevercomponents.com/demo/datapump/IBPump.zip
-
Chỉ tạo cơ sở dữ liệu metadata từ bản sao lưu của cơ sở dữ liệu đã sửa chữa (sau IBFirstAID) bằng lệnh
gbak -c -m -user SYSDBA -pass masterkey Disk:\Path\backup.fbk Disk:\Path\fresh.fdb
-
Chạy IBDataPump và đặt cơ sở dữ liệu đã sửa chữa một phần làm Nguồn, và cơ sở dữ liệu trống mới làm đích
-
Nhấp vào các tab tiếp theo, nhấp vào các nút thích hợp và ở tab thứ 3 nhấp “Pump”. Chờ cho hoàn tất (có thể là quá trình dài, để có ý tưởng bạn có thể kiểm tra động lực tăng trưởng của kích thước cơ sở dữ liệu đích).
-
Kết quả là bạn sẽ có cơ sở dữ liệu fresh.fdb với các mối quan hệ khóa ngoại nhất quán - hoàn toàn ổn.
Nếu cơ sở dữ liệu có vòng lặp với các khóa ngoại, IBDataPump sẽ cảnh báo bạn và đưa ra danh sách các ràng buộc như vậy - một hoặc nhiều trong số chúng nên được xóa trước khi việc bơm có thể thực hiện được.
Tất nhiên, đã có một số trường hợp việc bơm yêu cầu cách tiếp cận đặc biệt, và nếu bạn gặp phải tình huống như vậy, vui lòng liên hệ hỗ trợ của chúng tôi.