2013-05-01 15 views
9

İki tabloya, Satış ve Ürünüm var. Satışı Ürüne gönderme yapan bir yabancı anahtar kısıtlaması vardır. Yabancı anahtar, oluşturulduktan sonra WITH NOCHECK oluşturuldu ve hemen devre dışı bırakıldı. Yabancı anahtar kısıtını etkinleştirmek ve güvenmek istiyorum. Etkinleştiriliyor, ancak güvenilir olmasına izin veremiyorum. StackOverflow'daki ve çeşitli bloglardaYabancı anahtar kısıtlamaları nasıl güvenilir yapılır?

Benzer sorular ALTER TABLE T WITH CHECK CHECK CONSTRAINT C çalışan is_disabled=0 ve is_not_trusted=0 neden gerektiğini belirtmek fakat is_not_trusted benim için her zaman 1'dir. Neyi yanlış yapıyorum?

SQL Fiddle üzerinde örnek kodu koymak için çalıştı ama "DBCC" komutları gibi değildi, bu yüzden burada:

sizin örneklere dayanarak
-- "_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. 

cevap

17

, ben de denedim:

  • Dış anahtarı bırakın ve yeniden oluşturun.
  • Tabloyu bırakın ve yeniden oluşturun.

    bir kısıtlama DEĞİL IÇIN çoğaltma ile oluşturulursa görünüyor
    NOT FOR REPLICATION 
    

    , her zaman güvenilir değil:

Sonra komuta şey fark ettim.

Books Online alıntı:

Bazı durumlarda, bir çoğaltma topolojisinde kullanım aktivitesi için arzu edilen maddenin aktivitesi farklı muamele edilecek. Örneğin, ekleme satırının bir kullanıcı tarafından Publisher'da eklenirse ve , tablodaki bir kontrol kısıtlamasını karşılarsa örneğinde, satırında bir satır aracı tarafından eklendiğinde, aynı kısıtlamayı zorlamaz. Abone. REPLICATION seçeneği DEĞİL çoğaltma aracısı bir operasyon gerçekleştirdiğinde aşağıdaki veritabanı nesneleri farklı davranılır belirtmek yapmanızı sağlar:

Yabancı anahtar kısıtlamaları

yabancı anahtar kısıtlaması zorlanmaz çoğaltma aracısı Ekleme, güncelleme veya silme işlemini gerçekleştirir. IS_NOT_TRUSTED ayar etkilenmiştir çoğaltma için sadece ilgili olduğu gibi

görünüyor. Kısıtlama üzerinde çalıştığınız sunucu üzerinde kısıtlama olduğu sürece, iyi olmalı. Bu yüzden devam ettim ve bunu doğruladı:

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. 

hala huzuru için IS_NOT_TRUSTED = 0 bkz sadece NOT FOR REPLICATION olmadan yabancı bir anahtarı yeniden istiyorsanız.

Sizin için merak ediyorsanız, KONTROL kısıtlamaları üzerinde de aynı etkiyi doğruladım.

+0

Louie, testleri yapmak için zaman ayırdığınız için teşekkür ederim, bu harika bir cevap, keşke size birden fazla destek verebilseydim :) Güvenilirliği kısıtlamaya çalışıyorum çünkü güvenilmez olanları okudum bazı sorguların performansını etkileyebilir. Veritabanını devraldım ve çoğaltmıyoruz ama her şey "spekülatif genellik" durumunda olabilecek "DEĞİŞTİRME İÇİN DEĞİL" gibi görünüyor. – WileCau

+0

@WileCau FK'lerin güvenilir olarak işaretlenmediği durumlarda, yürütme süresinde gerçekten bir iyileşme oluyorsunuz. Bu uygulamayı hiçbir şekilde teşvik etmiyorum. Bununla birlikte, büyük miktarda veriyi, aşamalı sql'den üretim sql'e taşımak çok yararlıdır. Daha fazla bilgi için buraya bakın http://sqlblog.com/blogs/hugo_kornelis/archive/2007/03/29/can-you-trust-your-constraints.aspx – harsimranb

+0

@ Pathachiever11, haklısınız, kısıtlamaların devre dışı bırakılmasının nedeni çünkü bazı tablolar başlangıçta başka bir tutarlı veri tabanından dolduruldu, bu yüzden veri geçişini yavaşlattılar. İlk geçişten sonra, kısıtlamalar yeni veriler üzerinde tutarlılığı sağlamak için yeniden etkinleştirilmeli, ancak unutuldu. – WileCau