Tabela de remoção de dados do servidor SQL

Tenho um problema. Eu tenho uma mesa com quase 2 bilhões de linhas (sim, eu sei...) e tem um monte de dados duplicados nele que eu gostaria de excluir dele. Estava a pensar como fazer isso, exactamente?

as colunas são: Primeiro, Último, dob, endereço, cidade,estado, zip, telefone e estão em uma tabela chamada {[[0]}. Cada registro tem um ID único felizmente, e seu na coluna chamada ID.

Como posso retirar isto e deixar uma entrada única (linha) dentro da tabela pf_main para cada pessoa??

agradeço antecipadamente as vossas respostas...

Author: marc_s, 2014-08-07

5 answers

Uma mesa de 2 mil milhões de linhas é bastante grande. Deixe-me assumir que first, last, e dob constitui uma "pessoa". Minha sugestão é construir um índice sobre a "pessoa" e então fazer a abordagem truncate/re-inserir. Na prática, isto parece:
create index idx_pf_main_first_last_dob on pf_main(first, last, dob);

select m.*
into temp_pf_main
from pf_main m
where not exists (select 1
                  from pf_main m2
                  where m2.first = m.first and m2.last = m.last and m2.dob = m.dob and
                        m2.id < m.id
                 );

truncate table pf_main;

insert into pf_main
    select *
    from temp_pf_main;
 2
Author: Gordon Linoff, 2014-08-30 01:07:56
SELECT 
   ID, first, last, dob, address, city, state, zip, telephone, 
   ROW_NUMBER() OVER (PARTITION BY first, last, dob, address, city, state, zip, telephone ORDER BY ID) AS RecordInstance
FROM PF_main

Dar-lhe-á o "número" de cada item único (ordenado por Id)

Por isso, se tiver os seguintes registos:

Id, último, primeiro, D. N., endereço, cidade, estado, zip, telefone
006, trevelyan, alec, '1954-05-15', '85 Albert Embankment', 'London', "UK", "1SE1 7TP", 0064
007, bond, james, '1957-02-08', '85 Albert Embankment', 'London', "UK", "1SE1 7TP", 0074
008, bond, james, '1957-02-08', '85 Albert Embankment', 'London', "UK", " SE1 7TP", 0074
009, bond, james, '1957-02-08', '85 Albert Embankment', 'London', "UK", "SE1 7TP", 0074

Obterá os seguintes resultados (nota na última coluna)

006, trevelyan, alec, '1954-05-15', '85 Albert Embankment', 'London', "UK", "1SE1 7TP', 0064, 1
007, bond, james, '1957-02-08', '85 Albert Embankment', 'London', "UK", "1SE1 7TP', 0074, 1
008, bond, james, '1957-02-08', '85 Albert Embankment', 'London', "UK", "SE1 7TP', 0074, 2
009, bond, james, '1957-02-08', '85 Albert Embankment', 'London', "UK", "SE1 7TP', 0074, 3

Pode Apagar Registos com registo > 1:
WITH Records AS
(
   SELECT 
      ID, first, last, dob, address, city, state, zip, telephone,
      ROW_NUMBER() OVER (PARTITION BY first, last, dob, address, city, state, zip, telephone ORDER BY ID) AS RecordInstance
   FROM PF_main
)
DELETE FROM Records
WHERE RecordInstance > 1
 6
Author: Mark Sowul, 2014-08-07 04:50:02

Outras respostas certamente dar-lhe-ão ideias quanto à sintaxe.

Com 2 bilhões de linhas, suas preocupações podem envolver outras coisas além da sintaxe, então eu vou lhe dar uma resposta genérica que funciona em muitas bases de dados. Se você não puder dar ao luxo de fazer a remoção ou cópia "online" em uma sessão, ou estão com pouco espaço, então considere a seguinte abordagem incremental.

Apaga este grande pode demorar muito, muito tempo a completar, como em horas ou até mesmo dias, e também pode correr o risco de falhar antes conclusao. Em alguns casos, a abordagem que funcionou melhor, surpreendentemente, foi um procedimento rudimentar, de longa duração armazenado que tomou pequenos lotes e cometeu todos os poucos registros (poucos sendo um termo relativo aqui). Poucos podem ter 100 ou 1000 ou 10000 discos. Claro que não parece elegante, mas o ponto é que é "incremental" e um consumidor de baixo recurso.

A ideia é identificar uma chave de parcionamento através da qual você pode abordar intervalos de registos (para partição do seu conjunto de trabalho), ou faça uma consulta inicial para identificar as chaves duplicadas de outra tabela. Em seguida, iterar através dessas teclas um pequeno lote de cada vez, excluir, em seguida, commit, e repetir. Se o fizer ao vivo sem uma tabela temp, certifique-se de manter os intervalos pequenos, adicionando critérios apropriados para reduzir os conjuntos de resultados, e manter o cursor ou ordenar tamanhos de área pequenos.

-- Pseudocode
counter = 0;
for each row in dup table       -- and if this takes long, break this into ranges
   delete from primary_tab where id = @id
   if counter++ > 1000 then
      commit;
      counter = 0;
   end if
end loop
Este proc armazenado pode ser parado e reiniciado sem se preocupar com um rollback gigante, e também funcionará de forma fiável durante horas ou dias sem grande impacto na disponibilidade da base de dados. In Oracle this could be undo segments and sort area sizes as well as other things, but in MSSQL I am not an expert. Eventualmente, acabará. Enquanto isso, você não está amarrando a mesa-alvo com fechaduras ou grandes transações, e assim DML pode continuar na mesa. A ressalva é que, se o DML continuar nele, então você potencialmente terá que repetir o instantâneo para a mesa de ids dup para lidar com quaisquer dupes que surjam desde o instantâneo.

Advertência: Isto não defrag blocos livres/linhas ou coalesce espaço excluído como completamente a construção de uma nova tabela, mas permite que ele seja feito on-line e sem alocação de uma nova cópia. Por outro lado, se você tiver a liberdade de fazê-lo on-line e / ou uma janela de manutenção, e as linhas duplicadas são maiores do que 15-20% de seus dados, então você deve optar pela abordagem" Criar tabela como Selecione * do original menos duplicates", como na resposta de Gordon, a fim de comprimir o segmento de dados em um densamente utilizado, segmento contíguo, e obter um melhor desempenho de cache/IO a longo prazo. No entanto, raramente são duplicados mais de uma fração de uma porcentagem do espaço.

As razões para tal incluem:

Uma tabela demasiado grande para criar uma cópia temporária.

2 - Você não pode ou não quer deixar cair a tabela original para fazer a troca uma vez que o novo está pronto.

Não se arranja uma janela de manutenção para fazer um gigante. operacao.
Caso contrário, veja a resposta do Gordon Linoff.
 3
Author: codenheim, 2014-08-07 03:57:20
Todos os outros ofereceram grandes métodos para fazer isto do ponto de vista técnico, vou apenas acrescentar um ponto pragmático. IMHO é difícil automatizar completamente o processo de eliminação dos duplicados em uma grande tabela de pessoas. Se a correspondência estiver muito relaxada... então os registos legítimos serão apagados. Se a correspondência for demasiado rigorosa... então os duplicados serão deixados.

Para os meus clientes, construí uma consulta como a acima que devolve linhas que representam provavelmente duplicados, utilizando o endereço e o apelido como critério de correspondência. Em seguida, eles olham a lista de prováveis e clicam em "Apagar" ou "mesclar" nas linhas que eles escolhem para ser um duplicado.

Isto pode não funcionar no seu projecto (com milhares de milhões de linhas), mas faz sentido num ambiente onde tanto duplicações como dados perdidos precisam de ser evitados. Um único operador humano pode melhorar a limpeza de milhares de linhas de dados em poucos minutos, e eles podem fazê-lo um pouco de cada vez ao longo de muitos sessao.

 1
Author: Ty H., 2014-08-07 03:49:30
IMHO, não há melhor maneira de descobrir, e é por isso que vês tantas soluções diferentes. Depende da sua situação. Agora, eu tenho uma situação em que eu tenho um grande arquivo de história, listando as métricas mensais para cada uma das dezenas de milhares de contas de empréstimos por anos e anos. Cada conta é representada no arquivo para os muitos fins de mês enquanto ele permanece ativo, mas quando ele fica inativo, ele aparecerá em nenhuma data posterior. Só quero os últimos registos de cada conta. I não me importo com o recorde quando a conta foi aberta há 20 anos, e tudo o que me interessa é o recorde mais recente, quando a conta fechou há 5 anos. Para essas contas ainda activas, quero o registo do mês de calendário mais recente. Então eu acho que "duplicates" são esses registros para a mesma conta para todos, menos o último registro mensal para essa conta, e eu quero me livrar deles. Este pode não ser o teu problema exacto, mas a solução que te apresento pode dar-te o impulso que queres para a tua vida. solucao.

(eu faço a maior parte do meu código sql no SAS PROC SQL, mas eu acho que você vai ter a idéia.)

A minha solução usa um subcontingente...
 /* dedupe */ 
 proc sql ;   
   create table &delta. as       
     select distinct b.*, sub.mxasof
       from &bravo. b
       join ( select distinct Loan_Number, max(asof) as mxasof format 6.0
                from &bravo.
                group by Loan_Number
            ) sub
       on 1
       and b.Loan_Number = sub.Loan_Number
       and b.asof = sub.mxasof
       where 1
       order by b.Loan_Number, b.asof desc ;
 0
Author: spicetrader, 2015-08-04 21:43:36