Pro SQL Server Relational Database Design and Implementation: Best Practices for Scalability and Performance é uma fonte muito confiável de boas ideias de design de banco de dados. Como alternativa ao Entity-Attribute-Value, ele sugere usar SQL dinâmico para permitir que seus usuários adicionem novas colunas esparsas a uma tabela.
Para mim, essa ideia fede. Adicionar novas colunas requer um bloqueio de modificação de esquema. Esse é um bloqueio muito sério e eu preferiria que meus usuários não tivessem a capacidade de obtê-lo.
Existe alguma propriedade de colunas esparsas que faz com que permitir que os usuários assumam um bloqueio tão sério não seja tão terrível quanto seria para outros tipos de coluna?
Embora louvável, sua preocupação em adicionar e remover colunas é, em grande parte, equivocada.
Adicionar uma coluna anulável é uma operação somente de metadados: ou seja, ela só envolve pequenas alterações na definição da tabela do banco de dados em tabelas internas e não requer a reescrita dos índices clusterizados e todos os índices não clusterizados. Isso significa que tal modificação é muito rápida. Da mesma forma, remover uma coluna também é somente de metadados, pois o mecanismo de armazenamento simplesmente ignorará esses dados até que cada página seja eventualmente substituída sem eles.
Você pode ver isso em ação neste violino .
SET STATISTICS IO ON
é usado para mostrar leituras da própria tabela, e você pode ver que isso só acontece na adição de uma coluna não anulável.Suas únicas preocupações reais devem ser:
Por exemplo, uma longa execução
SELECT
mantém umSch-S
bloqueio na tabela. OALTER
tenta pegar umSch-M
bloqueio e espera. Todas as outrasSELECT
consultas de modificação então se acumulam atrás dele, esperando por seu próprioSch-S
bloqueio que eles podem pegar.Infelizmente, isso não pode ser evitado usando
WAIT_AT_LOW_PRIORITY
, pois isso ainda não foi implementado para esse tipo deALTER
. Sua melhor aposta é colocar o seguinte antes do seuALTER
:Por que não? (Claro que posso listar um monte de razões teóricas, mas...) Independentemente se seus usuários fizerem uma alteração de esquema ou se você, como desenvolvedor, fizer essas mesmas alterações, um bloqueio de modificação de esquema será necessário. A maioria dos casos de uso em que os usuários finais têm esse acesso estão em um mundo limitado, onde eles estariam apenas atirando em si mesmos ou em sua equipe no pé. Em um ambiente multilocatário, não deve haver cruzamento, e os locatários devem ser separados de qualquer maneira.
Outras medidas de design de aplicativos podem ser implementadas para minimizar os danos causados pelos usuários finais que também se dão socos no rosto, como execução atrasada das alterações de esquema (por exemplo, uma fila agendada para executar o SQL gerado fora do horário comercial) e limitar o acesso a essa capacidade para usuários privilegiados de administrador do aplicativo.
Novamente, não acredito nisso, e a solução deve ser uma solução arquitetônica. Além do que mencionei acima, outras escolhas de design que podem mitigar o risco disso são ter uma quantidade predefinida de colunas de vários tipos de dados que são mapeadas individualmente quando o usuário final precisa de uma coluna personalizada, ou ter uma tabela separada, por exemplo,
ObjectNameExtended
onde novas colunas são adicionadas dinamicamente pelos usuários para que o bloqueio de modificação do esquema afete apenas as personalizações e não o aplicativo nativo, pelo menos.Além disso, como Erik Darling apontou, as colunas esparsas têm um conjunto de limitações que podem ser bem ruins, como impedir que você compacte quaisquer tabelas/índices dos quais elas fazem parte:
Além disso, de um anúncio de manutenção nesta rede: