Study/django

mysql에서 postgresql로 마이그레이션 시도를 하다 #1

bluebamus 2023. 10. 11.

1. dbeaver를 이용해 테이블 데이터 이전을 했다. dump를 이용할 수도 있겠지만, 있는 기능을 활용하고자 했다.

2. 원본의 database에서 이전하고자 하는 테이블을 전부 선택하고 오른쪽 마우스를 눌러 데이터 내보내기를 누른다

3. 테이블을 선택한다.

4. target container에서 미리 만들어둔 타겟인 postgresql의 데이터베이스/스키마를 선택하고 다음을 누른다.

5. 여기서 문제가 발생한다. 해당 DB의 연결이 지정된 사용자가 아니고 일반적으로 사용하는 postgre(root) 사용자라면 이전된 모든 테이블의 권한은 postgre가 된다.

 - 이를 바꿔주기 위해 다음 스크립트를 사용했다.

DO $$ 
DECLARE 
    r RECORD;
BEGIN 
    FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = '스키마 이름') 
    LOOP 
        EXECUTE 'ALTER TABLE 테이블 이름.' || r.tablename || ' OWNER TO 사용자 이름'; 
    END LOOP; 
END $$;

 - 이후 다음과 같은 속성을 확인할 수 있다 (Dbeaver는 확인할 수 없어 pqadmin4를 사용했다.)

6. run server 후 발생한 문제

django.db.utils.ProgrammingError: 오류:  NOT의 인자는 boolean 자료형이어야 함(integer 자료형이 아님)
LINE 1: ...y' AS "table" FROM "online_study_post" WHERE (NOT "online_st...

 - 혹시나 해서 shell_plus를 이용해 다음과 같은 쿼리를 확인하였다.

   - 테스트를 해보니 objects.all()은 문제가 없으나 커스텀한 manage의 함수를 사용하면 문제가 발생하였다.

In [13]: queryset = OnlineStudyPost.objects.filter(Q(is_deleted=False) & Q(is_hidden=False))

In [14]: str(queryset.query)
Out[14]: 'SELECT "online_study_post"."id", "online_study_post"."author_id", "online_study_post"."title", "online_study_post"."content", "online_study_post"."title_image", "online_study_post"."link1", "online_study_post"."link2", "online_study_post"."file1", "online_study_post"."file2", "online_study_post"."table_name", "online_study_post"."created_at", "online_study_post"."updated_at", "online_study_post"."reply_count", "online_study_post"."like_count", "online_study_post"."last_group_num", "online_study_post"."visit_count", "online_study_post"."is_deleted", "online_study_post"."is_hidden", "online_study_post"."dev_lang", "online_study_post"."branch", "online_study_post"."difficulty_level" FROM "online_study_post" WHERE (NOT "online_study_post"."is_deleted" AND NOT "online_study_post"."is_hidden") ORDER BY "online_study_post"."created_at" DESC'

 - 이상함을 감지하고 이전되기 전 mysql의 필드 정보를 확인했다.

 - models의 코드를 확인한다.

is_deleted = models.BooleanField(default=False, verbose_name=_("Deleted state"))
is_hidden = models.BooleanField(default=False, verbose_name=_("Hidden state"))

 - 문제는 mysql에서 int로 필드 값이 정의되어 있었다. 

   - 여러 해결 방법이 있겠지만, 가장 효율적인건 사용하는 테이블들을 확인하여 int -> boolean 으로 변경하는 것이다. 기존 데이터가 있다면, 컬럼 데이터를 따로 백업 후 컬럼 삭제 후 속성을 boolean으로 변경하고 코드나 스크립트를 사용해 일괄 업데이트하는 것이 제일 좋을것이다. 

   - 현재 데이터는 없기 때문에 쉽게 변경 가능할 것 같다.

   - 해당 작업은 차후 계획이기에 실행 이후 2번째 포스팅으로 기록을 남기게 될 것 같다.

댓글