{#guc-server-settings} # 서버 설정 AgensGraph는 PostgreSQL의 수백 개 설정에 열한 개를 더합니다. 이 페이지는 그 열한 개를 문서화합니다. 그 밖의 모든 설정은 PostgreSQL의 것이며 바뀌지 않았고, [PostgreSQL의 서버 설정 장](https://www.postgresql.org/docs/18/runtime-config.html)이 그것을 설명합니다. 무엇을 *어떻게* 그리고 *어디에* 설정하는지는 `postgresql.conf`·`ALTER SYSTEM`· `ALTER DATABASE`·`ALTER ROLE`·`SET`을 다루는 [설정](../operations/configuration.md)을 참고하십시오. 열한 개 중 하나인 `graph_path`는 Cypher를 실행하는 모든 세션에 필요합니다. 나머지는 쓸 만한 기본값을 가지고 있으므로, 그러지 않을 이유가 생기기 전까지는 신경 쓰지 않아도 됩니다. {#guc-the-settings} ## 설정 목록 아래의 모든 기본값은 실행 중인 서버에서 읽은 `pg_settings.boot_val`입니다: ```sql SELECT name, vartype AS type, boot_val AS default, coalesce(unit,'') AS unit, context FROM pg_settings WHERE name IN ('allow_null_properties','auto_gather_graphmeta','cypher_allow_unsafe_ddl', 'eager_mem','enable_eager','enable_graph_ddl','enable_graph_dml', 'enable_graph_endpoint_elision','enable_multiple_update', 'enable_property_promotion','graph_path') ORDER BY name; ``` ``` name | type | default | unit | context -------------------------------+---------+---------+------+----------- allow_null_properties | bool | off | | user auto_gather_graphmeta | bool | off | | superuser cypher_allow_unsafe_ddl | bool | off | | user eager_mem | integer | 4096 | kB | user enable_eager | bool | on | | user enable_graph_ddl | bool | off | | user enable_graph_dml | bool | off | | superuser enable_graph_endpoint_elision | bool | on | | user enable_multiple_update | bool | on | | user enable_property_promotion | bool | on | | user graph_path | string | | | user ``` 두 가지 context 값은 이렇게 읽습니다: `user` : 어느 롤이든, 어느 세션에서든, 언제든 바꿀 수 있습니다. `postgresql.conf`에서, 또는 데이터베이스별· 롤별로도 설정할 수 있습니다. `superuser` : 세션에서 이것을 바꿀 수 있는 것은 슈퍼유저, 또는 그 매개변수에 `SET` 권한을 부여받은 롤뿐입니다. 그 밖의 모두는 `permission denied to set parameter`를 받습니다. `postgresql.conf.sample`을 읽는 대신 `pg_settings`를 조회하십시오. 설치 디렉터리에 함께 들어 있는 샘플 파일은 `enable_eager`와 `enable_multiple_update`를 `off`로 적어 두었습니다. 둘의 실제 기본값은 `on`이므로, 그 파일을 옮겨 적은 표는 두 행이 틀리게 됩니다. {#guc-agversion-a-preset-rather-than-a-setting} ## agversion — 설정이 아니라 프리셋 `agversion`은 AgensGraph 버전을 알려 줍니다. context가 `internal`이므로 이것은 *프리셋*입니다. 설정하는 것이 아니라 서버가 알려 주는 값입니다. `postgresql.conf`에 쓸 수 없고, 설정하려 하면 거부됩니다: ```sql SET agversion = '1'; ``` ``` ERROR: parameter "agversion" cannot be changed ``` ```sql SELECT name, setting, context, category FROM pg_settings WHERE name = 'agversion'; ``` ``` name | setting | context | category -----------+------------+----------+---------------- agversion | 2.18.6.0 | internal | Preset Options ``` 무엇에 접속해 있는지 확인하는 보통의 방법인 `SHOW`로 읽습니다: ```sql SHOW agversion; ``` ``` agversion ------------ 2.18.6.0 ``` `version()`과 `server_version`은 이 릴리스가 기반으로 삼은 PostgreSQL 버전을 알려 줍니다. 둘 다 알아야 하는 클라이언트는 둘 다 읽어야 합니다. {#guc-graph_path} ## graph_path ``` string · default '' (empty) · context user ``` 세션이 작업하는 그래프를 지정합니다. Cypher나 GQL 문장에서 한정하지 않은 모든 레이블 이름이 그 그래프에서 해석됩니다. 모든 그래프 DDL 문장이 거기에 레이블을 만들거나 변경합니다. 그래프판 `search_path`이며, 건너뛸 수 없는 유일한 설정입니다. 이것이 없으면 아무것도 해석되지 않습니다: ```cypher RESET graph_path; MATCH (n:person) RETURN count(n); ``` ``` ERROR: graph_path is NULL HINT: Use SET graph_path ``` 설정하면 같은 문장이 실행됩니다: ```sql SET graph_path = moviekb; SHOW graph_path; ``` ``` graph_path ------------ moviekb ``` `CURRENT_GRAPH`는 문장 안에서 키워드만으로 같은 값을 읽습니다: ```cypher SELECT CURRENT_GRAPH; ``` ``` current_graph --------------- moviekb ``` {#guc-exactly-one-graph-name} ### 그래프 이름은 정확히 하나 `search_path`와 달리 `graph_path`는 목록이 아닙니다. 쉼표로 구분한 값을 이름 두 개로 해석하지 않습니다. 이름 하나로 받아들이며, 그런 이름은 존재하지 않습니다: ```sql SET graph_path = 'moviekb, twins'; ``` ``` ERROR: invalid value for parameter "graph_path": "moviekb, twins" DETAIL: graph "moviekb, twins" does not exist. ``` 그러므로 세션 하나는 그래프 하나를 읽고 씁니다. 한 문장에서 그래프 두 개에 닿으려면 둘을 스키마 두 개로 보는 SQL을 쓰십시오. 그 방법은 [SQL과 Cypher 섞어 쓰기](../querying/combining-sql-and-cypher.md)에 있습니다. {#guc-when-the-value-is-checked} ### 값을 언제 검사하는가 존재하지 않는 그래프는 쿼리를 실행할 때가 아니라 `SET` 하는 시점에 거부됩니다: ```sql SET graph_path = nosuchgraph; ``` ``` ERROR: invalid value for parameter "graph_path": "nosuchgraph" DETAIL: graph "nosuchgraph" does not exist. ``` 이름은 식별자이므로 따옴표로 감싸지 않으면 소문자로 내려갑니다. 대소문자를 섞은 이름으로 만든 그래프에는 따옴표가 필요합니다: ```cypher CREATE GRAPH "MixedCase"; SET graph_path = MixedCase; ``` ``` ERROR: invalid value for parameter "graph_path": "mixedcase" DETAIL: graph "mixedcase" does not exist. ``` ```sql SET graph_path = "MixedCase"; SHOW graph_path; ``` ``` graph_path ------------ MixedCase ``` ```cypher DROP GRAPH "MixedCase" CASCADE; SET graph_path = moviekb; ``` {#guc-one-value-for-a-database-or-a-role} ### 데이터베이스나 롤에 값 하나 지정하기 `SET`은 그 세션 동안만 유지됩니다. 더 넓은 범위 두 가지가 그 되풀이를 덜어 주며, 둘 다 지금 접속이 아니라 다음 접속부터 적용됩니다. 어떤 데이터베이스에 접속하는 모두에게 적용하려면: ```sql ALTER DATABASE docs SET graph_path = moviekb; ``` ``` ALTER DATABASE ``` 어느 데이터베이스에 접속하든 특정 롤 하나에 적용하려면: ```sql ALTER ROLE analyst SET graph_path = moviekb; ``` ``` ALTER ROLE ``` 둘 다 `pg_db_role_setting`에서 보이며, 롤 설정이 데이터베이스 설정을 이깁니다: ```sql SELECT r.rolname, s.setconfig FROM pg_db_role_setting s JOIN pg_roles r ON r.oid = s.setrole WHERE r.rolname = 'analyst'; ``` ``` rolname | setconfig ---------+---------------------- analyst | {graph_path=moviekb} ``` 그 뒤에 접속하는 롤에는 이미 값이 들어 있습니다: ```sql SHOW graph_path; ``` ``` graph_path ------------ moviekb ``` `ALTER DATABASE … RESET graph_path`와 `ALTER ROLE … RESET graph_path`가 그것을 다시 없앱니다. `postgresql.conf`에 클러스터 전체 기본값을 두는 것도 되지만, 원하는 바인 경우는 드뭅니다. 클러스터의 모든 데이터베이스가 그 그래프를 가진 것처럼 말하게 되기 때문입니다. 값은 카탈로그와 대조해 검사하므로, `ALTER DATABASE db SET graph_path`는 `db`에 접속한 상태에서 실행해야 합니다. 검사는 *현재* 데이터베이스에서 그 그래프를 찾습니다. 다른 곳에서 실행하면 실패합니다: ```sql ALTER DATABASE docs SET graph_path = moviekb; ``` ``` ERROR: invalid value for parameter "graph_path": "moviekb" DETAIL: graph "moviekb" does not exist. ``` {#guc-allow_null_properties} ## allow_null_properties ``` bool · default off · context user ``` null 속성 값을 저장할 것인지 버릴 것인지 결정합니다. 꺼져 있으면 null을 대입하는 것이 속성을 지웁니다. 그러면 null로 설정한 속성과 애초에 없던 속성이 같은 것이 됩니다. 켜면 null이 JSON null로 저장되고 키가 남습니다. ```cypher CREATE GRAPH nulls; SET graph_path = nulls; CREATE VLABEL t; CREATE (:t {name: 'a', extra: null}); SET allow_null_properties = on; CREATE (:t {name: 'b', extra: null}); MATCH (n:t) RETURN n ORDER BY id(n); ``` ``` n ------------------------------------ t[3.1]{"name": "a"} t[3.2]{"name": "b", "extra": null} ``` 값이 없는 것과 null인 것의 뜻이 다르고 그 구별을 지켜야 하는 데이터를 적재할 때 켜십시오. 보통 관계형 원본에서 가져오는 경우입니다. 대가는 저장된 null이 값 없이 존재하는 키가 된다는 것입니다. 검사들이 서로 다르게 답합니다: ```cypher MATCH (n:t) RETURN exists(n.extra) AS exists, n.extra IS NULL AS is_null, properties(n) ? 'extra' AS key_present; ``` ``` exists | is_null | key_present --------+---------+------------- f | t | t ``` `REMOVE n.extra`는 이 설정이 무엇이든 키를 지웁니다. 속성을 없애는 방법은 여전히 이것입니다. ```cypher RESET allow_null_properties; DROP GRAPH nulls CASCADE; SET graph_path = moviekb; ``` {#guc-auto_gather_graphmeta} ## auto_gather_graphmeta ``` bool · default off · context superuser ``` 모든 그래프 쓰기의 부수 효과로 `ag_graphmeta`를 최신 상태로 유지합니다. `ag_graphmeta`는 그래프의 (시작 레이블, 간선 레이블, 끝 레이블) 삼중마다 간선이 몇 개인지 기록합니다. 플래너는 그것으로 스캔을 쳐냅니다. 어떤 레이블과 도저히 일치할 수 없는 `MATCH`는 아예 스캔하지 않습니다. 이 설정이 꺼져 있으면 그 테이블은 마지막 `regather_graphmeta()` 호출 시점까지만 최신입니다. 켜면 즉시 전체 수집이 일어나므로, 그 시점부터 테이블이 정확해집니다: ```sql SET auto_gather_graphmeta = on; ``` ``` NOTICE: regathering graphmeta... SET ``` ```sql SELECT g.graphname, se.labname AS start, e.labname AS edge, ee.labname AS "end", m.edgecount FROM pg_catalog.ag_graphmeta m JOIN pg_catalog.ag_graph g ON g.oid = m.graph JOIN pg_catalog.ag_label e ON e.graphid = m.graph AND e.labid = m.edge JOIN pg_catalog.ag_label se ON se.graphid = m.graph AND se.labid = m.start JOIN pg_catalog.ag_label ee ON ee.graphid = m.graph AND ee.labid = m."end" WHERE g.graphname = 'moviekb' ORDER BY 3; ``` ``` graphname | start | edge | end | edgecount -----------+--------+------------+-------+----------- moviekb | person | acted_in | movie | 25 moviekb | person | directed | movie | 21 moviekb | movie | related_to | movie | 11 ``` ```cypher RESET auto_gather_graphmeta; ``` 읽기가 대부분인 그래프에는 켜십시오. 쓰기마다 드는 약간의 일보다 정확한 메타데이터가 값어치가 있습니다. 쓰기가 많은 적재에는 꺼 둔 채로 두고 끝난 뒤에 `regather_graphmeta()`를 호출하십시오. `pg_upgrade`나 복원 뒤에도 반드시 호출해야 합니다. 그 테이블과 그것이 가능하게 하는 쳐내기는 [그래프 메타데이터](../system_catalogs/graph-metadata.md)가 다룹니다. {#guc-cypher_allow_unsafe_ddl} ## cypher_allow_unsafe_ddl ``` bool · default off · context user ``` 카탈로그가 더는 설명하지 못하는 그래프와 사용자 사이를 평소에 막고 서 있는 카탈로그 검사 두 개를 건너뜁니다. 그래프를 고치기 위한 것이지, 그 상태로 작업하기 위한 것이 아닙니다. **`graph_path`가 존재하지 않는 그래프를 가리킬 수 있게 합니다.** 검사가 `SET` 시점에서 쿼리 실행 시점으로 옮겨 가고, 그때의 메시지는 다릅니다: ```sql SET cypher_allow_unsafe_ddl = on; SET graph_path = nosuchgraph; SHOW graph_path; ``` ``` graph_path ------------- nosuchgraph ``` ```cypher MATCH (n) RETURN count(n); ``` ``` ERROR: current graph_path "nosuchgraph" is invalid HINT: Use SET graph_path ``` ```cypher RESET cypher_allow_unsafe_ddl; SET graph_path = moviekb; ``` **레이블을 잘못된 종류로 삭제할 수 있게 합니다.** 간선 레이블에 `DROP VLABEL`을 쓰는 것은 평소에는 거부됩니다. 이 설정을 켜면 성공합니다: ```cypher CREATE GRAPH unsafe; SET graph_path = unsafe; CREATE ELABEL e; DROP VLABEL e; ``` ``` ERROR: DROP VLABEL cannot DROP edge label ``` ```cypher SET cypher_allow_unsafe_ddl = on; DROP VLABEL e; ``` ``` DROP VLABEL ``` ```cypher RESET cypher_allow_unsafe_ddl; DROP GRAPH unsafe CASCADE; SET graph_path = moviekb; ``` 둘이 쓸모 있는 상황은 정확히 하나입니다. 카탈로그와 테이블이 어긋난 그래프를 해체하려는 경우입니다. 그것이 필요한 문장에만 설정하고 곧바로 되돌리십시오. {#guc-eager_mem} ## eager_mem ``` integer · default 4096 · unit kB · context user · minimum 1024 ``` eager 계획 노드 하나가 디스크로 넘기기 전에 쓸 수 있는 메모리 양입니다. eager 계획을 위한 `work_mem`이며, `work_mem`이 그렇듯 쿼리별이나 접속별이 아니라 노드별입니다. ```sql SHOW eager_mem; SET eager_mem = '64MB'; SHOW eager_mem; ``` ``` eager_mem ----------- 4MB (1 row) SET eager_mem ----------- 64MB (1 row) ``` 최솟값은 1 MB이며, 더 작은 값은 잘라 맞추는 것이 아니라 거부됩니다: ```sql SET eager_mem = '512kB'; ``` ``` ERROR: 512 kB is outside the valid range for parameter "eager_mem" (1024 kB .. 2147483647 kB) ``` ```sql RESET eager_mem; ``` 자기가 쓴 것을 읽는 쓰기가 디스크로 넘어가고 있다면 올리십시오. [`enable_eager`](#guc-enable_eager)를 참고하십시오. 기본값 4 MB는 `work_mem`의 것과 같은 보수적인 출발점입니다. 큰 중간 결과를 구체화하는 문장은 이 값을 넘어섭니다. {#guc-enable_eager} ## enable_eager ``` bool · default on · context user ``` 플래너가 *eager* 계획, 즉 뒤의 절이 읽기 전에 쓰기의 출력을 구체화하는 계획을 만들 수 있게 합니다. 어떤 문장에는 그것이 필요합니다. `CREATE` 다음에, 그 `CREATE`가 방금 만든 것과 일치할 수 있는 `MERGE`가 오는 경우를 보십시오. 둘을 행 단위로 번갈아 실행할 수 없습니다. 두 번째 절이 절반만 쓰인 그래프를 보게 되기 때문입니다. 그래서 플래너는 첫 절의 결과를 버퍼에 담습니다. `EXPLAIN`은 그 노드를 `eager`로 표시합니다: ```cypher CREATE GRAPH eager; SET graph_path = eager; CREATE VLABEL src; CREATE VLABEL dst; CREATE (:src {n: 1}), (:src {n: 2}); EXPLAIN (COSTS OFF) MATCH (a:src) CREATE (:dst {n: a.n}) MERGE (:dst {n: a.n + 10}); ``` ``` QUERY PLAN ---------------------------------------------------------------------------------------------------------------- Graph Merge -> Nested Loop CypherMerge Join Join Filter: ("<0000000000>".properties.'n' = ((_agens_default_s_1.a).properties.'n' `+` '10'::jsonb)) -> Subquery Scan on _agens_default_s_1 -> Graph Create eager -> Seq Scan on src a -> Seq Scan on dst "<0000000000>" ``` 이것을 끈다고 해서 그런 문장이 다른 방식으로 실행되지는 않습니다. 실패하게 됩니다: ```cypher SET enable_eager = off; MATCH (a:src) CREATE (:dst {n: a.n}) MERGE (:dst {n: a.n + 10}); ``` ``` ERROR: eagerness plan is not allowed. ``` ```cypher RESET enable_eager; DROP GRAPH eager CASCADE; SET graph_path = moviekb; ``` 그러므로 이것은 PostgreSQL의 `enable_hashjoin` 같은 비용 기반 토글이 아닙니다. 켜 두십시오. 어떤 문장이 eager 계획에 의존하는지 알아보려 할 때만 끄십시오. 큰 쓰기를 더 싸게 만들려 할 때 그것이 중요해집니다. {#guc-enable_graph_ddl} ## enable_graph_ddl ``` bool · default off · context user ``` SQL DDL이 그래프 레이블의 모양을 바꿀 수 있게 합니다. 레이블을 그래프 레이블이게 하는 것은 그 컬럼들이고, 그래프 카탈로그가 그것을 설명합니다. `ALTER TABLE`은 그 카탈로그를 갱신하지 않습니다. 그것으로 레이블의 모양을 바꾸면 그래프가 더는 사실이 아닌 것을 설명하게 될 수 있습니다. 꺼져 있으면 그런 시도는 거부되고, 카탈로그를 함께 맞춰 주는 문장을 힌트로 알려 줍니다: ```sql ALTER TABLE moviekb.movie ADD COLUMN note text; ``` ``` ERROR: cannot add a column to graph label "movie" with ALTER TABLE HINT: Use ALTER VLABEL or ALTER ELABEL instead, which keeps the graph catalog in step. ``` ```sql ALTER TABLE moviekb.movie DROP COLUMN properties; ``` ``` ERROR: cannot drop a column of graph label "movie" with ALTER TABLE HINT: Use ALTER VLABEL or ALTER ELABEL instead, which keeps the graph catalog in step. ``` ```sql ALTER TABLE moviekb.movie NO INHERIT moviekb.ag_vertex; ``` ``` ERROR: cannot remove a parent label from graph label "movie" with ALTER TABLE HINT: A label's parents are fixed when it is created. ``` 거부되는 것의 전체 목록입니다. 컬럼을 더하거나 지우거나 타입을 바꾸는 것, 컬럼의 생성 표현식을 떼어 내거나 바꾸는 것, not-null 제약을 컬럼으로 지목하든 제약 이름으로 지목하든 지우는 것, 부모 레이블을 더하거나 없애는 것입니다. 같은 설정이 레이블의 컬럼 이름을 바꾸는 것과 레이블을 다른 스키마로 옮기는 것도 거부합니다. 켜면 그 모두가 풀립니다. 무슨 권한을 주는 것은 아닙니다. 그 레이블을 변경할 수 있는 사람이 여전히 그 레이블에 무슨 일이 일어날지 정합니다. 모양을 바꾸는 일이 의도된 것이기를 요구할 뿐입니다. 절대 풀리지 않는 것이 둘 있습니다. `id`·`start`·`end`·`properties`의 타입은 전혀 바꿀 수 없습니다. 모든 정점과 간선이 그 컬럼들로 이루어져 있기 때문입니다: ```sql SET enable_graph_ddl = on; ALTER TABLE moviekb.movie ALTER COLUMN properties TYPE text; ``` ``` ERROR: cannot change the type of column "properties" of graph label "movie" DETAIL: Every vertex and edge is made of that column. ``` ```sql RESET enable_graph_ddl; ``` 그리고 테이블 자체의 이름을 바꾸거나 지우는 것은 각자의 메시지와 함께 계속 거부됩니다 (`cannot rename table "movie"`, `cannot drop table … because vlabel … requires it`). `ALTER VLABEL … RENAME TO`와 `DROP VLABEL`을 쓰십시오. 직접 설정하든 하지 않든 이 설정을 만나게 됩니다. 평범한 컬럼을 지닌 레이블에 대해 `pg_dump`는 복원이 되도록 `ALTER TABLE` 문장을 `SET enable_graph_ddl = on`으로 감쌉니다. [서버 측 도구](../operations/tools.md)를 참고하십시오. {#guc-enable_graph_dml} ## enable_graph_dml ``` bool · default off · context superuser ``` 그래프 레이블에 대한 SQL `INSERT`·`UPDATE`·`DELETE`·`MERGE`를 허용합니다. SQL로 레이블을 읽는 데는 설정이 필요 없습니다. 쓰는 데는 필요합니다. Cypher의 쓰기 경로가 그래프를 일관되게 지키기 때문입니다. 존재하는 양 끝점, 레이블과 맞는 id, 그리고 그에 딸린 메타데이터입니다. 꺼져 있으면 모든 SQL 쓰기가 거부됩니다: ```psql INSERT INTO moviekb.movie (properties) VALUES ('{"title": "x"}'); ``` ``` ERROR: DML query to graph objects is not allowed ``` ```psql UPDATE moviekb.movie SET properties = '{}'; ``` ``` ERROR: DML query to graph objects is not allowed ``` ```sql DELETE FROM moviekb.movie; ``` ``` ERROR: DML query to graph objects is not allowed ``` 켜면 그래프가 말하는 대로라는 보장을 포기하게 됩니다. 간선 레이블에 대한 `INSERT`는 양 끝점이 존재하는지 검사하지 않으므로, 매달린 간선을 만들 수 있습니다. Cypher로는 그런 것을 만들 수 없습니다: ```psql CREATE GRAPH dangling; SET graph_path = dangling; CREATE VLABEL v; CREATE ELABEL e; CREATE (:v {n: 1}); SET enable_graph_dml = on; INSERT INTO dangling.e (start, "end", properties) VALUES ('3.1'::graphid, '99.99'::graphid, '{}'); RESET enable_graph_dml; ``` ``` INSERT 0 1 ``` 그 결과는 서로 다른 두 쿼리가 다르게 답하는 간선입니다. 양 끝점을 모두 묶는 패턴은 아무것도 찾지 못합니다. 없는 정점과의 조인이 실패하기 때문입니다: ```cypher MATCH (a)-[r:e]->(b) RETURN a, r, b; ``` ``` a | r | b ---+---+--- (0 rows) ``` 양 끝점을 아무것도 묶지 않는 패턴은 그것을 셉니다. 조인할 것이 없기 때문입니다: ```cypher MATCH ()-[r:e]->() RETURN count(r) AS edges; ``` ``` edges ------- 1 ``` ```cypher DROP GRAPH dangling CASCADE; SET graph_path = moviekb; ``` 조심해서 작성한 대량 적재를 할 때, 또는 Cypher가 닿지 못하는 행을 고칠 때 켰다가 다시 끄십시오. `superuser` 설정 둘 중 하나입니다. 평범한 롤이 `SET enable_graph_dml = on`을 시도하면 `ERROR: permission denied to set parameter "enable_graph_dml"`을 받으며, 스스로 켤 수 없습니다. {#guc-enable_graph_endpoint_elision} ## enable_graph_endpoint_elision ``` bool · default on · context user ``` 쿼리가 전혀 쓰지 않는 패턴 끝점에 대한 스캔을 플래너가 없앨 수 있게 합니다. `->()` 같은 익명 끝점은 조인 말고는 보태는 것이 없습니다. 그 끝점에 레이블도 속성 조건도 없다면 그 조인은 행을 걸러 내지도 못합니다. 플래너는 그것을 없앱니다. 이름이 레이블을 제한하는 데만 쓰인 경우에는 이름 있는 끝점도 없앱니다. 간선의 끝점 id에 대한 레이블 검사는 그 간선 자체에 대한 `graphid` 범위 검사이기 때문입니다: ```cypher EXPLAIN (COSTS OFF) MATCH (p:person)-[r:acted_in]->() RETURN count(r); ``` ``` QUERY PLAN ----------------------------------------------------------------------------------------- Aggregate -> Seq Scan on acted_in r Filter: ((start >= '4.0'::graphid) AND (start <= '4.281474976710655'::graphid)) ``` 이것이 없으면 같은 쿼리가 릴레이션 세 개를 조인하고, 들여다보지도 않을 끝점을 위해 정점 계층 전체를 스캔합니다: ```cypher SET enable_graph_endpoint_elision = off; EXPLAIN (COSTS OFF) MATCH (p:person)-[r:acted_in]->() RETURN count(r); ``` ``` QUERY PLAN ----------------------------------------------------------------------------------------------------- Aggregate -> Hash Join Hash Cond: (r."end" = "<0000000001>".id) -> Hash Join Hash Cond: (r.start = p.id) -> Seq Scan on acted_in r Filter: ((start >= '4.0'::graphid) AND (start <= '4.281474976710655'::graphid)) -> Hash -> Seq Scan on person p -> Hash -> Append -> Seq Scan on ag_vertex "<0000000001>_1" -> Seq Scan on movie "<0000000001>_2" -> Seq Scan on person "<0000000001>_3" ``` ```sql RESET enable_graph_endpoint_elision; ``` 열한 개 중 `EXPLAIN (SETTINGS)`가 보고하는 것은 이것뿐이므로, 이 값을 바꾼 세션에서 뽑은 계획은 그 사실을 함께 알려 줍니다. 계획을 비교할 때만 끄십시오. {#guc-enable_multiple_update} ## enable_multiple_update ``` bool · default on · context user ``` 한 문장에서 같은 요소를 두 번 이상 쓰는 것을 조용히 넘길지 경고할지 결정합니다. 패턴이 어떤 요소와 여러 번 일치하는 문장은 일치할 때마다 그것을 씁니다. 켜져 있으면 그 일이 조용히 일어납니다. 꺼져 있으면 서버가 되풀이마다 경고합니다. 쓰기는 그대로 일어나므로, 이것은 제한이 아니라 진단 장치입니다: ```cypher CREATE GRAPH repeats; SET graph_path = repeats; CREATE VLABEL t; CREATE (:t {n: 0}), (:t {n: 0}); MATCH (a:t) MATCH (b:t) SET b.n = b.n + 1 RETURN count(b) AS rows; MATCH (n:t) RETURN n ORDER BY id(n); ``` ``` rows ------ 4 ``` ``` n ---------------- t[3.1]{"n": 1} t[3.2]{"n": 1} ``` 크로스 조인이 행 네 개를 만들어 각 정점에 두 번씩 닿았지만, `n`은 하나만 올랐습니다. 설정을 끄면 같은 문장이 그 사실을 알려 줍니다: ```cypher SET enable_multiple_update = off; MATCH (a:t) MATCH (b:t) SET b.n = b.n + 1 RETURN count(b) AS rows; ``` ``` WARNING: graph element(3,1) has been SET multiple times WARNING: graph element(3,2) has been SET multiple times rows ------ 4 ``` ```cypher RESET enable_multiple_update; DROP GRAPH repeats CASCADE; SET graph_path = moviekb; ``` `SET`이 기대한 대로 하지 않은 이유를 따질 때 꺼 두십시오. 되풀이된 쓰기는 대개 패턴이 의도보다 많이 일치한다는 신호입니다. 경고는 레이블 id와 로컬 id를 알려 주는데, 그것이 그 요소의 `graphid`입니다. {#guc-enable_property_promotion} ## enable_property_promotion ``` bool · default on · context user ``` 승격된 타입 컬럼이 있을 때 Cypher의 속성 읽기를 그 컬럼에서 답할지 결정합니다. 속성은 실제 타입을 가진 실제 컬럼으로 구체화할 수 있습니다. [속성을 컬럼으로 승격하기](../querying/typed-columns.md)를 참고하십시오. 켜져 있으면 `n.key`가 그 컬럼을 읽고 그 컬럼의 타입으로 돌아옵니다. 꺼져 있으면 모든 읽기가 `jsonb` 컬럼인 `properties`로 가서 `jsonb`로 돌아옵니다: ```cypher CREATE GRAPH promoted; SET graph_path = promoted; CREATE VLABEL item (score int GENERATED); CREATE (:item {score: 3}), (:item {score: 20}), (:item {score: 100}); MATCH (n:item) RETURN n.score AS score, pg_typeof(n.score) AS type ORDER BY n.score; ``` ``` score | type -------+----------- 3 | "integer" 20 | "integer" 100 | "integer" ``` ```cypher SET enable_property_promotion = off; MATCH (n:item) RETURN n.score AS score, pg_typeof(n.score) AS type ORDER BY n.score; ``` ``` score | type -------+--------- 3 | "jsonb" 20 | "jsonb" 100 | "jsonb" ``` ```{warning} 비용에만 관여하는 플래너 토글과 달리, 이것을 끄면 쿼리 **결과**가 달라질 수 있습니다. 해석된 `n.key`는 그 타입 컬럼의 고유한 의미 — 수치 또는 콜레이션 정렬, 그리고 타입을 아는 비교 — 를 쓰는 반면, `jsonb` 대체 경로는 `jsonb`의 정렬과 비교를 씁니다. 정렬이나 범위 조건, 타입이 다른 값끼리의 비교가 다르게 나올 수 있습니다. ``` ```cypher RESET enable_property_promotion; DROP GRAPH promoted CASCADE; SET graph_path = moviekb; ``` 켜 두십시오. 승격된 컬럼이 쿼리의 답을 바꿨는지 확인할 때 끄십시오. 그리고 다시 켠 뒤에 쿼리나 컬럼 쪽을 고치십시오. {#guc-see-also} ## 관련 항목 - [설정](../operations/configuration.md) — 설정을 어디에 지정할 수 있는지, 그리고 그래프 워크로드에 중요한 PostgreSQL 설정 - [구문](syntax.md) — `graph_path`의 값이 따르는 어휘 규칙 - [데이터 타입](types.md) — `allow_null_properties`와 `enable_property_promotion`이 속성의 타입에 관해 바꾸는 것 - [그래프 메타데이터](../system_catalogs/graph-metadata.md) — `auto_gather_graphmeta`가 유지하는 테이블 - [서버 측 도구](../operations/tools.md) — `pg_dump`·`pg_upgrade`와 그것들이 기대는 설정 - [PostgreSQL: 서버 설정](https://www.postgresql.org/docs/18/runtime-config.html) — 그 밖의 모든 설정