{#label-inheritance-label-inheritance} # 레이블 상속 레이블은 다른 레이블을 상속할 수 있습니다. 자식은 자기 id 시퀀스와 자기 행을 가진 별개의 레이블이지만, 부모를 이름으로 부르는 패턴은 자식의 행에도 일치합니다. 덕분에 계열 전체를 하나의 패턴으로 쿼리하는 능력을 포기하지 않고도 타입 계층을 가질 수 있습니다. 이 상속은 PostgreSQL의 테이블 상속입니다 — [레이블은 테이블](graph-on-postgresql.md)이고, 레이블에 준 `INHERITS`는 그 테이블의 `INHERITS`가 됩니다. {#label-inheritance-declaring-a-hierarchy} ## 계층 선언하기 이 페이지의 예제는 [예제 데이터셋](../get_started/example-dataset.md)을 쓰지 않고 자체의 작은 그래프를 만듭니다. 상속은 영화와 사람보다 계층 구조에서 보기가 쉽기 때문입니다. 다 보고 나면 `DROP GRAPH inh CASCADE;`를 실행하십시오. ```cypher CREATE GRAPH inh; SET graph_path = inh; CREATE VLABEL work; CREATE VLABEL film INHERITS (work); CREATE VLABEL series INHERITS (work); CREATE (:film {title: 'A'}), (:series {title: 'B'}), (:work {title: 'C'}); ``` 부모를 이름으로 부르면 계열의 모든 행에 일치합니다: ```cypher MATCH (n:work) RETURN label(n) AS label, n.title AS t ORDER BY t; ``` ``` label | t ----------+----- "film" | "A" "series" | "B" "work" | "C" ``` 자식을 이름으로 부르면 그 자식에만 일치합니다: ```cypher MATCH (n:film) RETURN label(n) AS label, n.title AS t; ``` ``` label | t --------+----- "film" | "A" ``` `label(n)`이 무엇을 반환하는지 보십시오. 정점이 만들어질 때의 레이블이고, 부모는 결코 아닙니다. 정점은 정확히 하나의 레이블에 속합니다. "부모에 일치한다"는 것은 패턴이 어느 테이블을 스캔하는지에 대한 이야기이고, 정점이 레이블 두 개를 갖는다는 이야기가 아닙니다. {#label-inheritance-only-excluding-the-children} ## ONLY: 자식을 제외하기 `ONLY`는 패턴을 이름으로 부른 그 레이블 자체로 제한합니다: ```cypher MATCH (n:work ONLY) RETURN label(n) AS label, n.title AS t; ``` ``` label | t --------+----- "work" | "C" ``` 간선에도 쓸 수 있고, 대괄호 안에 적습니다: ```cypher MATCH ()-[e:rel ONLY]->() RETURN count(e) AS n; ``` ``` n --- 0 ``` 이 0이 바로 유용한 경우입니다. `rel`에는 자식 `sequel`이 있고 모든 간선이 `sequel`로 만들어졌으므로, `rel ONLY`는 그중 하나도 일치시키지 못하지만 그냥 `rel`은 전부 일치시킵니다. {#label-inheritance-edges-inherit-the-same-way} ## 간선도 같은 방식으로 상속한다 ```cypher CREATE ELABEL rel; CREATE ELABEL sequel INHERITS (rel); MATCH (a:film {title: 'A'}), (b:series {title: 'B'}) CREATE (a)-[:sequel]->(b); MATCH ()-[e:rel]->() RETURN label(e) AS label; ``` ``` label ---------- "sequel" ``` {#label-inheritance-more-than-one-parent} ## 부모가 둘 이상일 때 레이블은 여러 레이블을 한 번에 상속할 수 있습니다: ```cypher CREATE VLABEL hybrid INHERITS (work, film); ``` 그러면 `hybrid`의 행은 `MATCH (n:work)`에도 일치하고 `MATCH (n:film)`에도 일치합니다. {#label-inheritance-what-every-graph-already-inherits} ## 모든 그래프가 이미 상속하고 있는 것 직접 만드는 모든 레이블은 `INHERITS` 절을 쓰지 않아도 `ag_vertex`나 `ag_edge`를 상속합니다. 레이블 없는 `MATCH (n)`이 모든 것에 일치하는 이유가 그것입니다. [그래프가 어떻게 저장되는가](#graph-on-postgresql-every-graph-has-two-labels-you-did-not-create)를 참고하십시오. {#label-inheritance-what-it-costs} ## 비용은 무엇인가 부모에 대한 패턴은 부모의 테이블과 그 아래 모든 테이블을 스캔하므로, 실행 계획에 계열 전체를 훑는 `Append`가 붙습니다: ```cypher EXPLAIN (COSTS OFF) MATCH (n:work) RETURN n; ``` ``` QUERY PLAN ------------------------------------ Result -> Append -> Seq Scan on work n_1 -> Seq Scan on film n_2 -> Seq Scan on series n_3 -> Seq Scan on hybrid n_4 ``` `ONLY`는 그 `Append`를 없앱니다: ```cypher EXPLAIN (COSTS OFF) MATCH (n:work ONLY) RETURN n; ``` ``` QUERY PLAN -------------------- Seq Scan on work n ``` 여기서 두 가지가 따라옵니다. 계층이 깊으면, "한 레이블의 행을 달라"는 가장 값싼 쿼리조차 필요보다 많은 관계에 대해 계획을 세우게 됩니다. 그러므로 한 레이블의 행만 원한다면 자식을 이름으로 부르거나 `ONLY`를 붙이십시오. 그리고 인덱스는 스캔될 테이블마다 있어야 합니다. `work`에 걸린 인덱스가 `film`의 행을 인덱싱해 주지는 않습니다. 계층 전체에 인덱스를 만드는 방법은 [인덱스와 제약](../querying/indexes-and-constraints.md)이 다룹니다. ```{note} 쿼리가 정말로 계열 전체를 원할 때 상속을 꺼내십시오 — 어떤 때는 `film`이고 어떤 때는 `series`인 `work` 같은 경우입니다. 어차피 모든 쿼리가 자식을 이름으로 부른다면, 레이블을 따로 두는 편이 더 단순하고 계획도 더 잘 나옵니다. ```