Importador em massa do Vbulletin: valor nulo na coluna "pinned_globally" da relação "topics" viola restrição de não nulo

Estou tentando fazer uma importação com o importador em massa do vBulletin. Consegui fazer com que ele funcionasse na maior parte. Ele criou usuários e posts, mas os tópicos não estão sendo criados.

O que está sendo passado para create_topics(topics) parece certo. O que está em processed em base.rb:create_records parece certo (skipped não está definido). Mas nenhum tópico está sendo criado.

Aqui está o erro:

ERROR:  null value in column "pinned_globally" of relation "topics" violates not-null constraint

Mas se um tópico não está fixado globalmente, qual valor ele deve ter? Estou tentando comentar esse campo em TOPIC_COLUMNS em base.rb.

EDIT: Acho que isso pode resolver, mas não saberei por um tempo:

    create_topics(topics) do |row|
      created_at = Time.zone.at(row[5])

      t = {
        imported_id: row[0],
        title: normalize_text(row[1]),
        category_id: category_id_from_imported_id(row[2]),
        user_id: user_id_from_imported_id(row[3]),
        closed: row[4] == 0,
        created_at: created_at,
        views: row[6] || 0,
        visible: row[7] == 1,
        pinned_globally: row[8] == 1 # ============== JP adicionou isso:
      }
      t[:pinned_at] = created_at if row[8] == 1

      t
    end

Isso é estranho, já que essa coluna tem um valor padrão? Ela tem um valor padrão no seu banco de dados quando você executa \\d topics?

pinned_globally | boolean | | not null | false

Aha. Isso explica por que não está no código, eu acho.

Mas isso não resolve o mistério.

pinned_globally    | boolean   |     | not null | false

EDIT:
IA Aleatória diz:

Talvez isso seja uma “ferramenta de inserção em massa”?

Não consigo encontrar uma fonte que diga credivelmente o que a citação acima diz, mas faz sentido, no sentido de que o objetivo é ser rápido, então pular padrões parece algo que faria, e explica o que está acontecendo e, espero, a solução que ainda estou esperando para ver se funcionou.

Aqui está a documentação real! PostgreSQL: Documentation: 18: COPY

Se uma lista de colunas for especificada, COPY TO copia apenas os dados nas colunas especificadas para o arquivo. Para COPY FROM, cada campo no arquivo é inserido, em ordem, na coluna especificada. Colunas da tabela não especificadas na lista de colunas COPY FROM receberão seus valores padrão.

Então, se eu estiver lendo isso corretamente, se um campo estiver na lista de campos, o postgres copia cegamente o que você dá a ele, e em branco/nulo é inserido em vez do padrão desejado.

Está ficando cada vez mais lento. Há alguma razão para não usar LIMIT 1000 como o importador regular faz? Parece que talvez 885K tópicos seja muito para morder de uma vez?

Verifiquei o script para a última importação em massa que fiz e ele realmente tem um pinned_globally: false explícito, então isso é aparentemente necessário - é o único valor de coluna explícito codificado no código.

    create_topics(topics) do |row|
      t = {
        imported_id: row[0],
        title: my_normalize_text(row[1]),
        category_id: category_id_from_imported_id(row[2]),
        user_id: user_id_from_imported_id(row[3]),
        created_at: Time.zone.at(row[4]),
        pinned_globally: false
      }

Estranho, já que não tem isso para outras colunas semelhantes de not null, default false como closed ou has_summary.

A última importação que fiz com o importador em massa fez mais de 3 milhões de tópicos em cerca de 2 horas. Talvez você tenha um vazamento de memória? Ou talvez seu código MySQL (ou o que quer que você use para ler os dados de origem) esteja lento em algum lugar?

Boas notícias! Todos os tópicos foram criados! Más notícias! Nenhum dos posts está conectado a eles, mas espero que seja porque os posts foram criados antes dos tópicos.

Isso é estranho. Tinha tanta certeza de que tinha uma explicação. :person_shrugging:

Os 7 milhões de posts levaram apenas algumas horas, mas os menos de 1 milhão de tópicos levaram cerca de 4.

É uma máquina antiga (que aparentemente compraram apenas para o trabalho?), e o mysql é remoto. Olhando para o htop, não há vazamento de memória óbvio no nível do sistema. Limpei todos os dados e estou reconstruindo os contêineres para ver se funcionará desta vez.

Muito obrigado pela sua ajuda.

1 curtida

Bem, agora a importação de user_email está falhando com:

CONTEXT:  COPY user_emails, linha 1: "1  \N      @gmail.com     true    2004-03-08 14:12:00 UTC 2004-03-08 14:12:00 UTC"

Levei mais algumas horas, mas aqui está o porquê - a função process_topic lida com todos esses valores padrão.

Acho que deveria haver um

topic[:pinned_globally] ||= false

ou talvez

topic[:pinned_globally] ||= topic[:pinned_at].nil?
1 curtida