Vbulletin 일괄 가져오기: "topics" 관계의 "pinned_globally" 열에 null 값이 있어 not-null 제약 조건을 위반했습니다

vBulletin 대량 가져오기를 사용하여 가져오기를 시도하고 있습니다. 대부분은 성공적으로 수행되었습니다. 사용자와 게시글은 생성되었지만, 주제는 생성되지 않고 있습니다.

create_topics(topics)에 전달되는 데이터는 올바르게 보입니다. base.rb:create_recordsprocessed에 있는 내용도 정상적으로 보입니다(skipped가 설정되지 않음). 하지만 주제가 생성되지 않습니다.

다음은 오류 메시지입니다:

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

주제가 전역으로 고정되지 않았을 경우, 어떤 값을 가져야 하나요? base.rbTOPIC_COLUMNS에서 해당 필드를 주석 처리하는 방법을 시도해 보고 있습니다.

수정: 이것이 문제를 해결할 것 같지만, 확실히 알기까지는 시간이 좀 걸릴 것입니다:

    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가 이 부분을 추가했습니다:
      }
      t[:pinned_at] = created_at if row[8] == 1

      t
    end

그 컬럼에 기본값이 있다고 하는데, 이상하네요. \d topics 명령을 실행했을 때 데이터베이스에서 실제로 기본값이 설정되어 있나요?

pinned_globally | boolean | | not null | false

아하. 그게 코드에 없는 이유를 설명해주는 것 같네요.

하지만 여전히 미스터리가 해결되지는 않았습니다.

pinned_globally    | boolean   |     | not null | false

수정:

무작위 AI가 이렇게 말합니다:

이것이 "벌크 삽입 도구"일까요?

위 인용문이 실제로 무엇을 하는지 신뢰할 수 있는 출처를 찾을 수는 없었지만, 논리적으로는 말이 됩니다. 즉, 이 작업의 목적은 속도를 높이는 것이므로 기본값을 건너뛰는 것이 당연해 보이며, 이는 현재 일어나고 있는 상황을 설명해 주며, 제가 아직 작동 여부를 확인하지 못하고 있는 해결책과도 일치합니다.

실제 문서입니다! PostgreSQL: Documentation: 18: COPY

컬럼 목록이 지정되면, COPY TO는 파일에 지정된 컬럼의 데이터만 복사합니다. COPY FROM의 경우, 파일의 각 필드는 순서대로 지정된 컬럼에 삽입됩니다. COPY FROM 컬럼 목록에 지정되지 않은 테이블 컬럼은 기본값을 받게 됩니다.

따라서 제가 올바르게 이해했다면, 필드가 필드 목록에 포함되어 있으면 postgres는 제공한 값을 무비판적으로 복사하며, 원하는 기본값 대신 빈 값/null이 삽입됩니다.

점점 느려지고 있습니다. 일반 가져오기 도구가 사용하는 것처럼 LIMIT 1000을 사용하지 않는 이유가 있을까요? 885K개의 토픽을 한 번에 처리하는 것은 너무 많은 것 같지 않나요?

마지막 대량 가져오기 시 사용한 스크립트를 확인해 보니 실제로 pinned_globally: false가 명시적으로 포함되어 있네요. 즉, 이것이 필요한 것 같습니다. 코드에서 명시적으로 하드코딩된 열 값은 이것뿐이니까요.

    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
      }

closedhas_summary 같은 다른 유사한 not null, default false 열에는 이런 설정이 없어서 좀 이상하네요.

대량 가져오기 도구로 마지막으로 수행한 가져오기에서는 약 2시간 만에 300만 개 이상의 토픽을 처리했습니다. 메모리 누수가 있는 건가요? 아니면 소스 데이터를 읽는 데 사용하는 MySQL 코드(또는 기타 도구)의 특정 부분이 느린 것일 수도 있습니다.

좋은 소식! 모든 토픽이 생성되었습니다! 나쁜 소식! 그 어떤 게시글도 토픽에 연결되어 있지 않아요. 하지만 다행히도 게시글이 토픽보다 먼저 생성되었기 때문일 수 있겠네요.

그렇군요. 확실히 설명이 있을 줄 알았거든요. :person_shrugging:

700만 개의 게시글은 단 몇 시간 만에 처리되었는데, 100만 개 미만의 토픽은 4시간 정도 걸렸습니다.

오래된 서버(이 작업을 위해 특별히 구매했다는 것 같지만)를 사용 중이고, mysql은 원격에 있습니다. htop을 확인해 봤지만 시스템 레벨에서 명백한 메모리 누수는 보이지 않아요. 모든 데이터를 지우고 컨테이너를 재구축해서 이번에는 잘 될지 확인해 보고 있습니다.

도움 주셔서 정말 감사합니다.

음, 이제 user_email 가져오기가 다음 오류로 실패하고 있습니다:

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

몇 시간 더 걸렸지만, 그 이유는 다음과 같습니다. process_topic 함수가 모든 기본값을 처리하고 있기 때문입니다.

아래와 같은 코드가 있어야 할 것 같습니다.

topic[:pinned_globally] ||= false

아니면

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