ATUALIZAR com JOIN em registros de 100 mm, como fazer isso melhor? (em T-SQL)


11

Eu preciso atualizar 100 milhões de registros em uma única tabela, com efeito, normalizando a tabela substituindo o valor varchar de uma coluna por simplesmente um ID. (Eu digo "substituindo", mas realmente estou escrevendo o ID em outra coluna.)

O que estou tentando alcançar é normalizar o conjunto de dados. Os dados ainda não normalizados não possuem indexação. Meu pensamento era que eu não criaria índices nos valores brutos, esperando, em vez disso, indexar as chaves estrangeiras que substituirão os valores varchar pelos valores tinyint após a conclusão da atualização.

UPDATE A
SET A.AutoClassID = B.AutoClassID
FROM AutoDataImportStaging.dbo.Automobile as A
JOIN AutoData.dbo.AutoClass as B on (A.AutoClassName = B.AutoClassName)

fundo

  • usando o MSSQL 2008 R2 no Server 2008 R2
  • servidor tem 8 GB de RAM
  • o servidor possui um RAID10, 7200 RPM SATA (nada bom, eu sei, na produção, isso só lerá dados e não gravará dados; além da recente escassez de HD necessária para o custo)
  • servidor tem CPU Xeon quad-core dupla
  • a máquina não está fazendo mais nada (atualmente dedicado ao dev, somente esse processo)
  • log simples ativado (? - mas ele ainda faz logon para que possa reverter?)
  • observe que a consulta faz referência a dois bancos de dados diferentes, pelo que vale a pena
  • "largura" de um registro na tabela sendo atualizado é de 455 bytes

Recursos durante a execução

  • a RAM física está no máximo
  • a E / S do disco está no limite máximo
  • A CPU quase não está fazendo nada (o ponto de estrangulamento é a E / S)
  • tempo de execução foi de 14 horas e contando!

Suspeito de algumas coisas, como eu preciso de um índice nos dados brutos, mesmo depois de soltar a coluna (AutoClassName) após a atualização da normalização. Também me pergunto se devo apenas repetir a tabela um registro de cada vez, em vez de JOIN, o que parecia ridículo quando comecei isso, mas agora parece que isso teria sido mais rápido.

Como devo mudar minha metodologia para minhas atualizações de normalização restantes (semelhantes a esta) mais rapidamente?

Respostas:


7

Você está tentando fazer isso como uma transação única (muito grande). Em vez disso, faça a atualização em lotes menores.

Você também se beneficiaria de:

  • Um índice temporário em AutoData.dbo.AutoClass.AutoClassName
  • Mais RAM. Muito mais RAM.

1
+1 Concordo com a atualização do lote usando a TOPcláusula. Essa seria a minha abordagem.
Thomas Stringer

Se eu fizer UPDATE TOP, precisarei de uma cláusula WHERE (WHERE AutoClassID é NULL)? A cláusula WHERE não apresentaria uma nova ocorrência de desempenho (uma varredura de tabela que não estou fazendo agora). Sem dúvida, diminuiria o problema de RAM que estou tendo com o JOIN.
Chris Adragna

Minha resposta está atrasada, mas no meu caso, SET ROWCOUNT provou ser o mais eficaz.
precisa saber é o seguinte

10

Eu adotaria uma abordagem diferente.

Em vez de atualizar as tabelas existentes, basta criar uma nova tabela com o que você precisa.

Isso quase certamente será mais rápido:

SELECT DISTINCT
    AutoClassID,
    <Other fields>
INTO
    AutoDataImportStaging.dbo.Automobile
FROM
    AutoData.dbo.AutoClass

Como atualmente escrito, há muitas operações lógicas acontecendo:

  • Leia todos os valores de A.AutoClassName
  • Leia todos os valores de B.AutoClassName
  • Compare os valores A e B
  • Do conjunto correspondente, leia todos os valores de B.AutoClassID
  • Atualize os valores existentes de A.AutoClassId para serem o valor B.AutoClassId por quaisquer índices existentes

Isso soa como uma abordagem simples e agradável, especialmente considerando o problema de E / S do disco que estou tendo. Obrigado por responder tão rapidamente.
31712 Chris Chragna

1
Sugiro que você verifique novamente se possui espaço livre suficiente em seus arquivos de log e dados. Se os arquivos crescem automaticamente, o desempenho diminui. Muitas vezes vejo pessoas executando alguma atualização grande e única e aumentando automaticamente seu arquivo de log sem perceber.
darin strait

5

Dar uma volta na mesa, uma linha de cada vez, não será mais rápido!

Como suspeito e confirmado por você, isso será vinculado à E / S - ter um disco, as leituras, gravações, logs de transações e (qualquer) espaço de trabalho temporário competirão pela mesma E / S.

A recuperação simples ainda registrará as transações, mas o log será limpo por um ponto de verificação. É possível que o tamanho inicial do log e as configurações de crescimento automático estejam causando uma lentidão de E / S - o log de transações precisará aumentar para acomodar as alterações.

Você já tentou indexar o campo AutoClassName? Quantos valores diferentes de AutoClasse existem?

Pode ser necessário agrupar as atualizações com base nas limitações de sua E / S. Então atualize 1 milhão, posto de controle, repita ....


Existem apenas 15 valores diferentes de AutoClasse. Seus comentários confirmam muitas das minhas suspeitas (e dores!). Obrigado por responder.
Chris Adragna

3

Crie índices para os campos de junção.

Você sempre pode soltar os índices quando terminar.

Eu ficaria muito surpreso se os índices não melhorassem significativamente o desempenho da atualização.


Tenho certeza que os índices melhorariam. Suponho que a questão é se eles melhoram mais do que o tempo necessário para criar o índice (apenas para um uso). Provavelmente sim. :)
Chris Adragna

3

Exporte da maneira que desejar, crie uma nova tabela e importe de volta. Como bônus, você teria uma cópia dos dados como backup, caso milagres acontecessem.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.