Was geht verloren, wenn ich mit `WITH NOCHECK` einen Fremdschlüssel erstelle?

11

Ich weiß, dass, wenn ich EXISTS()einen FK-Suchwert aufrufe, das Ergebnis sofort ist, wenn dieser FK-Einschränkung vertraut wird.

Und wenn es nicht vertrauenswürdig ist (wie beim Erstellen der FK mit WITH NOCHECK), muss SQL Server in der Tabelle nachsehen, ob der Wert tatsächlich vorhanden ist.

Gibt es noch etwas, das ich durch die Verwendung verliere NOCHECK?

Vaccano
quelle

Antworten:

13

Wie Sie in Ihrem existsBeispiel festgestellt haben , kann SQL Server die Tatsache verwenden, dass ein Fremdschlüssel beim Erstellen des Abfrageplans vertrauenswürdig ist.

Gibt es noch etwas, das ich durch die Verwendung von NOCHECK verliere?

Abgesehen von der Tatsache, dass Sie einer Spalte Werte hinzufügen können, die nicht vorhanden sein sollten, wie von Ste Bov beantwortet, gibt es mehr Szenarien, in denen der Abfrageplan besser ist, wenn dem Fremdschlüssel vertraut wird.

Hier ist ein Beispiel mit einer indizierten Ansicht .

Sie haben zwei Tabellen mit einer vertrauenswürdigen FK-Einschränkung.

create table dbo.Country
(
  CountryID int primary key,
  Name varchar(50) not null
);

create table dbo.City
(
  CityID int identity primary key,
  Name varchar(50),
  IsBig bit not null,
  CountryID int not null
);

alter table dbo.City 
  add constraint FK_CountryID 
  foreign key (CountryID) 
  references dbo.Country(CountryID);

Es gibt nicht so viele Länder, aber eine Unmenge von Städten, und einige von ihnen sind große Städte.

Beispieldaten:

-- Three countries
insert into dbo.Country(CountryID, Name) values
(1, 'Sweden'),
(2, 'Norway'),
(3, 'Denmark');

-- Five big cities
insert into dbo.City(Name, IsBig, CountryID) values
('Stockholm', 1, 1),
('Gothenburg', 1, 1),
('Malmoe', 1, 1),
('Oslo', 1, 2),
('Copenhagen', 1, 3);

-- 300 small cities
insert into dbo.City(Name, IsBig, CountryID)
select 'NoName', 0, Country.CountryID
from dbo.Country
  cross apply (
              select top(100) *
              from sys.columns
              ) as T;

Die am häufigsten ausgeführten Abfragen in dieser Anwendung beziehen sich auf die Ermittlung der Anzahl der Großstädte pro Land. Um dies zu beschleunigen, fügen wir eine indizierte Ansicht hinzu.

create view dbo.BigCityCount with schemabinding
as
select count_big(*) as BigCityCount,
       City.CountryID,
       Country.Name as CountryName
from dbo.City
  inner join dbo.Country
    on City.CountryID = Country.CountryID
where City.IsBig = 1 
group by City.CountryID,
         Country.Name;

 go

create unique clustered index CX_BigCityCount
  on dbo.BigCityCount(CountryID);

Nach einer Weile kommt die Forderung, ein neues Land hinzuzufügen

insert into dbo.Country(CountryID, Name) values(4, 'Finland');

Der Abfrageplan für diese Einfügung enthält keine Überraschungen.

Geben Sie hier die Bildbeschreibung ein

Eine gruppierte Indexeinfügung in die CountryTabelle.

Nun, wenn Ihr Fremdschlüssel nicht vertrauenswürdig war

alter table dbo.City nocheck constraint FK_CountryID;

und Sie fügen ein neues Land hinzu

insert into dbo.Country(CountryID, Name) values(5, 'Iceland');

Sie würden mit diesem nicht so schönen Bild enden.

Geben Sie hier die Bildbeschreibung ein

Der untere Zweig dient zum Aktualisieren der indizierten Ansicht. Es wird ein vollständiger Tabellenscan durchgeführt, um Cityherauszufinden, ob das Land mit CountryID = 5bereits Zeilen in der Tabelle enthält City.

Wenn der Schlüssel vertrauenswürdig ist, weiß SQL Server, dass es keine Zeilen geben kann City, die mit der neuen Zeile in übereinstimmen Country.

Mikael Eriksson
quelle
4

Sie verlieren Abfrageoptimierungen. In der Praxis ist die einzige Optimierung, an die ich mich erinnere, die Beseitigung redundanter Verknüpfungen. Zum Beispiel, wenn Sie in einer Ansicht haben:

select *
from Orders o
join Customers c on o.CustomerID = c.ID

Und wenn Sie die Ansicht verwenden, verwenden Sie nicht die Spalten, in denen cdieser Join gelöscht werden kann, wenn eine ordnungsgemäße FK eingerichtet ist.

Ihr EXISTSBeispiel ist ein Sonderfall zum Entfernen eines redundanten Joins. Ich denke nicht, dass ein bestimmtes Beispiel praktisch relevant ist.

Sie verlieren auch die strikte Datenintegrität, die eine vertrauenswürdige Einschränkung bietet.

usr
quelle
3

Die NOCHECK-Option macht genau das, was sie verspricht.

Es wird hauptsächlich zum Hinzufügen eines Fremdschlüssels in der Mitte der Existenz einer Tabelle verwendet, in der eine neue Beziehung vorhanden ist, die möglicherweise nicht erforderlich war (zumindest nach meinem Verständnis).

Dies bedeutet, dass die Spalte mit dem Fremdschlüssel möglicherweise Werte enthält, die nicht mit dem festgelegten Wert korrelieren, auf den sie sich beziehen soll.

Dies bedeutet, dass bei einer NOCHECK-Option in SQL Server überprüft werden muss, ob dieser Schlüsselwert tatsächlich ein Primärschlüssel ist. Wenn NOCHECK nicht festgelegt ist, geht SQL Server davon aus, dass alles in dieser Spalte definitiv vorhanden ist, da der Eintrag in der Tabelle nicht vorhanden sein könnte, wenn er nicht bereits ein Primärschlüssel war, und Sie den Primärschlüssel nicht löschen könnten, ohne die Zeile in zu löschen Frage.

Einfach NOCHECK ist ein Fremdschlüssel, dem Sie nicht vertrauen können, um sich tatsächlich auf irgendetwas zu beziehen.

Sie verlieren nichts anderes als das Vertrauen, dass der Primärschlüssel garantiert vorhanden ist.

Ste Bov
quelle
Aus Ihrer Antwort geht nicht hervor, ob nach der ersten Erstellung der Einschränkung eine Durchsetzung des Fremdschlüssels erfolgt . Können Sie klarstellen, was passiert, wenn Sie versuchen, INSERTeine neue Zeile zu erstellen, die sich auf eine nicht vorhandene übergeordnete Zeile bezieht, oder wenn Sie später versuchen, DELETEeine Zeile mit untergeordneten Zeilen zu erstellen?
jpmc26