2009-06-29 7 views
5

primera nota que he visto esta pregunta: TSQL delete with an inner joinSQL Eliminar si la fila no se ve afectada por las limitaciones

que tienen una gran mesa y varias relaciones de clave externa, cada una de ellas con los datos de una determinada edad. Necesitamos eliminar datos más antiguos que un dato dado de forma regular para evitar que el DB crezca sin límite.

Estoy escribiendo una consulta que eliminará de cada punto de la estrella si lo hace por los parámetros dados (lamentablemente estos son configurables y diferentes entre las tablas).

Después de esta primera eliminación, tengo una tabla central que me preocupa que estoy haciendo el doble del trabajo al intentar eliminar, ya que al eliminar la base de datos comprueba los condicionales. Tengo un conjunto de:

AND NOT EXISTS 
(SELECT key 
FROM table 
WHERE table.key = centretable.key) 

que TSQL está convirtiendo en una anti semi unión correcta y haciéndola muy bien en los índices. El problema es que crea una lista de cosas para eliminar y luego realiza las mismas comprobaciones nuevamente mientras realiza la eliminación.

Supongo que mi pregunta es si hay un intento de eliminar por fila, (no voy a hacer eso en un cursor porque sé lo lento que sería), pero se podría pensar que tal palabra clave existiría , No he tenido suerte encontrándolo.

+1

re su comentario; Agregué un ejemplo de la nocheck para desactivar una clave foránea. –

Respuesta

0

Si está reutilizando la misma lista de cosas para eliminar, podría considerar insertar las claves para eliminarlas en una tabla temporal y luego usarlas en la segunda consulta.

SELECT Key, ... 
INTO #ToDelete 
FROM Table T 
WHERE ... 

Entonces algo como esto

... 
LEFT OUTER JOIN #ToDelete D 
ON T.Key=D.Key 
WHERE D.Key IS NULL 

DROP #ToDelete 
+0

El optimizador de consultas ya lo hizo. Estoy revisando para ver si hay una palabra clave para eliminar cuando no están vinculados, así que puedo hacerlo de una vez. – Spence

0

Si ha especificado la clave externa como una restricción al crear la tabla en la base de datos se puede decir la base de datos de qué hacer en caso de eliminación, mediante el establecimiento de la regla de eliminación. Esta regla especifica qué sucede si un usuario intenta eliminar una fila con datos que están involucrados en una relación de clave externa. La configuración "Sin acción" le dice al usuario que la eliminación no está permitida y el DELETE se revierte. Implementarlo así evitaría que usted lo revise usted mismo antes de eliminarlo, y por lo tanto podría ser visto como una especie de intento. Bueno, al menos funciona así en MS SQL. http://msdn.microsoft.com/en-us/library/ms177288.aspx

+0

Quiero lo contrario. No estoy tratando de poner en cascada la eliminación. Estoy tratando de eliminar todo lo que no está conectado a nada más. – Spence

2

En términos de un único comando que sólo comprueba las relaciones una vez (en lugar de dos veces en su ejemplo - una vez para la NOT EXISTS, una vez por el DELETE), entonces espero que la respuesta es un gran grasa no, lo siento.

(frente a la idea de la pared): Si esto es un problema importante, podría intentar algún tipo de aplicación de conteo de referencias, usando disparadores para actualizar el contador - pero en realidad me esperaba esto será mucho más sobrecarga de mantener que simplemente verificar las claves como ya lo está haciendo.

También puede investigar NOCHECK durante la eliminación (ya que lo está comprobando usted mismo); pero sólo se puede hacer esto a nivel de tabla (por lo que probablemente está bien para los scripts de administración, pero no para el código de producción) - es decir:

-- disable 
alter table ChildTableName nocheck constraint ForeignKeyName 

-- enable 
alter table ChildTableName check constraint ForeignKeyName 

Una prueba rápida muestra que con ella le permitió no examinar un índice clúster adicional en la clave foránea; con esto deshabilitado, esto se omite.

Aquí hay un ejemplo completo; Puede ver el plan de consulta de las dos operaciones DELETE ...(A ser posible de forma aislada del resto del código):

create table parent (id int primary key) 
create table child (id int primary key, pid int) 
alter table child add constraint fk_parent foreign key (pid) 
    references parent (id) 

insert parent values (1) 
insert parent values (2) 
insert child values (1,1) 
insert child values (2,1) 

-- ******************* THIS ONE CHECKS THE FOREIGN KEY 
delete from parent 
where not exists (select 1 from child where pid = parent.id) 

-- reset 
delete from child 
delete from parent 
insert parent values (1) 
insert parent values (2) 
insert child values (1,1) 
insert child values (2,1) 

-- re-run with check disabled 
alter table child nocheck constraint fk_parent 

-- ******************* THIS ONE DOESN'T CHECK THE FOREIGN KEY  
delete from parent 
where not exists (select 1 from child where pid = parent.id) 

-- re-enable 
alter table child check constraint fk_parent 

Una vez más - recalco esto sólo se debe ejecutar desde cosas como las secuencias de comandos de administración.

+0

Desafortunadamente, las claves externas no controlan las restricciones. Saludos por tu entrada. – Spence

+0

Lo dejaré por unos días y le daré el voto favorable si nadie contrarresta su afirmación. – Spence

+0

Doi, FKeys en TSQL son restricciones de verificación, aunque especiales. Es una sugerencia válida y en la transacción podría ser la única forma de hacerlo si el rendimiento se convierte en un problema. – Spence

0

La respuesta corta a tu pregunta es no, no hay ninguna palabra clave estándar RDBMS para la eliminación de un registro maestro cuando todas las referencias de clave externa a desaparecer (y ciertamente ninguno que explicaría las claves externas en varias tablas).

Su opción más eficiente es una segunda consulta que se ejecuta en una medida que sea necesario eliminar del "centro", basada en una serie de NO EXISTE (cláusulas) por cada una de las mesas con las claves externas.

Esto se basa en dos afirmaciones creo que son ambas verdaderas para su situación:

  1. Va a eliminar más "relacionadas" registros que los registros de "centro" (padre). Por lo tanto, cualquier operación que intente ajustar "centro" cada vez que elimine de una de las otras tablas dará como resultado una actualización instantánea a "centro", pero requerirá muchas consultas desperdiciadas para eliminar un registro "central" solo ocasionalmente.

  2. Dado que hay varios puntos en la estrella desde el "centro", cualquier "esfuerzo perdido" buscando una clave externa en uno de ellos es mínimo en comparación con el total. Por ejemplo, si hay cuatro claves externas para verificar antes de eliminar desde "centro", solo puede guardar, en el mejor de los casos, el 25% del tiempo.

1

Se puede crear una vista indizada de su selecto frase:

SELECT key FROM table WHERE table.key = centretable.key 

La vista indizada es una copia física de los datos, por lo tanto, sería muy rápido para comprobar.

Tiene la sobrecarga de actualizar la vista, por lo que debería probar esto en función de su patrón de uso.

Cuestiones relacionadas