¿Qué se pierde cuando creo una clave externa usando `WITH NOCHECK`?


11

Sé que si hago una EXISTS()llamada en un valor de búsqueda FK, entonces, si esa restricción FK es confiable, el resultado es inmediato.

Y si no es confiable (como cuando creo el FK usando WITH NOCHECK), SQL Server tiene que ir y verificar la tabla para ver si el valor está realmente allí.

¿Hay algo más que pierdo al usar NOCHECK?

Respuestas:


13

Como descubrió con su existsejemplo, SQL Server puede utilizar el hecho de que se confía en una clave externa cuando se crea el plan de consulta.

¿Hay algo más que pierda al usar NOCHECK?

Además del hecho de que puede agregar valores a una columna que no debería estar allí, como respondió Ste Bov , tendrá más escenarios en los que el plan de consulta será mejor cuando se confíe en la clave externa.

Aquí hay un ejemplo con una vista indizada .

Tiene dos tablas con una restricción FK de confianza.

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);

No hay tantos países, sino una gran cantidad de ciudades, y algunas de ellas son grandes ciudades.

Data de muestra:

-- 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;

Las consultas ejecutadas con mayor frecuencia en esta aplicación están relacionadas con la búsqueda del número de grandes ciudades por país. Para acelerar las cosas con eso, agregamos una vista indexada.

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);

Después de un tiempo surge la demanda de agregar un nuevo país.

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

El plan de consulta para ese inserto no tiene sorpresas.

ingrese la descripción de la imagen aquí

Una inserción de índice agrupado en la Countrytabla.

Ahora, si no se confiaba en su clave externa

alter table dbo.City nocheck constraint FK_CountryID;

y agregas un nuevo país

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

terminarías con esta foto no tan bonita.

ingrese la descripción de la imagen aquí

La rama inferior está allí para actualizar la vista indizada. Realiza un análisis completo de la tabla Citypara determinar si el país con CountryID = 5ya tiene filas en la tabla City.

Cuando la clave es confiable, SQL Server sabe que no puede haber filas Cityque coincidan con la nueva fila Country.


4

Estás perdiendo optimizaciones de consultas. En la práctica, la única optimización que recuerdo es la eliminación de uniones redundantes. Por ejemplo, si tiene en una vista:

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

Y cuando usa la vista, no hace uso de las columnas de cesa unión, entonces puede eliminarse si hay una configuración FK adecuada.

Su EXISTSejemplo es un caso especial de eliminar una unión redundante. No creo que ese ejemplo en particular sea prácticamente relevante.

También pierde la estricta integridad de los datos que proporciona una restricción confiable.


3

La opción NOCHECK hace exactamente lo que dice en la lata.

Se usa principalmente para agregar una clave foránea a la mitad de la existencia de una tabla donde hay una nueva relación que puede no haber sido requerida (al menos eso entiendo).

Significa que la columna que tiene la clave externa PUEDE tener valores dentro de ella que no se correlacionan con el valor designado con el que debería relacionarse.

Esto significa que cuando tiene una opción NOCHECK en SQL Server tiene que ir y verificar si ese valor de clave es realmente una clave principal. Si NOCHECK no está configurado, entonces SQL Server supone que cualquier cosa que esté en esa columna definitivamente existe porque la entrada no podría existir en la tabla si aún no era una clave primaria, y no podría eliminar la clave primaria sin eliminar la fila en pregunta.

Simplemente NOCHECK es una clave foránea en la que no puede confiar para relacionarse realmente con nada.

En realidad, no está perdiendo nada más que la confianza de que la clave principal garantiza estar allí.


No está claro en su respuesta si hay alguna aplicación de la clave externa después de la creación inicial de la restricción. ¿Podría aclarar qué sucede si intenta INSERTuna nueva fila que se relaciona con una fila principal no existente o si intenta DELETEuna fila que tiene filas secundarias más adelante?
jpmc26
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.