2009-10-28 28 views
15

Trong MSSQL 2005 tôi chỉ tấn công được thông báo lỗi khét tiếng:Vấn đề với khóa ngoại tuyến là nhiều đường dẫn và chu kỳ là gì?

Giới thiệu FOREIGN KEY constraint XXX trên bàn YYY có thể gây ra chu kỳ hoặc nhiều đường thác. Chỉ định ON DELETE NO ACTION hoặc ON UPDATE NO ACTION, hoặc sửa đổi các ràng buộc KEY NGOẠI HỐI khác.

Bây giờ, StackOverflow có một số chủ đề về thông báo lỗi này, vì vậy tôi đã có giải pháp (trong trường hợp của mình, tôi sẽ phải sử dụng trình kích hoạt), nhưng tôi tò mò là tại sao có một vấn đề.

Như tôi đã hiểu, về cơ bản có hai kịch bản mà họ muốn tránh - một chu kỳ và nhiều đường dẫn. Một chu kỳ sẽ là nơi hai bảng có các khóa nước ngoài xếp chồng lên nhau. OK, một chu trình có thể mở rộng nhiều bảng, nhưng đây là trường hợp cơ bản và sẽ dễ phân tích hơn.

Nhiều đường dẫn sẽ là khi TableA có khóa ngoài để TableB và TableC, và TableB cũng có khóa ngoài cho TableC. Một lần nữa - đây là trường hợp cơ bản tối thiểu.

Tôi không thể thấy bất kỳ vấn đề nào phát sinh khi bản ghi bị xóa hoặc cập nhật trong bất kỳ bảng nào trong số đó. Chắc chắn, bạn có thể cần phải truy vấn cùng một bảng nhiều lần để xem bản ghi nào cần cập nhật/xóa, nhưng đó thực sự là một vấn đề? Đây có phải là vấn đề về hiệu suất không?

Trong các chủ đề SO khác, mọi người truy cập nhãn bằng cách sử dụng các thác là "risky" và nêu rõ "resolving cascade paths is a complex problem". Tại sao? Nguy cơ ở đâu? Vấn đề ở đâu?

Trả lời

4

Bạn có bảng con với 2 đường dẫn xếp tầng từ cùng một cấp độ gốc: một "xóa", một "dấu".

Điều gì sẽ được ưu tiên? Bạn mong đợi điều gì sau đó? vv

Lưu ý: Trình kích hoạt là mã và có thể thêm một số thông tin hoặc điều kiện vào một tầng.

0

Tôi đồng ý với các thác đó là "nguy hiểm" và nên tránh. (Cá nhân tôi thích xếp tầng các thay đổi bằng tay thay vì máy chủ sql tự động xử lý chúng). Đây cũng là vì ngay cả khi máy chủ sql xóa hàng triệu hàng, sản lượng vẫn sẽ hiển thị như

(1 row (s) bị ảnh hưởng)

+1

Thay thế bằng trình kích hoạt có làm cho nó tốt hơn không? Tất nhiên - có một cách tiếp cận như "không dùng chìa khóa nước ngoài" và làm mọi thứ từ mã. Tôi không nghĩ rằng tôi cần phải cho bạn biết tại sao tôi nghĩ rằng đó là một ý tưởng tồi ... –

1

Lý do chúng tôi cấm sử dụng cascade xóa đã làm với hiệu suất và khóa . Có nó không phải là xấu như vậy khi bạn xóa một bản ghi nhưng sớm hay muộn bạn sẽ cần phải xóa một nhóm lớn các hồ sơ và cơ sở dữ liệu của bạn sẽ đến bế tắc.

Nếu bạn đang xóa đủ bản ghi, SQL Server có thể chuyển sang khóa bảng và không ai có thể làm bất cứ điều gì với bảng cho đến khi nó được hoàn tất.

Gần đây, chúng tôi đã chuyển một trong các khách hàng của chúng tôi đến máy chủ của riêng mình. Là một phần của thỏa thuận, chúng tôi cũng phải xóa tất cả hồ sơ của khách hàng đó tạo thành máy chủ gốc của chúng tôi. Xóa tất cả thông tin của mình theo lô (để không gây ra sự cố với người dùng khác) mất một vài tháng. Nếu chúng ta có thiết lập xóa tầng, cơ sở dữ liệu sẽ không thể tiếp cận được với các máy khách khác trong một thời gian dài vì hàng triệu bản ghi đã bị xóa trong một giao dịch và hàng trăm bảng đã bị khóa cho đến khi giao dịch được thực hiện. Tôi cũng có thể thấy một tình huống mà một bế tắc có thể đã xảy ra khi sử dụng xóa tầng vì chúng tôi không kiểm soát được thứ tự đường dẫn tầng đã thực hiện và cơ sở dữ liệu của chúng tôi bị tiêu chuẩn hóa với clientid xuất hiện trong hầu hết các bảng. Vì vậy, nếu nó khóa một bảng có khóa ngoài cũng đến một bảng thứ ba cũng như bảng khách hàng trong một đường dẫn khác, nó có thể không thể kiểm tra bảng đó để xóa khỏi bảng thứ ba vì đây là tất cả một giao dịch và các khóa sẽ không được phát hành cho đến khi nó được thực hiện. Vì vậy, có thể nó sẽ không cho phép chúng tôi thiết lập xóa tầng nếu nó thấy khả năng tạo deadlocks trong giao dịch.

