2013-05-01 17 views
9

Tôi có hai bảng, Bán và Sản phẩm. Bán có ràng buộc khóa ngoài tham chiếu đến Sản phẩm. Khóa ngoại đã được tạo WITH NOCHECK và ngay lập tức bị tắt sau khi tạo. Tôi muốn kích hoạt và tin tưởng ràng buộc khoá ngoại. Kích hoạt nó hoạt động nhưng tôi không thể làm cho nó được tin cậy.Làm thế nào để các ràng buộc khóa ngoại được tin cậy?

Các câu hỏi tương tự trên StackOverflow và các blog khác nhau cho biết rằng chạy ALTER TABLE T WITH CHECK CHECK CONSTRAINT C sẽ dẫn đến is_disabled=0is_not_trusted=0, nhưng is_not_trusted luôn là 1 đối với tôi. Tôi đang làm gì sai?

Tôi cố gắng để đưa mẫu mã trên SQL Fiddle nhưng nó không thích "DBCC" lệnh, vì vậy ở đây là:

-- "_Scratch" is just a sandbox DB that I use for testing stuff. 
USE _Scratch 

CREATE TABLE dbo.Product 
(
    ProductKeyId INT PRIMARY KEY NOT NULL, 
    Description VARCHAR(40) NOT NULL 
) 

CREATE TABLE dbo.Sale 
(
    ProductKeyId INT NOT NULL, 
    SaleTime DATETIME NOT NULL, 
    Value MONEY NOT NULL 
) 

ALTER TABLE dbo.Sale WITH NOCHECK 
    ADD CONSTRAINT FK_Product_ProductKeyId FOREIGN KEY (ProductKeyId) 
    REFERENCES dbo.Product (ProductKeyId) NOT FOR REPLICATION; 

ALTER TABLE dbo.Sale NOCHECK CONSTRAINT FK_Product_ProductKeyId 

INSERT INTO dbo.Product VALUES (1, 'Food') 
INSERT INTO dbo.Sale VALUES (1, GETDATE(), 1.00) 

-- Check the disabled/trusted state 
SELECT name, is_disabled, is_not_trusted 
FROM sys.foreign_keys 
WHERE name = 'FK_Product_ProductKeyId' 

    -- name      is_disabled is_not_trusted 
    -- FK_Product_ProductKeyId 1   1 

-- Check the FK_Product_ProductKeyId constraint 
DBCC CHECKCONSTRAINTS('FK_Product_ProductKeyId') 

    -- DBCC execution completed. 
    -- If DBCC printed error messages, contact your system administrator. 

-- Check all constraints on Sale table 
DBCC CHECKCONSTRAINTS('Sale') 

    -- DBCC execution completed. 
    -- If DBCC printed error messages, contact your system administrator. 

-- Add the constraint and check existing data 
ALTER TABLE Sale WITH CHECK CHECK CONSTRAINT FK_Product_ProductKeyId 

-- Check the disabled/trusted state 
SELECT name, is_disabled, is_not_trusted 
FROM sys.foreign_keys 
WHERE name = 'FK_Product_ProductKeyId' 

    -- name      is_disabled is_not_trusted 
    -- FK_Product_ProductKeyId 0   1 

-- Check the FK_Product_ProductKeyId constraint 
DBCC CHECKCONSTRAINTS('FK_Product_ProductKeyId') 

    -- DBCC execution completed. 
    -- If DBCC printed error messages, contact your system administrator. 

-- Check all constraints on Sale table 
DBCC CHECKCONSTRAINTS('Sale') 

    -- DBCC execution completed. 
    -- If DBCC printed error messages, contact your system administrator. 

Trả lời

17

Dựa trên ví dụ của bạn, tôi cũng đã cố gắng:

  • Thả và tạo lại khóa ngoại.
  • Thả và tạo lại bảng.

Sau đó, tôi nhận thấy một cái gì đó trong lệnh:

NOT FOR REPLICATION 

