Pregunta

Desde par de días estoy pensando en un escenario siguiente

Considere Tengo 2 tablas con relación padre-hijo de tipo uno-a-muchos. En la eliminación de la fila principal que tengo que eliminar las filas de los niños se relacionan con los padres. simple derecho?

i tiene que hacer un ámbito de transacción para hacer la operación anterior i puedo hacer esto de la siguiente manera; (Su código pseudo pero yo estoy haciendo esto en C # código usando la conexión ODBC y la base de datos es SQL Server)

  1. iniciar la transacción (lectura confirmada)
  2. Lea todo niño, donde child.fk = p1
  3. foreach (niño) niño borrar según sea child.pk = cx
  4. padres borrar según sea parent.pk = p1
  5. comprometerse trans

o

  1. iniciar la transacción (lectura confirmada)
  2. Eliminar todos los child.fk donde p1 =
  3. padres borrar según sea parent.pk = p1
  4. comprometerse trans

Ahora hay un par de preguntas en mi mente

  1. ¿Cuál de arriba es mejor utilizar especialmente teniendo en cuenta un escenario de sistema de tiempo real donde miles de otras operaciones (seleccionar / actualizar / / inserción de borrado) están llevando a cabo en un lapso de segundos.

  2. tampoco garantiza que ningún nuevo niño con child.fk = p1 se añadió hasta que finalice la transacción?

  3. En caso afirmativo para la segunda pregunta entonces cómo se asegura? no se necesitan los bloqueos a nivel de tabla o qué.

  4. ¿Hay algún tipo de índice de bloqueo permite el servidor SQL si es así lo que hace y cómo se puede utilizar.

Saludos Mubashar

¿Fue útil?

Solución

Nunca usar (y nunca he tenido una necesidad legítima de) eliminaciones en cascada, y tampoco se han utilizado los factores desencadenantes para hacer cumplir esto. Las razones principales para esto es que por lo general:

  • Elimina ni siquiera se permitiría en la aplicación -. Las cosas están marcados como borrados, o que están temporalmente consistente para todos los tiempos y tienen fechas de vigencia, fechas de terminación, etc.
  • Quiero saber si un padre se elimina accidentalmente que todo el material asociado a ellos simplemente no lo hace desaparecer - por lo RI sin eliminaciones en cascada protege de extraíble de todo un árbol de dependencias
  • Fuerzas aplicación y diseño de base de datos para ser más reflexivo acerca de la interdependencia de las entidades y asegurar la refactorización apropiado de la estructura y procesos
  • Forzar la creación de un procedimiento de eliminación apropiada para una entidad le permite elegir el orden de cada paso y, potencialmente, evitar los puntos muertos -., Y también asegurarse de que sus consultas están sintonizados

La única ventaja de eliminaciones en cascada que puedo ver es que es declarativa, que se define con las tablas y presumiblemente tienen el menor espacio posible extensión de bloqueo. Los beneficios superan por encima de su uso en mi opinión.

Como en su segundo ejemplo, me gustaría encerrar en una transacción (por lo general en un procedimiento almacenado):

DELETE FROM child WHERE child.fk IN (set to delete);
DELETE FROM parent WHERE parent.pk IN (set to delete);

Toda la transacción, o bien tener éxito salir de su base de datos en un estado coherente o no confirmar ningún cambio si los niños o los padres no pueden ser borrados por cualquier razón - es decir, si había otra referencia FK a un niño o padre no representaron en su eliminación.

La base de datos se va a garantizar su integridad referencial en todo momento.

USE SandBox
GO

IF EXISTS ( SELECT  *
            FROM    sys.objects
            WHERE   object_id = OBJECT_ID(N'Child')
                    AND type IN ( N'U' ) ) 
    DROP TABLE dbo.Child
GO

IF EXISTS ( SELECT  *
            FROM    sys.objects
            WHERE   object_id = OBJECT_ID(N'Parent')
                    AND type IN ( N'U' ) ) 
    DROP TABLE dbo.Parent
GO

CREATE TABLE Parent
    (
     PK INT NOT NULL
            IDENTITY
    ,Nm VARCHAR(15)
    ,PRIMARY KEY ( PK )
    )
GO

CREATE TABLE Child
    (
     PK INT NOT NULL
            IDENTITY
    ,FK INT NOT NULL
    ,Nm VARCHAR(15)
    ,PRIMARY KEY ( PK )
    ) 
GO

ALTER TABLE Child
        WITH CHECK
ADD CONSTRAINT FK_Child_Parent FOREIGN KEY ( FK ) REFERENCES Parent ( PK )
GO

DECLARE @LastParent AS INT

INSERT  INTO Parent ( Nm )
VALUES  ( 'Donald Duck' )
SET @LastParent = SCOPE_IDENTITY()

INSERT  INTO Child ( FK, Nm )
VALUES  ( @LastParent, 'Huey' )
INSERT  INTO Child ( FK, Nm )
VALUES  ( @LastParent, 'Dewey' )
INSERT  INTO Child ( FK, Nm )
VALUES  ( @LastParent, 'Louie' )

SELECT  *
FROM    Parent
SELECT  *
FROM    Child
GO

BEGIN TRANSACTION
DELETE  FROM Child
WHERE   FK = ( SELECT   PK
               FROM     Parent
               WHERE    Nm = 'Donald Duck'
             )
 -- Run just to here
 -- In another session do this:
 -- INSERT INTO Child (FK, Nm) VALUES ((SELECT PK FROM Parent WHERE Nm = 'Donald Duck'), 'Cuckoo')
 -- Then return here
DELETE  FROM Parent
WHERE   Nm = 'Donald Duck' -- Should fail
IF @@ERROR <> 0 
    ROLLBACK TRANSACTION
ELSE 
    COMMIT TRANSACTION

SELECT  *
FROM    Parent
SELECT  *
FROM    Child

Otros consejos

Tanto sus enfoques son erróneos. Usted siempre debe:

  • inserción de los padres en primer lugar, a continuación, los niños
  • Actualización de los padres en primer lugar, a continuación, los niños
  • padres de eliminación en primer lugar, a continuación, los niños
  • Seleccione el primer padre, niño, entonces

Mejor aún, declarar la integridad referencial con eliminaciones en cascada y dejar que la manija de la supresión de los niños.

La esencia del problema es que usted tiene que elegir un orden y aferrarse a él, cualquier padre a hijo o hijo a padre. La tarde no tiene sentido en la mayoría de los casos, así que es mejor palo con la primera.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top