Một lý do khác để tránh xóa tầng là đôi khi sự tồn tại của bản ghi con là lý do đủ để không xóa bản ghi cha. Ví dụ: nếu bạn có bảng khách hàng và khách hàng đó đã có đơn hàng trong quá khứ, bạn sẽ không muốn xóa anh ấy và mất thông tin theo thứ tự thực tế.

+4

Nếu bạn đang đối phó với hàng triệu hàng thì hầu như luôn luôn bạn phải sử dụng cách giải quyết khó khăn như batching, vô hiệu hóa các phím nước ngoài, chạy công việc trong thời gian nhàn rỗi, vv Nhưng đó không phải là một kịch bản hàng ngày. Mọi người chuẩn bị cho điều đó trước. Họ kiểm tra nó trong một môi trường thử nghiệm. Họ tạo ra những đoạn mã dài và xoắn để chỉnh sửa DB để nó có được hiệu suất chấp nhận được. Và một khi nó được thực hiện nó bị lãng quên. Nhưng "ON DELETE CASCADE" có nghĩa là để được sử dụng trong cuộc sống hàng ngày, khi bạn không xóa hàng triệu hàng nhưng tối đa là vài trăm tại một thời điểm. –

+0

Và deadlocks trên cascades (hoặc thậm chí xóa đơn giản cho một số hàng trong cùng một bảng) có thể xảy ra anyway - ngăn chặn nhiều đường dẫn cascade và chu kỳ không làm một chút để làm cho nó tốt hơn. –

1

Xem xét một bảng nhân viên:

CREATE TABLE Employee 
(
    EmpID INTEGER NOT NULL PRIMARY KEY, 
    Name VARCHAR(40) NOT NULL, 
    MgrID INTEGER NOT NULL REFERENCES Employee(EmpID) ON DELETE CASCADE 
); 

INSERT INTO Employees( 1, "Bill", 1); 
INSERT INTO Employees( 23, "Steve", 1); 
INSERT INTO Employees(234212, "Helen", 23); 

Bây giờ giả sử Bill nghỉ hưu:

DELETE FROM Employees WHERE Name = "Bill"; 

Ooooppps; tất cả mọi người chỉ bị sa thải!

[Chúng tôi có thể tranh luận xem chi tiết cú pháp có chính xác hay không; khái niệm là viết tắt, tôi nghĩ vậy.]

+13

Tôi cho rằng trong trường hợp này, DELETE CASCADE ON đã được sử dụng không chính xác. Xin lỗi, đó là lỗi của riêng bạn nếu bạn xây dựng một chương trình lỗi - nó không phải là công việc của ngôn ngữ lập trình để bảo vệ bạn khỏi việc viết mã xấu. –

-1

Tôi nghĩ có hay không sử dụng tùy chọn BẬT DELETE CASCADE là câu hỏi về mô hình kinh doanh bạn đang triển khai. Một mối quan hệ giữa hai đối tượng kinh doanh có thể là một "hiệp hội" đơn giản, trong đó cả hai đầu của mối quan hệ có liên quan, nhưng các đối tượng độc lập thì vòng đời khác nhau và được kiểm soát bởi logic khác. Tuy nhiên, cũng có các mối quan hệ "tổng hợp", trong đó một đối tượng thực sự có thể được xem là "cha mẹ" hoặc "chủ sở hữu" của đối tượng "con" hoặc "chi tiết". Thậm chí còn có khái niệm thậm chí mạnh mẽ hơn về mối quan hệ "thành phần", trong đó một đối tượng chỉ tồn tại như một thành phần của một số phần. Trong trường hợp "liên kết", bạn thường sẽ không khai báo ràng buộc ON DELETE CASCADE. Tuy nhiên, đối với các tập hợp hoặc bố cục, BẬT DELETE CASCADE giúp bạn lập bản đồ mô hình kinh doanh của mình với cơ sở dữ liệu chính xác hơn và theo cách khai báo. Đây là lý do tại sao nó làm phiền tôi rằng MS SQL Server hạn chế việc sử dụng tùy chọn này cho một đường dẫn tầng đơn. Nếu tôi không nhầm, nhiều hệ thống cơ sở dữ liệu SQL được sử dụng rộng rãi khác không áp đặt những hạn chế như vậy.

+0

Và đây là câu trả lời ... làm thế nào? –

1

Tôi nghĩ rằng vấn đề là khi bạn thực hiện một đường dẫn "ON DELETE CASCADE" và "ON DELETE RESTRICT", hoặc "NO ACTION", kết quả sẽ không thể thực hiện được. Nó phụ thuộc vào việc xóa-kích hoạt (đây cũng là một kích hoạt, nhưng một trong những bạn không phải xây dựng chính mình) sẽ được thực hiện đầu tiên.

+0

Với các giao dịch, điều này không phải là vấn đề - hàng bị xóa, xóa các thác, sau đó việc xóa bị hạn chế và toàn bộ điều sẽ bị lùi lại. – Brilliand

Các vấn đề liên quan