Có vẻ như nếu một hạn chế được tạo ra với KHÔNG để nhân rộng, nó luôn luôn không đáng tin cậy.

Trích dẫn từ Books Online:

Trong một số trường hợp, đó là mong muốn cho hoạt động người dùng trong một topo sao chép được đối xử khác với hoạt động đại lý. Ví dụ: nếu một hàng được chèn bởi người dùng tại Nhà xuất bản và việc chèn thỏa mãn ràng buộc kiểm tra trên bảng, có thể không được yêu cầu thực thi cùng ràng buộc khi hàng được chèn bởi nhân rộng đại lý tại Người đăng kí. NGƯỜI ĐÀN ÔNG KHÔNG CHO tùy chọn sao chép cho phép bạn xác định rằng các đối tượng cơ sở dữ liệu sau đây được đối xử khác biệt khi một đại lý sao chép thực hiện một hoạt động:

ràng buộc khoá ngoại

các ràng buộc khoá ngoại là không được thực thi khi một đại lý sao chép thực hiện thao tác chèn, cập nhật hoặc xóa.

Dường như các thiết lập IS_NOT_TRUSTED chỉ có liên quan để nhân rộng ảnh hưởng bởi . Tôi đoán miễn là ràng buộc được thực thi trên máy chủ bạn đang làm việc, nó sẽ ổn thôi. Vì vậy, tôi đã đi trước và khẳng định nó:

SELECT name, is_disabled, is_not_trusted 
FROM sys.foreign_keys 
WHERE name = 'FK_Product_ProductKeyId' 

name     is_disabled is_not_trusted 
FK_Product_ProductKeyId 0   1 

INSERT INTO dbo.Sale VALUES (2, GETDATE(), 1.00) 

Msg 547, Level 16, State 0, Line 1 
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Product_ProductKeyId". The conflict occurred in database "_Scratch", table "dbo.Product", column 'ProductKeyId'. 
The statement has been terminated. 

Nếu bạn vẫn muốn xem IS_NOT_TRUSTED = 0 cho yên tâm, chỉ cần tái tạo lại chính nước ngoài không có NOT FOR REPLICATION.

Trong trường hợp nếu bạn đang thắc mắc, tôi cũng đã xác minh tác dụng tương tự đối với ràng buộc CHECK.

+0

Louie, cảm ơn bạn đã dành thời gian để làm các bài kiểm tra, đó là một câu trả lời tuyệt vời, tôi ước tôi có thể cung cấp cho bạn nhiều hơn một upvote :) Tôi đã cố gắng để có được những hạn chế đáng tin cậy vì tôi đọc ở đâu đó có thể ảnh hưởng đến hiệu suất của một số truy vấn. Tôi thừa hưởng cơ sở dữ liệu và chúng tôi không sao chép nhưng mọi thứ dường như là "KHÔNG CHO LẠI LẠI", có thể là một trường hợp "tổng quát đầu cơ". – WileCau

+0

@WileCau Bạn thực sự nhận được một sự cải thiện trong thời gian thực hiện khi FK được đánh dấu không đáng tin cậy. Tôi không có cách nào khuyến khích thực hành này. Tuy nhiên, nó rất hữu ích để di chuyển một lượng lớn dữ liệu, từ nói sql dàn dựng đến sql sản xuất. kiểm tra ở đây để biết thêm thông tin http://sqlblog.com/blogs/hugo_kornelis/archive/2007/03/29/can-you-trust-your-constraints.aspx – harsimranb

+0

@ Pathachiever11, bạn nói đúng, lý do các ràng buộc đã bị vô hiệu hóa là vì một số bảng ban đầu được phổ biến từ một cơ sở dữ liệu đã biết khác nên chúng chỉ làm chậm quá trình di chuyển dữ liệu. Sau khi di chuyển ban đầu, các ràng buộc nên được kích hoạt lại để thực thi tính nhất quán trên dữ liệu mới, nhưng chúng đã bị lãng quên. – WileCau

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