Em um aplicativo Web em que estou trabalhando, todas as operações do banco de dados são abstraídas usando alguns repositórios genéricos definidos no ORM do Entity Framework.
No entanto, para ter um design simples para os repositórios genéricos, todas as tabelas envolvidas devem definir um número inteiro exclusivo ( Int32
em C #, int
em SQL). Até agora, este sempre foi o PK da tabela e também o IDENTITY
.
Chaves estrangeiras são muito usadas e fazem referência a essas colunas inteiras. Eles são necessários para consistência e para gerar propriedades de navegação pelo ORM.
A camada de aplicativo geralmente executa as seguintes operações:
- carregamento inicial de dados da tabela (*) -
SELECT * FROM table
- Atualização -
UPDATE table SET Col1 = Val1 WHERE Id = IdVal
- Excluir -
DELETE FROM table WHERE Id = IdVal
- Inserir -
INSERT INTO table (cols) VALUES (...)
Operações menos frequentes:
- Inserção em massa -
BULK INSERT ... into table
seguida (*) por toda a carga de dados (para recuperar identificadores gerados) - Exclusão em massa - esta é uma operação de exclusão normal, mas "volumosa" da perspectiva do ORM:
DELETE FROM table where OtherThanIdCol = SomeValue
- Atualização em massa - esta é uma operação de atualização normal, mas "volumosa" da perspectiva do ORM:
UPDATE table SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue
* todas as tabelas pequenas são armazenadas em cache no nível do aplicativo e quase todas SELECTs
não atingem o banco de dados. Um padrão típico é carga inicial e muita INSERT
s, UPDATE
s e DELETE
s.
Com base no uso atual do aplicativo, há uma chance muito pequena de atingir 100 milhões de registros em qualquer uma das tabelas.
Pergunta: Na perspectiva do DBA, existem problemas significativos com os quais posso ter essa limitação de design da tabela?
[EDITAR]
Depois de ler as respostas (obrigado pelo ótimo feedback) e os artigos referenciados, sinto que preciso adicionar mais detalhes:
Especificações atuais do aplicativo - não mencionei o aplicativo da Web atual, porque quero entender se o modelo também pode ser reutilizado para outros aplicativos. No entanto, meu caso particular é um aplicativo que extrai muitos metadados de um DWH. Os dados de origem são bastante confusos (desnormalizados de uma maneira estranha, com algumas inconsistências, sem identificador natural em muitos casos etc.) e meu aplicativo está gerando entidades separadas e claras. Além disso, muitos dos identificadores gerados (
IDENTITY
) são exibidos, para que o usuário possa usá-los como chaves comerciais. Além de uma grande refatoração de código, isso exclui o uso de GUIDs ."eles não devem ser a única maneira de identificar uma linha de maneira única" (Aaron Bertrand ♦) - esse é um conselho muito bom. Todas as minhas tabelas também definem uma restrição exclusiva para garantir que duplicatas de negócios não sejam permitidas.
Design orientado a aplicativos front-end vs. Design orientado a banco de dados - a escolha do design é causada por esses fatores
Limitações do Entity Framework - PKs de várias colunas são permitidas, mas seus valores não podem ser atualizados
Limitações personalizadas - ter uma única chave inteira simplifica muito as estruturas de dados e o código não-SQL. Por exemplo: todas as listas de valores têm uma chave inteira e valores exibidos. Mais importante, garante que qualquer tabela marcada para armazenamento em cache poderá colocar em um
Unique int key -> value
mapa.
Consultas de seleção complexas - isso quase nunca acontece porque todos os dados de tabelas pequenas (<20-30K registros) são armazenados em cache no nível do aplicativo. Isso torna a vida um pouco mais difícil ao escrever o código do aplicativo (mais difícil de escrever o LINQ), mas o banco de dados é muito melhor:
Exibições de lista - não gerará
SELECT
consultas no carregamento (tudo está armazenado em cache) ou consultas com esta aparência:SELECT allcolumns FROM BigTable WHERE filter1 IN (val1, val2) AND filter2 IN (val11, val12)
Todos os outros valores necessários são buscados por meio de pesquisas em cache (O (1)), portanto, nenhuma consulta complexa será gerada.
Editar visualizações - gerará
SELECT
instruções como esta:SELECT allcolumns FROM BigTable WHERE PKId = value1
(todos os filtros e valores são int
s)