Qual é a melhor maneira de remover linhas duplicadas de uma SQL Server
tabela bastante grande (ou seja, mais de 300.000 linhas)?
As linhas, é claro, não serão duplicatas perfeitas devido à existência do RowID
campo de identidade.
Minha mesa
RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null
sql-server
tsql
duplicates
Seibar
fonte
fonte
DELETE FROM
usá-lo diretamente. Veja stackoverflow.com/q/18439054/398670ROWID()
função pela coluna RowID, se houver)Respostas:
Assumindo que não há nulos,
GROUP BY
as colunas exclusivas eSELECT
oMIN (or MAX)
RowId são a linha a ser mantida. Em seguida, exclua tudo o que não tinha um ID de linha:Caso você tenha um GUID em vez de um número inteiro, poderá substituir
com
fonte
DELETE FROM MyTable WHERE RowId NOT IN (SELECT MIN(RowId) FROM MyTable GROUP BY Col1, Col2, Col3);
LEFT JOIN
é menos eficiente queNOT EXISTS
sqlinthewild.co.za/index.php/2010/03/23/... O mesmo site também comparaNOT IN
vsNOT EXISTS
. sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in Fora dos 3, acho que tem oNOT EXISTS
melhor desempenho. Todos os três irão gerar um plano com uma associação automática, embora isso possa ser evitado.DELETE MyTable FROM MyTable
a sintaxe correta? Não vejo como colocar o nome da tabela logo após aDELETE
opção como na documentação aqui . Desculpe se isso é óbvio para os outros; Eu sou um novato no SQL apenas tentando aprender. Mais importante do que por que funciona: qual é a diferença entre incluir o nome da tabela ou não?Outra maneira possível de fazer isso é
Estou usando
ORDER BY (SELECT 0)
acima, pois é arbitrário qual linha preservar em caso de empate.Para preservar o mais recente
RowID
, por exemplo, você pode usarORDER BY RowID DESC
Planos de Execução
O plano de execução para isso geralmente é mais simples e mais eficiente do que o da resposta aceita, pois não requer a auto-junção.
Nem sempre é esse o caso. Um local em que a
GROUP BY
solução pode ser preferida são as situações em que um agregado de hash seria escolhido em preferência a um agregado de fluxo.A
ROW_NUMBER
solução sempre dará praticamente o mesmo plano, enquanto aGROUP BY
estratégia é mais flexível.Fatores que podem favorecer a abordagem agregada de hash seriam
Nas versões extremas desse segundo caso (se houver muito poucos grupos com muitas duplicatas em cada um), também seria possível inserir simplesmente as linhas para manter em uma nova tabela e, em seguida, inserir
TRUNCATE
o original e copiá-las para minimizar o registro em comparação com a exclusão de um proporção muito alta das linhas.fonte
uniqueidentifier
. Este é muito mais simples e funciona perfeitamente em qualquer mesa. Obrigado Martin.RowId
) para comparar.Há um bom artigo sobre como remover duplicatas no site de suporte da Microsoft. É bastante conservador - eles fazem tudo em etapas separadas - mas devem funcionar bem em grandes mesas.
Eu usei auto-junções para fazer isso no passado, embora provavelmente possa ser usado com uma cláusula HAVING:
fonte
A consulta a seguir é útil para excluir linhas duplicadas. A tabela neste exemplo tem
ID
como coluna de identidade e as colunas com dados duplicados sãoColumn1
,Column2
eColumn3
.A seguir mostra de script uso
GROUP BY
,HAVING
,ORDER BY
em uma consulta, e retorna os resultados com coluna duplicado e sua contagem.fonte
NOT IN
muitas vezes tem um desempenho melhor queOUTER JOIN ... NULL
. Eu gostaria de acrescentar umHAVING MAX(ID) IS NOT NULL
para a consulta que embora semanticamente não deve ser necessário como que pode melhorar o plano exemplo de que aquiPostgres:
fonte
fonte
Isso excluirá linhas duplicadas, exceto a primeira linha
Consulte ( http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server )
fonte
Eu preferiria o CTE para excluir linhas duplicadas da tabela do servidor sql
é altamente recomendável seguir este artigo :: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/
fonte
Para buscar linhas duplicadas:
Para excluir as linhas duplicadas:
fonte
DELETE FROM
, em segundo lugar, não funcionará, porque você não podeSELECT
da mesma tabela da qual você éDELETE
. No MySQL, isso disparaMySQL error 1093
.Rápido e Sujo para excluir linhas duplicadas exatas (para tabelas pequenas):
fonte
Prefiro a subconsulta \ tendo a solução count (*)> 1 à junção interna porque achei mais fácil ler e foi muito fácil transformar uma instrução SELECT para verificar o que seria excluído antes da execução.
fonte
MAX(id)
para eliminar as últimas duplicatas e adicioneiLIMIT 1000000
à consulta interna para que não fosse necessário verificar a tabela inteira. Isso mostrou um progresso muito mais rápido do que as outras respostas, que pareceriam travar por horas. Depois que a tabela foi removida para um tamanho gerenciável, você poderá concluir as outras consultas. Dica: verifique se col1 / col2 / col3 possui índices para agrupar por.fonte
Eu pensei em compartilhar minha solução, pois ela funciona em circunstâncias especiais. No meu caso, a tabela com valores duplicados não tinha uma chave estrangeira (porque os valores foram duplicados de outro banco de dados).
PS: ao trabalhar em coisas como essa, eu sempre uso uma transação, isso não apenas garante que tudo seja executado como um todo, mas também me permite testar sem arriscar nada. Mas é claro que você deve fazer um backup de qualquer maneira apenas para ter certeza ...
fonte
Esta consulta mostrou um desempenho muito bom para mim:
excluiu 1 milhão de linhas em pouco mais de 30 segundos de uma tabela de 2 milhões (50% de duplicatas)
fonte
Usando CTE. A idéia é ingressar em uma ou mais colunas que formam um registro duplicado e remover o que você quiser:
fonte
Ainda outra solução fácil pode ser encontrada no link colado aqui . Este é fácil de entender e parece ser eficaz para a maioria dos problemas semelhantes. É para o SQL Server, mas o conceito usado é mais do que aceitável.
Aqui estão as partes relevantes da página vinculada:
Considere estes dados:
Então, como podemos excluir esses dados duplicados?
Primeiro, insira uma coluna de identidade nessa tabela usando o seguinte código:
Use o seguinte código para resolvê-lo:
fonte
ROW_NUMBER
versão funciona bem para esse caso, sem a necessidade de adicionar uma nova coluna antes de começar.Aqui está outro bom artigo sobre como remover duplicatas .
Ele discute por que é difícil: "O SQL é baseado em álgebra relacional e duplicatas não podem ocorrer na álgebra relacional, porque duplicatas não são permitidas em um conjunto " .
A solução da tabela temporária e dois exemplos de mysql.
No futuro, você evitará isso no nível do banco de dados ou da perspectiva do aplicativo. Eu sugeriria o nível do banco de dados porque seu banco de dados deve ser responsável por manter a integridade referencial; os desenvolvedores apenas causarão problemas;)
fonte
Ah com certeza. Use uma tabela temporária. Se você deseja uma declaração única e de baixo desempenho que "funcione", você pode:
Basicamente, para cada linha da tabela, a sub-seleção localiza o RowID superior de todas as linhas exatamente iguais à linha em consideração. Então você acaba com uma lista de RowIDs que representam as linhas não duplicadas "originais".
fonte
Eu tinha uma tabela em que precisava preservar linhas não duplicadas. Não tenho certeza da velocidade ou eficiência.
fonte
HAVING COUNT(*) > 1
?Usa isto
fonte
A outra maneira é criar uma nova tabela com os mesmos campos e com índice exclusivo . Em seguida, mova todos os dados da tabela antiga para a nova tabela . Automaticamente, o SQL SERVER ignora (há também uma opção sobre o que fazer se houver um valor duplicado: ignorar, interromper ou sth) valores duplicados. Portanto, temos a mesma tabela sem linhas duplicadas. Se você não deseja um Índice Único, após a transferência dos dados, você pode soltá-lo .
Especialmente para tabelas maiores, você pode usar o DTS (pacote SSIS para importar / exportar dados) para transferir todos os dados rapidamente para sua nova tabela indexada exclusivamente. Para 7 milhões de linhas, leva apenas alguns minutos.
fonte
Usando a consulta abaixo, podemos excluir registros duplicados com base na coluna única ou na coluna múltipla. a consulta abaixo é excluída com base em duas colunas. o nome da tabela é:
testing
e os nomes das colunasempno,empname
fonte
Criar nova tabela em branco com a mesma estrutura
Executar consulta como esta
Em seguida, execute esta consulta
fonte
Esta é a maneira mais fácil de excluir registros duplicados
http://askme.indianyouth.info/details/how-to-dumplicate-record-from-table-in-using-sql-105
fonte
Eu mencionaria essa abordagem da melhor maneira possível e funciona em todos os servidores SQL: Muitas vezes, há apenas uma - duas duplicatas, e os IDs e a contagem de duplicatas são conhecidos. Nesse caso:
fonte
Não sei como seria o desempenho, mas acho que você poderia escrever um gatilho para impor isso, mesmo que não pudesse fazê-lo diretamente com um índice. Algo como:
Além disso, varchar (2048) me parece suspeito (algumas coisas na vida são 2048 bytes, mas é bastante incomum); realmente não deveria ser varchar (max)?
fonte
Outra maneira de fazer isso: -
fonte
fonte
fonte
Você deseja visualizar as linhas que está prestes a remover e manter o controle sobre quais linhas duplicadas devem ser mantidas. Consulte http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/
fonte