¿Cuál es la arquitectura de índice apropiada cuando se ve obligado a implementar IsDeleted (eliminaciones suaves)?

16

Actualmente, tenemos una base de datos y una aplicación existentes que es completamente funcional. No tengo la capacidad de cambiar la arquitectura en este momento. Hoy, cada tabla en la base de datos tiene un campo "IsDeleted" NOT NULL BIT con un valor predeterminado de '0'. Cuando la aplicación "elimina" datos, simplemente actualiza el indicador IsDeleted a 1.

Lo que me cuesta entender es cómo deben estructurarse los índices en cada una de las tablas. En este momento, cada consulta / join / etc siempre implementa la verificación IsDeleted. Es un estándar que nuestros desarrolladores deben seguir. Dicho esto, estoy tratando de determinar si todos mis índices de claves primarias agrupadas en cada una de las tablas deben modificarse para incluir la clave primaria Y el campo BIT IsDeleted. Además, desde CADA consulta / unión / etc. debe implementar la verificación IsDeleted, ¿es una suposición apropiada que CADA índice SOLO (no agrupado también) debe incluir el campo IsDeleted como el primer campo del índice?

Otra pregunta que tengo es sobre los índices filtrados. Entiendo que podría poner filtros en los índices como "WHERE IsDeleted = 0" para reducir el tamaño de los índices. Sin embargo, dado que cada unión / consulta tendrá que implementar la verificación IsDeleted, ¿eso evitaría que se use el índice filtrado (dado que la columna IsDeleted se usa en join / query)?

Recuerde, no tengo la capacidad de cambiar el enfoque IsDeleted.

Philᵀᴹ
fuente

Respuestas:

13

El enfoque más fácil aquí es dejar sus claves e índices agrupados solos, y utilizar índices filtrados para sus índices no agrupados.

Además, puede migrar algunas tablas grandes a montones particionados o almacenes de columnas agrupadas particionadas (SQL Server 2016+), dejando la clave primaria y los índices únicos sin particionar. Esto le permitiría empujar las columnas sin clave para las filas IsDeleted a una estructura de datos separada, que además podría comprimirse de manera diferente o almacenarse en un grupo de archivos diferente.

Y asegúrese de que los desarrolladores usen un literal en lugar de un parámetro para filtrar las filas IsDeleted. Con un parámetro, SQL Server tiene que usar el mismo plan de consulta para ambos casos.

P.EJ

SELECT ... WHERE ... AND IsDeleted=0

Y no:

SELECT ... WHERE ... AND IsDeleted=@IsDeleted

El uso de un parámetro evitará el uso del índice filtrado y puede ocasionarle problemas con la detección de parámetros.

David Browne - Microsoft
fuente
Dada la ubicuidad y la importancia de la IsDeletedcolumna, independientemente del almacenamiento físico, probablemente tendría sentido exponer los datos a través de dos vistas (opcionalmente en diferentes esquemas), resolviendo el problema de parametrización y cometiendo errores al acceder a datos que no deberían haber sido Accedido menos probable. El acceso a los datos base solo es relevante para los casos excepcionales en los que los datos eliminados y no eliminados deben combinarse de alguna manera, y cuando las filas realmente deben cambiarse a "eliminadas".
Jeroen Mostert
@JeroenMostert buenos consejos. RLS también se puede usar aquí, o algo así como los filtros de consulta global EF Core. docs.microsoft.com/en-us/ef/core/querying/filters
David Browne - Microsoft
9

Esta podría ser una opinión impopular, pero no creo que haya una respuesta "haz esto en todas partes" / talla única para tu pregunta.

Si tiene consultas que escanean muchas filas IsDeleted sin ningún motivo, una solución es crear un índice filtrado y no agrupado para satisfacer esa consulta.

Otra opción es crear una vista indizada que pueda ser aprovechada por una serie de consultas diferentes, que se filtra solo a las filas no eliminadas. Esto podría ser especialmente útil en Enterprise Edition, donde la coincidencia de vista indexada automática funciona sin proporcionar una NOEXPANDpista.

Para tablas pequeñas, o tablas que se leen en gran medida, agregar índices o vistas filtradas no agrupadas o cualquier cosa realmente podría agregar una sobrecarga innecesaria a su base de datos.

Josh Darnell
fuente
2

Bajo el supuesto razonable de que las eliminaciones son raras, no hay cambios en los índices es una solución adecuada.

Descubrí que, tarde o temprano, uno debe buscar referencias a filas eliminadas, y las filas que están en los índices de repente valen la pena.

Tenga en cuenta que, a menos que esté utilizando vistas, debe editar todas sus consultas para incluir los filtros de todos modos.

Joshua
fuente
0

He visto un sistema donde el indicador IS_DELETED es 0 o el valor de PK. En otros sistemas fue el negativo de la PK.

Como la mayoría de las consultas recuperaron valores mediante la clave "natural" o empresarial (a veces de múltiples campos), nunca consultaron por PK, excepto a través de combinaciones; pero siempre agregaron un AND IS_DELETED = 0 al final para la tabla principal y para cualquier tabla unida.

Este sistema también tenía una tabla de auditoría para cada tabla transaccional que rastreaba los cambios; y la aplicación tenía una función para mostrar todos los cambios de datos, incluidos los datos eliminados.

Rick Ryker
fuente
0

Espero que tenga el derecho y la capacidad de cambiar la consulta.

Sin embargo, dado que cada unión / consulta tendrá que implementar la verificación IsDeleted, ¿eso evitaría que se use el índice filtrado (dado que la columna IsDeleted se usa en join / query)?

Quería decir un punto importante, espero poder explicarlo.

En consulta compleja dónde Transaction tableyMaster tablas se usan ambas.

Usar IsDeleted=0solo en la Transactionmesa. No utilizar enMaster mesa.

Ejemplo,

Select * from dbo.Order O
inner join dbo.category C on o.categoryid=o.categoryid
inner join dbo.Product P on P.Productid=o.Productid
where o.isdeleted=0

No tiene sentido c.isdeleted=0(usar en la Categorytabla). Es innecesario.

Del mismo modo, ¿hay algún punto en el uso P.isdeleted=0?

Porque quiero todos los pedidos sin recuperar y sus detalles.

Cómo se Productpuede eliminar cuando Orderes Activeo donde Productidsea ​​referencia.

De esta manera, si depura cuidadosamente en una consulta importante, puede eliminar algo de isdeleted = 0.

No cree ciegamente un índice filtrado, primero seleccione todas esas consultas muy importantes y lentas.

Optimice esas consultas lentas y luego solo decida sobre el índice filtrado o ajuste el índice.

KumarHarsh
fuente