Eu tenho uma Competitions
tabela de resultados que contém os nomes dos membros da equipe e sua classificação, por um lado.
Por outro lado, preciso manter uma tabela com nomes exclusivos de concorrentes :
CREATE TABLE Competitors (cName nvarchar(64) primary key)
Agora, tenho cerca de 200.000 resultados na 1ª mesa e quando a tabela de concorrentes está vazia , posso fazer isso:
INSERT INTO Competitors SELECT DISTINCT Name FROM CompResults
E a consulta leva apenas 5 segundos para inserir cerca de 11.000 nomes.
Até o momento, este não é um aplicativo crítico, portanto, posso considerar truncar a tabela Concorrentes uma vez por mês, quando recebo os novos resultados da competição com cerca de 10.000 linhas.
Mas qual é a melhor prática quando novos resultados são adicionados, com novos concorrentes existentes E? Não quero truncar a tabela de concorrentes existentes
Preciso executar a declaração INSERT apenas para novos concorrentes e não fazer nada se eles existirem.
fonte
NVARCHAR(64)
coluna sua chave primária (e, portanto: cluster) !! Primeiro de tudo - é uma chave muito ampla - até 128 bytes; e segundo: o tamanho variável - novamente: não é o ideal ... Essa é a pior escolha que você pode ter - seu desempenho será um inferno, e a fragmentação de tabela e índice estará em 99,9% o tempo todo .....cName
falha em três das quatro categorias .... (não é estreitar, ele provavelmente não é estática, e definitivamente não é sempre crescente)Respostas:
Semântica, você está perguntando "inserir concorrentes onde ainda não existe":
fonte
Outra opção é deixar a tabela de resultados unida à tabela de concorrentes existentes e encontrar os novos concorrentes filtrando os registros distintos que não correspondem na associação:
A nova sintaxe MERGE também oferece uma maneira compacta, elegante e eficiente de fazer isso:
fonte
Não sei por que mais alguém não disse isso ainda;
NORMALIZAR.
Você tem uma mesa que modela competições? As competições são compostas por concorrentes? Você precisa de uma lista distinta de concorrentes em uma ou mais competições ......
Você deve ter as seguintes tabelas .....
Com restrições em CompetitionCompetitors.CompetitionID e CompetitorID apontando para as outras tabelas.
Com esse tipo de estrutura de tabela - suas chaves são INTS simples - não parece haver uma boa CHAVE NATURAL que se encaixaria no modelo, então acho que uma CHAVE SURROGATE é uma boa opção aqui.
Portanto, se você tiver isso, para obter a lista distinta de concorrentes em uma competição específica, você pode emitir uma consulta como esta:
E se você quisesse a pontuação para cada competição em que um concorrente estivesse:
E quando você tem uma nova competição com novos concorrentes, basta verificar quais já existem na tabela Competidores. Se eles já existem, você não insere no Concorrente para esses Concorrentes e insere nos novos.
Em seguida, você insere a nova Competição em Competição e, por fim, apenas cria todos os links em Competidores.
fonte
Você precisará juntar as mesas e obter uma lista de concorrentes únicos que ainda não existem
Competitors
.Isso irá inserir registros exclusivos.
Pode chegar um momento em que essa inserção precise ser feita rapidamente, sem poder aguardar a seleção de nomes exclusivos. Nesse caso, você pode inserir os nomes exclusivos em uma tabela temporária e, em seguida, usar essa tabela temporária para inserir em sua tabela real. Isso funciona bem porque todo o processamento acontece no momento em que você está inserindo uma tabela temporária, portanto não afeta sua tabela real. Então, quando todo o processamento estiver concluído, você fará uma inserção rápida na tabela real. Eu posso até envolver a última parte, onde você insere na tabela real, dentro de uma transação.
fonte
As respostas acima, que falam sobre normalização, são ótimas! Mas e se você se encontrar em uma posição como eu, onde não poderá tocar no esquema ou na estrutura do banco de dados como está? Por exemplo, os DBAs são 'deuses' e todas as revisões sugeridas vão para / dev / null?
A esse respeito, acho que isso também foi respondido com esta postagem do Stack Overflow em relação a todos os usuários acima, fornecendo exemplos de código.
Estou reposicionando o código de INSERT VALUES WHERE NOT EXISTS que mais me ajudou, pois não posso alterar nenhuma tabela de banco de dados subjacente:
O código acima usa campos diferentes dos que você possui, mas você obtém a essência geral das várias técnicas.
Observe que, conforme a resposta original no Stack Overflow, esse código foi copiado daqui .
De qualquer forma, meu argumento é "melhores práticas" muitas vezes se resume ao que você pode ou não fazer, assim como à teoria.
Boa sorte!
fonte
Normalizar suas tabelas operacionais, conforme sugerido pelo Transact Charlie, é uma boa idéia e economizará muitas dores de cabeça e problemas ao longo do tempo - mas existem coisas como tabelas de interface , que suportam integração com sistemas externos, e tabelas de relatório , que suportam coisas como analíticas em processamento; e esses tipos de tabelas não devem necessariamente ser normalizados - na verdade, muitas vezes é muito, muito mais conveniente e com desempenho para eles não serem .
Nesse caso, acho que a proposta do Transact Charlie para suas tabelas operacionais é boa.
Mas eu adicionaria um índice (não necessariamente exclusivo) ao CompetitorName na tabela Competitors para oferecer suporte a junções eficientes no CompetitorName para fins de integração (carregamento de dados de fontes externas) e colocaria uma tabela de interface na combinação: CompetitionResults.
Os resultados da competição devem conter quaisquer dados que os resultados da competição contenham. O objetivo de uma tabela de interface como esta é tornar o mais rápido e fácil possível truncá-lo e recarregá-lo de uma planilha do Excel ou de um arquivo CSV, ou de qualquer forma em que você tenha esses dados.
Essa tabela de interface não deve ser considerada parte do conjunto normalizado de tabelas operacionais. Em seguida, você pode ingressar no CompetitionResults, conforme sugerido por Richard, para inserir registros nos concorrentes que ainda não existem e atualizar os que existem (por exemplo, se você realmente tiver mais informações sobre os concorrentes, como o número de telefone ou endereço de email).
Uma coisa que eu observaria - na realidade, o nome do concorrente, parece-me, é muito improvável que seja único em seus dados . Em 200.000 concorrentes, você pode muito bem ter 2 ou mais David Smiths, por exemplo. Por isso, recomendo que você colete mais informações dos concorrentes, como número de telefone ou endereço de e-mail ou algo com maior probabilidade de ser único.
Sua tabela operacional, Concorrentes, deve ter apenas uma coluna para cada item de dados que contribui para uma chave natural composta; por exemplo, ele deve ter uma coluna para um endereço de email principal. Mas a tabela de interface deve ter um slot para antigos e novos valores para um endereço de email principal, para que o valor antigo possa ser usado para procurar o registro nos Concorrentes e atualizar essa parte para o novo valor.
Portanto, CompetitionResults deve ter alguns campos "antigos" e "novos" - oldEmail, newEmail, oldPhone, newPhone, etc. Dessa forma, você pode formar uma chave composta, em Concorrentes, em Nome do concorrente, E-mail e Telefone.
Então, quando você tiver alguns resultados de competição, poderá truncar e recarregar sua tabela CompetitionResults da planilha do Excel ou o que tiver, e executar uma inserção única e eficiente para inserir todos os novos concorrentes na tabela Competidores e atualizar uma atualização eficiente para atualizar todas as informações sobre os concorrentes existentes nos resultados da competição. E você pode fazer uma única inserção para inserir novas linhas na tabela CompetitionCompetitors. Essas coisas podem ser feitas em um procedimento armazenado ProcessCompetitionResults, que pode ser executado após o carregamento da tabela CompetitionResults.
Essa é uma espécie de descrição rudimentar do que eu vi repetidamente no mundo real com Oracle Applications, SAP, PeopleSoft e uma lista completa de outros pacotes de software corporativo.
Um último comentário que eu faria é o que fiz antes no SO: Se você criar uma chave estrangeira que garanta a existência de um Concorrente na tabela Concorrentes antes de poder adicionar uma linha com esse Concorrente a CompetitionCompetitors, verifique se chave estrangeira está definida para cascata atualizações e exclusões . Dessa forma, se você precisar excluir um concorrente, poderá fazê-lo e todas as linhas associadas a esse concorrente serão excluídas automaticamente. Caso contrário, por padrão, a chave estrangeira exigirá que você exclua todas as linhas relacionadas dos CompetitionCompetitors antes de permitir que você exclua um Concorrente.
(Algumas pessoas pensam que chaves estrangeiras não em cascata são uma boa precaução de segurança, mas minha experiência é que elas são apenas uma dor no traseiro que, na maioria das vezes, são simplesmente resultado de uma supervisão e criam um monte de trabalho Para lidar com pessoas que excluem acidentalmente coisas, é por isso que você tem coisas como "tem certeza" e vários tipos de backups regulares e fontes de dados redundantes.É muito, muito mais comum querer excluir um concorrente, cujos dados são todos errei por exemplo, do que excluir acidentalmente um e depois dizer "Ah, não! Eu não pretendia fazer isso! E agora não tenho os resultados de suas competições! Aaaahh!" Este último certamente é bastante comum, então , você precisa estar preparado para isso, mas o primeiro é muito mais comum,portanto, a melhor e mais fácil maneira de se preparar para a primeira, imo, é apenas fazer com que as chaves estrangeiras façam atualizações e exclusões em cascata.)
fonte
Ok, isso foi solicitado há 7 anos, mas acho que a melhor solução aqui é renunciar inteiramente à nova tabela e fazer isso como uma exibição personalizada. Dessa forma, você não está duplicando dados, não há preocupação com dados exclusivos e não toca na estrutura real do banco de dados. Algo assim:
Outros itens podem ser adicionados aqui, como junções em outras tabelas, cláusulas WHERE etc. Essa é provavelmente a solução mais elegante para esse problema, pois agora você pode apenas consultar a exibição:
... e adicione cláusulas WHERE, IN ou EXISTS à consulta de exibição.
fonte