{#upgrade-to-218-upgrading-to-218} # 2.18로 업그레이드하기 AgensGraph 2.18은 PostgreSQL 18 위에 만들어졌으므로 그리로 옮기는 것은 메이저 버전 업그레이드입니다. 데이터 디렉터리 형식이 바뀌었고, 2.17 데이터 디렉터리는 2.18 바이너리로 기동할 수 없습니다. 경로는 둘입니다. 기존 데이터 파일을 재사용해 빠른 `pg_upgrade`, 또는 덤프 후 다시 적재하는 것입니다. 어느 쪽이든 하기 전에 [무엇이 바뀌었는지](#218-migrating-to-218)를 읽고 자기 애플리케이션을 그에 비추어 확인하십시오. 2.17에서 잘 도는 쿼리를 망가뜨릴 변경이 여럿 있고, 업그레이드 도구는 그중 어느 것도 잡아 주지 않습니다. {#upgrade-to-218-check-your-application-first} ## 애플리케이션부터 확인하기 이 목록을 자기 코드베이스에 대고 하나씩 짚어 보십시오. 각 항목은 2.17에서 잘 돌던 코드를 2.18에서 오류나 다른 답으로 바꾸는 변경입니다. * **`xor`·`current_graph`·`current_property_graph`라는 이름의 식별자** — 이제 예약어입니다. 이름을 바꾸거나 **큰따옴표**로 감싸십시오(`MATCH (n:"xor")`). 여기서 백틱은 따옴표가 아닙니다. 변수 이름으로 쓰는 `let`과 `finish`, 레이블로 쓰는 `let`도 거부되며, 패턴 표기 `MATCH (n:insert)`는 여전히 되지만 `CREATE VLABEL insert;` 에는 따옴표가 필요합니다. 어느 단어가 어느 자리에서 실패하는지의 표는 [키워드](../appendix/keywords.md)를 참고하십시오. * **`call(...)` 또는 `(call { ... })`** — 이름이 글자 그대로 `call`인 함수, 또는 변수가 `call`이고 레이블 없이 속성 맵을 지닌 정점 패턴입니다. 둘 다 뜻이 달라지므로 이름을 따옴표로 감싸십시오. * **불리언이 아닌 조건** — `WHERE n.count`, `FILTER n.name`입니다. 전에는 0이 아닌지, 비어 있지 않은지로 골랐지만 이제 형 변환 오류를 냅니다. `::boolean`을 붙이거나 명시적으로 비교하십시오. * **정점·간선·경로에 대한 `collect()`** — 이제 사본을 담은 jsonb 배열이 아니라 네이티브 배열을 반환합니다. jsonb 형태를 파싱하던 클라이언트 코드는 고쳐야 하고, 모은 요소에서 속성을 읽던 코드는 이제 동작하기 시작합니다. * **정점이나 간선에 대한 `min()` / `max()`** — 이제 모호해져 오류입니다. `min(v::jsonb)`이나 `min(id(v))`를 쓰십시오. * **`range()`·`toStringList`·`toIntegerList`·`toFloatList`** — 반환 타입이 바뀌었습니다. * **`SKIP`이나 `LIMIT`이 붙은 `WITH … WHERE`** — 이제 걸러 낸 뒤에 나누므로 결과 집합이 달라집니다. * **그래프에 대한 행 수준 보안** — 이제 RLS가 그래프 쓰기에 실제로 적용됩니다. 레이블에 정책이 걸려 있다면 다시 시험하십시오. 전에는 빠져나가던 쓰기가 거부됩니다. * **레이블에 대한 `ALTER TABLE`** — 구조를 바꾸는 것은 모두 거부됩니다. 레이블 DDL을 쓰거나 `enable_graph_ddl`을 설정하십시오. * **`EXPLAIN` 회귀 기준** — 요소에 대한 `count()`, 속성 읽기, 가변 길이 순회 노드에서 계획 텍스트가 바뀌었습니다. * **양쪽 콜레이션이 다른 외래키** — 둘 중 하나라도 비결정 콜레이션이면 거부됩니다(`42P21`). 2.17은 만들어 주었습니다. 양쪽이 *같은* 비결정 콜레이션이면 지금도 됩니다. 서로 다른 결정 콜레이션 둘도 됩니다. `NOT VALID`로도 미룰 수 없고, 라벨 열에 건 외래키도 마찬가지로 거부됩니다. 이 항목은 애플리케이션만의 문제가 아닙니다. 2.17 덤프를 복원하면 그 테이블이 **제약 없이** 만들어집니다. 업그레이드 전에 해당 쌍을 찾으십시오 — [비결정 콜레이션이 낀 외래키](#upgrade-to-218-foreign-keys-with-a-nondeterministic-collation)를 보십시오. {#upgrade-to-218-foreign-keys-with-a-nondeterministic-collation} ## 비결정 콜레이션이 낀 외래키 덤프하거나 업그레이드하기 전에, **2.17** 클러스터의 데이터베이스마다 다음을 실행하십시오. ```sql SELECT c.conrelid::regclass AS referencing, c.conname, fa.attname AS col, fc.collname AS referencing_collation, pc.collname AS referenced_collation FROM pg_constraint c CROSS JOIN LATERAL unnest(c.conkey, c.confkey) AS k(fkatt, pkatt) JOIN pg_attribute fa ON fa.attrelid = c.conrelid AND fa.attnum = k.fkatt JOIN pg_attribute pa ON pa.attrelid = c.confrelid AND pa.attnum = k.pkatt JOIN pg_collation fc ON fc.oid = fa.attcollation JOIN pg_collation pc ON pc.oid = pa.attcollation WHERE c.contype = 'f' AND fa.attcollation <> pa.attcollation AND NOT (fc.collisdeterministic AND pc.collisdeterministic); ``` 나오는 행 하나하나가 2.18이 거부할 제약입니다. 2.17에서 두 열의 콜레이션을 같게 맞춘 다음 덤프하십시오. 조건은 서버가 적용하는 조건 그대로이고 서버가 읽는 카탈로그 열을 그대로 읽으므로, 업그레이드가 거부할 제약보다 더 많이도 더 적게도 고르지 않습니다. ```{warning} 어느 경로도 미리 알려 주지 않습니다. `pg_upgrade --check`는 `*Clusters are compatible*`로 끝나고, 업그레이드는 그 제약을 다시 만드는 자리에서 실패합니다. 덤프·복원은 더 나쁩니다. 복원이 성공했다고 보고하고 테이블은 **외래키 없이** 들어오며, 그 뒤로는 아무것도 참조하지 않는 행이 통과합니다. ``` {#upgrade-to-218-route-1-using-pg_upgrade} ## 경로 1. pg_upgrade 쓰기 `pg_upgrade`는 새 클러스터의 카탈로그를 만든 다음 기존 사용자 데이터 파일을 재사용하므로 데이터를 다시 쓰지 않습니다. 그래프는 평범한 스키마와 테이블로 저장되므로, 그래프 데이터도 관계형 데이터와 똑같이 옮겨 갑니다. {#upgrade-to-218-before-you-begin} ### 시작하기 전에 * **2.18을 별도의 위치에 설치하십시오.** 2.17 설치본을 덮어쓰지 마십시오. `pg_upgrade`에는 두 바이너리가 모두 필요하고, 2.17을 그대로 두는 것이 되돌아갈 길을 만들어 줍니다. * **디스크 공간.** 기본적으로 데이터 파일을 복사하므로 두 번째 사본을 둘 자리가 필요합니다. `--link`는 대신 하드 링크를 겁니다. 거의 즉시 끝나고 공간도 거의 들지 않지만, 두 데이터 디렉터리가 한 파일시스템에 있어야 하고 새 서버가 기동한 뒤에는 되돌릴 수 없게 됩니다. * **2.17 클러스터가 쓰는 외부 모듈을 2.18 설치본에도 똑같이 설치하십시오.** 예를 들어 `pgvector`입니다. AgensGraph 자신의 그래프 기능은 서버에 내장돼 있으므로 다시 만들 그래프 확장은 없습니다. * **평범한 컬럼을 지닌 레이블이 업그레이드를 막습니다.** `pg_upgrade`는 `pg_dump --binary-upgrade`에 일을 넘기는데, 그것은 `id`·`start`·`end`·`properties` 말고 다른 컬럼을 가진 그래프 레이블을, 물리적 컬럼 배치를 조용히 망가뜨리는 대신 거부합니다. 시작하기 전에 찾아 두십시오: ```sql SELECT c.relname, a.attname FROM pg_catalog.ag_label l JOIN pg_class c ON c.oid = l.relid JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum > 0 AND NOT a.attisdropped WHERE a.attname NOT IN ('id', 'start', 'end', 'properties'); ``` 업그레이드하기 전에 그 컬럼들을 지우거나 데이터를 다른 곳으로 옮기십시오. * 모든 명령은 데이터 디렉터리를 소유한 운영체제 사용자로 실행하십시오. 아래 명령은 다음 변수를 씁니다: ```shell export OLD=/usr/local/agensgraph-2.17 export NEW=/usr/local/agensgraph-2.18 export OLDDATA=$OLD/data export NEWDATA=$NEW/data ``` {#upgrade-to-218-step-1-stop-the-old-server} ### 1단계. 옛 서버 정지 `pg_upgrade`가 도는 동안 두 클러스터 모두 내려가 있어야 합니다. ```shell $OLD/bin/ag_ctl -D $OLDDATA stop ``` {#upgrade-to-218-step-2-initialize-the-new-cluster} ### 2단계. 새 클러스터 초기화 옛 클러스터와 같은 슈퍼유저·인코딩·로케일을 쓰고, 데이터 체크섬 설정도 맞추십시오. ```shell $NEW/bin/initdb -D $NEWDATA -U postgres --encoding=UTF8 --no-data-checksums ``` ```{warning} **대부분의 업그레이드에서 `--no-data-checksums`는 선택 사항이 아닙니다.** PostgreSQL 18은 데이터 페이지 체크섬을 기본으로 켜고 PostgreSQL 17은 껐습니다. 그러므로 2.17 클러스터를 `-k`로 초기화하지 않았다면 두 클러스터가 어긋나고, `pg_upgrade`는 아무것도 하기 전에 멈춥니다: Performing Consistency Checks ----------------------------- Checking cluster versions ok old cluster does not use data checksums but the new one does Failure, exiting 초기화하기 전에 어느 쪽인지 확인하십시오: $OLD/bin/pg_controldata -D $OLDDATA | grep checksum `Data page checksum version: 0`으로 나오면 `--no-data-checksums`를 주십시오. `1`로 나오면 그 플래그를 빼십시오. 체크섬을 켜는 것은 별개의 작업이며 ([`pg_checksums`](https://www.postgresql.org/docs/18/app-pgchecksums.html) 참고) 할 만한 일이지만, 업그레이드의 일부로 하지 말고 그 뒤에 하십시오. ``` {#upgrade-to-218-step-3-check-compatibility} ### 3단계. 호환성 확인 `--check`는 두 클러스터를 검사하며 아무것도 바꾸지 않습니다. ```shell $NEW/bin/pg_upgrade \ -b $OLD/bin -B $NEW/bin \ -d $OLDDATA -D $NEWDATA \ -U postgres --check ``` 검사가 성공하면 `*Clusters are compatible*` 로 끝납니다. ```{warning} 검사를 통과했다고 업그레이드가 성공한다는 뜻은 아닙니다. 이 검사는 [비결정 콜레이션이 낀 외래키](#upgrade-to-218-foreign-keys-with-a-nondeterministic-collation)를 찾지 않으며, 4단계는 그 제약을 다시 만드는 자리에서 실패합니다. 위 질의를 직접 실행하십시오. ``` 데이터베이스 슈퍼유저를 `-U`로 주십시오. 기본적으로 `pg_upgrade`는 운영체제 사용자로 접속하는데, 그것은 보통 데이터베이스 롤이 아닙니다. {#upgrade-to-218-step-4-run-the-upgrade} ### 4단계. 업그레이드 실행 `--check`만 뺀 같은 명령입니다: ```shell $NEW/bin/pg_upgrade \ -b $OLD/bin -B $NEW/bin \ -d $OLDDATA -D $NEWDATA \ -U postgres ``` `Upgrade Complete`로 끝납니다. 데이터 파일을 복사하는 대신 하드 링크하려면 검사와 업그레이드 양쪽에 `--link`를 더하십시오. {#upgrade-to-218-step-5-start-the-new-server} ### 5단계. 새 서버 기동 ```shell $NEW/bin/ag_ctl -D $NEWDATA -l $NEW/logfile start ``` 새 서버에 붙어 있는지, 그리고 그래프가 넘어왔는지 확인하십시오: ```sql SELECT version(); ``` ```cypher SET graph_path = ; MATCH (n) RETURN count(n); ``` {#upgrade-to-218-step-6-post-upgrade-tasks} ### 6단계. 업그레이드 뒤에 할 일 이 중 셋은 AgensGraph에만 해당하며, 어느 것도 선택 사항이 아닙니다. **통계를 다시 만드십시오.** `pg_upgrade`는 옵티마이저 통계를 가져오지 않으므로, 다시 만들기 전까지 계획이 나쁩니다: ```shell $NEW/bin/vacuumdb -U postgres --all --analyze-in-stages ``` **그래프 메타데이터를 다시 수집하십시오.** `ag_graphmeta`가 플래너의 스캔 쳐내기를 이끕니다. 바이너리 업그레이드는 그것을 빈 채로 두고 그래프를 무효로 표시하므로, 그래프마다 한 번씩 다시 만들기 전까지 쳐내기가 꺼져 있습니다: ```sql SET graph_path = ; SELECT regather_graphmeta(); ``` 반영됐는지 확인하십시오: ```sql SELECT graphname, graphmeta_valid FROM pg_catalog.ag_graph; ``` **간선 레이블의 통계를 다시 조정하십시오.** 2.18은 새 간선 레이블의 `start`·`end` 컬럼에 대한 통계 목표치를 10000에서 1000으로 낮췄습니다. 2.17에서 만든 레이블은 옛 값을 그대로 지녀 간선 조인 때마다 큰 계획 비용 — 큰 레이블에서는 수백 밀리초 — 을 치릅니다. 간선 레이블마다 이렇게 하십시오: ```sql ALTER TABLE . ALTER COLUMN start SET STATISTICS 1000; ALTER TABLE . ALTER COLUMN "end" SET STATISTICS 1000; ANALYZE .; ``` 그런 다음 업그레이드한 클러스터가 잘 도는 것을 확인했으면, `pg_upgrade`를 실행한 디렉터리에 그것이 써 둔 스크립트로 옛 데이터 파일을 지우십시오: ```shell ./delete_old_cluster.sh ``` {#upgrade-to-218-rolling-back} ### 되돌리기 복사 모드에서, 그리고 `delete_old_cluster.sh`를 실행하기 전이라면 2.17 데이터 디렉터리는 그대로 있습니다. 새 서버를 정지하고 옛 서버를 기동하십시오: ```shell $NEW/bin/ag_ctl -D $NEWDATA stop $OLD/bin/ag_ctl -D $OLDDATA -l $OLD/logfile start ``` `--link` 업그레이드 뒤에는 두 클러스터가 데이터 파일을 공유하므로, 새 서버가 기동한 뒤에는 되돌릴 수 없습니다. 백업에서 복원하십시오. {#upgrade-to-218-route-2-dump-and-reload} ## 경로 2. 덤프하고 다시 적재하기 더 느리지만 모든 것을 다시 쓰고, 실행 중에 바이너리 사본을 둘씩 두지 않아도 됩니다. ```shell $OLD/bin/pg_dumpall -U postgres -f cluster.sql # start the 2.18 cluster, then: $NEW/bin/psql -U postgres -d postgres -f cluster.sql ``` ```{warning} `psql`은 오류가 나도 멈추지 않고, 그러고도 종료 코드 0 을 냅니다. 새 서버가 거부하는 것은 — 예를 들어 [비결정 콜레이션이 낀 외래키](#upgrade-to-218-foreign-keys-with-a-nondeterministic-collation) — 출력 한 줄로 지나가고 복원은 그것 없이 계속됩니다. 복원을 믿기 전에 로그를 읽으십시오. ``` 복원이 멈추게 하려면 롤과 데이터를 따로 덤프하십시오. 롤 부분은 `ON_ERROR_STOP`으로 복원할 수 없습니다. `pg_dumpall`은 이미 새 클러스터에 있는 부트스트랩 슈퍼유저의 `CREATE ROLE`을 쓰고, `--clean --if-exists`는 접속 중인 롤의 `DROP ROLE`로 실패 지점을 옮길 뿐입니다. ```shell $OLD/bin/pg_dumpall -U postgres --globals-only -f globals.sql $OLD/bin/pg_dump -U postgres -Fc -d mydb -f mydb.dump # once per database # start the 2.18 cluster, then: $NEW/bin/psql -U postgres -d postgres -f globals.sql # roles; errors here are benign $NEW/bin/createdb -U postgres mydb $NEW/bin/pg_restore -U postgres --exit-on-error -d mydb mydb.dump ``` 알아 둘 것 둘입니다: * **복원에 `enable_graph_ddl`이 필요할 수 있습니다.** 평범한 컬럼을 지닌 레이블의 덤프는 자기 `ALTER TABLE … ADD COLUMN` 문장 둘레에 `SET enable_graph_ddl = on`을 내보냅니다. 그 설정은 어느 롤이든 쓸 수 있으므로 평범한 사용자도 복원할 수 있습니다. 그 롤에 `ALTER ROLE … SET`으로 강제로 꺼 두지 않았다면 말입니다. * **위의 그래프 메타데이터와 통계 작업은 여기서도 그대로 적용됩니다.** {#upgrade-to-218-downgrading-is-not-supported} ## 다운그레이드는 지원하지 않는다 어떤 그래프든 [승격된 컬럼](../querying/typed-columns.md)을 쓰고 있으면 2.18 덤프는 2.17에 복원되지 않습니다. 덤프에 2.17 파서가 거부하는 `CREATE VLABEL` 형태가 들어 있고, 평문 스트림에서는 그 문장 뒤의 모든 것이 유실됩니다. 되돌아갈 길이 필요하다면 업그레이드 전에 받아 둔 2.17 백업을 보관하십시오. `pg_dump`와 `pg_restore`가 AgensGraph 버전을 검사하지 않는다는 점도 유의하십시오. PostgreSQL의 `server_version` 범위 검사만 적용됩니다. 그래서 어긋남은 앞에서 거부되는 대신 복원 도중의 파싱 실패로 드러납니다. {#upgrade-to-218-a-worked-example} ## 실제 예제 [업그레이드 실습](upgrade-walkthrough.md)은 작은 클러스터에서 실제 명령과 출력으로 전체 절차를 돌려 봅니다.