Qual é a arquitetura de índice apropriada quando forçada a implementar IsDeleted (exclusões suaves)?

16

Atualmente, temos um banco de dados e aplicativo existentes que são totalmente funcionais. Eu não tenho a capacidade de alterar a arquitetura neste momento. Hoje, cada tabela no banco de dados possui um campo "IsDeleted" NOT NULL BIT com o padrão '0'. Quando o aplicativo "exclui" dados, ele simplesmente atualiza o sinalizador IsDeleted para 1.

O que estou tendo problemas para entender é como os índices em cada uma das tabelas devem ser estruturados. No momento, todas as consultas / associações / etc sempre implementam a verificação IsDeleted. É um padrão que nossos desenvolvedores devem seguir. Dito isto, estou tentando determinar se todos os meus índices de chave primária em cluster em cada uma das tabelas precisam ser alterados para incluir a chave primária AND o campo IsDeleted BIT. Além disso, desde CADA consulta / junção / etc. deve implementar a verificação IsDeleted, é uma suposição apropriada que TODOS os índices (também não agrupados em cluster) incluam o campo IsDeleted como o primeiro campo do índice?

Outra pergunta que tenho é sobre índices filtrados. Eu entendo que eu poderia colocar filtros nos índices como "WHERE IsDeleted = 0" para reduzir o tamanho dos índices. No entanto, como toda junção / consulta precisará implementar a verificação IsDeleted, isso impediria o uso do índice filtrado (já que a coluna IsDeleted é usada na junção / consulta)?

Lembre-se, eu não tenho a capacidade de alterar a abordagem IsDeleted.

Philᵀᴹ
fonte

Respostas:

13

A abordagem mais fácil aqui é deixar suas chaves e índices agrupados em paz e usar índices filtrados para seus índices não agrupados.

Além disso, você pode migrar algumas tabelas grandes para heaps particionados ou lojas de colunas em cluster particionadas (SQL Server 2016 ou superior), deixando a chave primária e os índices exclusivos não particionados. Isso permitiria enviar por push as colunas não chave das linhas IsDeleted para uma estrutura de dados separada, que também poderia ser compactada de maneira diferente ou armazenada em um grupo de arquivos diferente.

E verifique se os desenvolvedores usam um literal em vez de um parâmetro para filtrar as linhas IsDeleted. Com um parâmetro, o SQL Server precisa usar o mesmo plano de consulta para os dois casos.

POR EXEMPLO

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

E não:

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

O uso de um parâmetro impedirá o uso do índice filtrado e poderá causar problemas com a detecção de parâmetros.

David Browne - Microsoft
fonte
Dada a onipresença e a importância da IsDeletedcoluna, independentemente do armazenamento físico, provavelmente faria sentido expor os dados por meio de duas visualizações (opcionalmente em esquemas diferentes), resolvendo o problema de parametrização e cometendo erros ao acessar dados que não deveriam ter sido acessado menos provável. O acesso aos dados base é relevante apenas nos casos raros em que os dados excluídos e não excluídos precisam ser combinados de alguma forma e quando as linhas realmente precisam ser alteradas para "excluídas".
Jeroen Mostert
@JeroenMostert bons conselhos. O RLS também pode ser usado aqui, ou algo como Filtros de Consulta Global da EF Core. docs.microsoft.com/en-us/ef/core/querying/filters
David Browne - Microsoft
9

Pode ser uma opinião impopular, mas não acho que haja uma resposta "faça isso em todos os lugares" / tamanho único para a sua pergunta.

Se você tiver consultas que estão varrendo muitas linhas IsDeleted sem motivo, uma solução é criar um índice filtrado e não clusterizado para atender a essa consulta.

Outra opção é criar uma exibição indexada que possa ser aproveitada por várias consultas diferentes, que são filtradas apenas para as linhas não excluídas. Isso pode ser especialmente útil no Enterprise Edition, em que a correspondência automática de exibição indexada funciona sem fornecer uma NOEXPANDdica.

Para tabelas pequenas, ou tabelas que são lidas intensamente, a adição de índices ou visualizações filtrados não clusterizados ou qualquer coisa realmente pode estar adicionando sobrecarga desnecessária ao seu banco de dados.

Josh Darnell
fonte
2

Sob a suposição razoável de que exclusões são raras, nenhuma alteração nos índices é uma solução apropriada.

Descobri que mais cedo ou mais tarde é preciso consultar referências a linhas excluídas, e as linhas que estão nos índices subitamente valem a pena.

Observe que, a menos que você esteja usando visualizações, é necessário editar todas as suas consultas para incluir os filtros de qualquer maneira.

Joshua
fonte
0

Eu vi um sistema em que o sinalizador IS_DELETED é 0 ou o valor do PK. Em outros sistemas, era o negativo do PK.

Como a maioria das consultas recuperou valores pela chave "natural" ou comercial (às vezes com vários campos), elas nunca consultaram pelo PK, exceto por meio de junções; mas eles sempre adicionavam AND IS_DELETED = 0 no final da tabela principal e de todas as tabelas associadas.

Esse sistema também tinha uma tabela de auditoria para todas as tabelas transacionais que controlavam as alterações; e o aplicativo tinha um recurso para exibir todas as alterações de dados, incluindo os dados excluídos.

Rick Ryker
fonte
0

Espero que você tenha o direito e a capacidade de alterar a consulta.

No entanto, como toda junção / consulta precisará implementar a verificação IsDeleted, isso impediria o uso do índice filtrado (já que a coluna IsDeleted é usada na junção / consulta)?

Eu queria dizer um ponto importante, espero poder explicar.

Em consultas complexas, onde Transaction tablee Mastertabelas são usadas.

Use IsDeleted=0apenas na Transactiontabela. Não use na Mastertabela.

Exemplo,

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

Não há nenhum ponto c.isdeleted=0(usando na Categorytabela). É desnecessário.

Da mesma forma, há algum ponto em usar P.isdeleted=0?

Porque eu quero toda a Ordem não recuperada e seus detalhes.

Como pode Productser excluído quando Orderé Activeou onde Productidé referência.

Portanto, dessa maneira, se você depurar cuidadosamente em consultas importantes, poderá remover alguns dos isdeleted = 0.

Não crie cegamente o índice filtrado, primeiro selecione todas as consultas muito importantes e lentas.

Otimize essas consultas lentas e decida apenas sobre o Índice Filtrado ou ajuste o Índice.

KumarHarsh
fonte