PostgreSQL์์ ์กฐ์ง๋ ๋ชจ๋ธ๋ง: ์ธ์ ๋ฆฌ์คํธ vs ํด๋ก์
์ธ์ ๋ฆฌ์คํธ์ ํด๋ก์ ํ ์ด๋ธ์ ๋น๊ตํด PostgreSQL์์ ์กฐ์ง๋๋ฅผ ๋ชจ๋ธ๋งํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค. ํํฐ๋ง, ๋ฆฌํฌํ , ๊ถํ ๊ฒ์ฌ ์์ ๋ฅผ ํฌํจํฉ๋๋ค.

์กฐ์ง๋์ ํ์ํ ๊ฒ๋ค
์กฐ์ง๋๋ ๋๊ฐ ๋๊ตฌ์๊ฒ ๋ณด๊ณ ํ๋์ง, ํ์ด ์ด๋ป๊ฒ ๋ถ์๋ก ๋ฌถ์ด๋์ง ๋ณด์ฌ์ฃผ๋ ์ง๋์
๋๋ค. PostgreSQL์์ ์กฐ์ง๋๋ฅผ ๋ชจ๋ธ๋งํ ๋ ๋จ์ํ ๊ฐ ์ฌ๋์๊ฒ manager_id๋ฅผ ์ ์ฅํ๋ ๊ฒ ์ด์์ ์ผ์ ํ๊ฒ ๋ฉ๋๋ค. ์ค์ ์
๋ฌด(์กฐ์ง ํ์, ๋ฆฌํฌํ
, ์ ๊ทผ ๊ท์น)๋ฅผ ์ง์ํด์ผ ํฉ๋๋ค.
๋๋ถ๋ถ์ ์ฌ์ฉ์๋ ์ธ ๊ฐ์ง๋ฅผ ์ฆ๊ฐ์ ์ผ๋ก ๊ธฐ๋ํฉ๋๋ค: ์กฐ์ง ํ์, ์ฌ๋ ์ฐพ๊ธฐ, ๊ทธ๋ฆฌ๊ณ ๊ฒฐ๊ณผ๋ฅผ "๋ด ์์ญ"์ผ๋ก ํํฐ๋งํ๋ ๊ฒ. ์ ๋ฐ์ดํธ๋ ์์ ํด์ผ ํฉ๋๋ค. ๋งค๋์ ๊ฐ ๋ฐ๋๋ฉด ์ฐจํธ๊ฐ ๋ณด๊ณ ์๋ ๊ถํ์ ๋ง๊ฐ๋จ๋ฆฌ์ง ์๊ณ ๋ชจ๋ ๊ณณ์์ ์ฆ์ ๋ฐ์๋์ด์ผ ํฉ๋๋ค.
ํ์ค์ ์ผ๋ก ์ข์ ๋ชจ๋ธ์ ๋ช ๊ฐ์ง ๋ฐ๋ณต๋๋ ์ง๋ฌธ์ ๋ตํ ์ ์์ด์ผ ํฉ๋๋ค:
- ์ด ์ฌ๋์ ์งํ ๊ณ๋ณด(์ต์์๊น์ง)๋ ๋ฌด์์ธ๊ฐ?
- ์ด ๋งค๋์ ์๋์๋ ๋๊ฐ ์๋๊ฐ(์ง์ ๋ณด๊ณ ์ ์ ์ฒด ์๋ธํธ๋ฆฌ)?
- ๋์๋ณด๋๋ฅผ ์ํด ์ฌ๋๋ค์ด ์ด๋ป๊ฒ ํ๊ณผ ๋ถ์๋ก ๊ทธ๋ฃนํ๋๋๊ฐ?
- ์ฌ์กฐ์ง์ ์ด๋ป๊ฒ ๊ธ๋ฆฌ์น ์์ด ์ผ์ด๋๋?
- ์กฐ์ง ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋๊ฐ ๋ฌด์์ ๋ณผ ์ ์๋๊ฐ?
๋จ์ ํธ๋ฆฌ๋ณด๋ค ๋ ์ด๋ ค์ด ์ ์ ์กฐ์ง์ด ์์ฃผ ๋ณํ๋ค๋ ์ฌ์ค์ ๋๋ค. ํ์ด ๋ถ์๋ฅผ ์ฎ๊ธฐ๊ณ , ๋งค๋์ ๊ฐ ๊ทธ๋ฃน์ ๋ฐ๊พธ๊ณ , ์ผ๋ถ ๋ทฐ๋ ๋จ์ํ "์ฌ๋์ด ์ฌ๋์๊ฒ ๋ณด๊ณ ํ๋ค"๋ก ํํ๋์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด: ์ฌ๋์ ํ์ ์ํ๊ณ ํ์ ๋ถ์์ ์ํฉ๋๋ค. ๊ถํ์ ๋ ๋ค๋ฅธ ์ธต์ ์ถ๊ฐํฉ๋๋ค: ์กฐ์ง์ ํํ๊ฐ ๋จ์ง ๋ค์ด์ด๊ทธ๋จ์ด ์๋๋ผ ๋ณด์ ๋ชจ๋ธ์ ์ผ๋ถ๊ฐ ๋ฉ๋๋ค.
๋ช ๊ฐ์ง ์ฉ์ด๋ฅผ ์ ๋ฆฌํ๋ฉด ์ค๊ณ๊ฐ ๋ช ํํด์ง๋๋ค:
- ๋ ธ๋(node): ๊ณ์ธต ๊ตฌ์กฐ์ ํ ํญ๋ชฉ(์ฌ๋, ํ, ๋๋ ๋ถ์).
- ๋ถ๋ชจ(parent): ๋ฐ๋ก ์์ ๋ ธ๋(๋งค๋์ ๋๋ ํ์ ์์ ํ ๋ถ์).
- ์ ์กฐ(ancestor): ์์์ ๊ฑฐ๋ฆฌ ์์ ์๋ ๋ ธ๋(๋น์ ์ ๋งค๋์ ์ ๋งค๋์ ).
- ํ์(descendant): ์์์ ๊ฑฐ๋ฆฌ ์๋์ ์๋ ๋ ธ๋(๋น์ ์๋์ ๋ชจ๋ ์ฌ๋).
์์: Sales๊ฐ ์๋ก์ด VP ์๋๋ก ์ฎ๊ฒจ์ก๋ค๋ฉด ๋ ๊ฐ์ง๋ ์ฆ์ ์ ์ง๋์ด์ผ ํฉ๋๋ค. ๋์๋ณด๋๋ ์ฌ์ ํ "Sales ์ ์ฒด"๋ก ํํฐ๋ง๋๊ณ , ์๋ก์ด VP์ ๊ถํ์ Sales๋ฅผ ์๋์ผ๋ก ํฌํจํด์ผ ํฉ๋๋ค.
ํ ์ด๋ธ ์ค๊ณ ์ ์ ๋ด๋ ค์ผ ํ ๊ฒฐ์ ๋ค
์คํค๋ง๋ฅผ ํ์ ํ๊ธฐ ์ ์ ์ฑ์ด ๋งค์ผ ๋ตํด์ผ ํ๋ ์ง๋ฌธ์ ๋ช ํํ ํ์ธ์. "๋๊ฐ ๋๊ตฌ์๊ฒ ๋ณด๊ณ ํ๋?"๋ ์์์ผ ๋ฟ์ ๋๋ค. ๋ง์ ์กฐ์ง๋๋ ๋๊ฐ ๋ถ์๋ฅผ ์ด๋๋์ง, ๋๊ฐ ํ์ ํด๊ฐ๋ฅผ ์น์ธํ๋์ง, ๋๊ฐ ๋ฆฌํฌํธ๋ฅผ ๋ณผ ์ ์๋์ง๋ฅผ ๋ณด์ฌ์ค์ผ ํฉ๋๋ค.
ํ๋ฉด๊ณผ ๊ถํ ๊ฒ์ฌ๊ฐ ๋ฌป๋ ์ ํํ ์ง๋ฌธ์ ์ ์ด๋ณด์ธ์. ์ง๋ฌธ์ ๊ตฌ์ฒด์ ์ผ๋ก ์ด๋ฆ ์ง์ ์ ์๋ค๋ฉด, ๋ณด๊ธฐ์๋ ๋ง์ ๋ณด์ด์ง๋ง ์ฟผ๋ฆฌํ๊ธฐ ์ด๋ ค์ด ์คํค๋ง๊ฐ ๋์ค๊ธฐ ์ฝ์ต๋๋ค.
๋ชจ๋ ๊ฒ์ ๊ฒฐ์ ์ง๋ ์ ํ๋ค:
- ์ด๋ค ์ฟผ๋ฆฌ๋ฅผ ๋น ๋ฅด๊ฒ ๋ง๋ค์ด์ผ ํ๋: ์ง์ ๋งค๋์ , CEO๊น์ง์ ๊ณ๋ณด, ๋ฆฌ๋ ์๋์ ์ ์ฒด ์๋ธํธ๋ฆฌ, ํน์ "์ด ๋ถ์์ ๋ชจ๋ ์ฌ๋"?
- ์ด๊ฒ์ด ์๊ฒฉํ ํธ๋ฆฌ(ํ๋์ ๋งค๋์ )์ธ๊ฐ, ์๋๋ฉด ๋งคํธ๋ฆญ์ค ์กฐ์ง(๋ ์ด์์ ๋งค๋์ ๋๋ ๋ฆฌ๋)์ด ํ์ํ๊ฐ?
- ๋ถ์๋ ์ฌ๋๊ณผ ๊ฐ์ ๊ณ์ธต์ ๋
ธ๋๋ก ํํํ ๊ฒ์ธ๊ฐ, ์๋๋ฉด ๊ฐ ์ฌ๋์
department_id๊ฐ์ ๋ณ๋ ์์ฑ์ผ๋ก ๋ ๊ฒ์ธ๊ฐ? - ๋๊ตฐ๊ฐ๊ฐ ์ฌ๋ฌ ํ์ ์ํ ์ ์๋๊ฐ(๊ณต์ ์๋น์ค, ์ค์ฟผ๋)?
- ๊ถํ์ ํธ๋ฆฌ ์๋๋ก ํ๋ฅด๋๊ฐ, ์๋ก ํ๋ฅด๋๊ฐ, ์๋๋ฉด ์์ชฝ ๋ชจ๋์ธ๊ฐ?
์ด ์ ํ๋ค์ด "์ ํํ" ๋ฐ์ดํฐ๊ฐ ๋ฌด์์ธ์ง ์ ์ํฉ๋๋ค. Alex๊ฐ Support์ Onboarding ๋ ๋ค ์ด๋๋ค๋ฉด ๋จ์ผ manager_id๋ "ํ๋ณ ํ ๋ช
์ ๋ฆฌ๋" ๊ท์น์ ์๋ํ์ง ์์ ์ ์์ต๋๋ค. ๋ฆฌ๋-ํ ์กฐ์ธ ํ
์ด๋ธ์ด๋ "์ฃผ์ ํ 1๊ฐ์ ์ ์ ํ" ๊ฐ์ ๋ช
ํํ ์ ์ฑ
์ด ํ์ํ ์ ์์ต๋๋ค.
๋ถ์๋ ๋ ๋ค๋ฅธ ๊ฐ๋ฆผ๊ธธ์
๋๋ค. ๋ถ์๋ฅผ ๋
ธ๋๋ก ๋ค๋ฃจ๋ฉด "Department A๊ฐ Team B๋ฅผ ํฌํจํ๊ณ Team B๊ฐ Person C๋ฅผ ํฌํจํ๋ค"๋ฅผ ํํํ ์ ์์ต๋๋ค. ๋ถ์๋ฅผ ๋ณ๋๋ก ๋๋ฉด department_id = X๋ก ํํฐ๋งํ๋ ๊ฒ์ด ๋ ๋จ์ํ์ง๋ง, ํ์ด ๋ถ์๋ฅผ ๊ฐ๋ก์ง๋ฅผ ๋ ๋ฌด๋์ง ์ ์์ต๋๋ค.
๋ง์ง๋ง์ผ๋ก ๊ถํ์ ํ์ดํ ์ธ์ด๋ก ์ ์ํ์ธ์. "๋งค๋์ ๋ ์๋์ ๋ชจ๋ ์ฌ๋์ ๊ธ์ฌ๋ฅผ ๋ณผ ์ ์์ง๋ง ๋๋ฃ๋ ๋ณผ ์ ์๋ค"๋ ์๋-ํธ๋ฆฌ ๊ท์น์ ๋๋ค. "๋๊ตฌ๋ ์์ ์ ๊ด๋ฆฌ ๊ณ๋ณด๋ ๋ณผ ์ ์๋ค"๋ ์-ํธ๋ฆฌ ๊ท์น์ ๋๋ค. ์ด ๋ถ๋ถ์ ์ผ์ฐ ๊ฒฐ์ ํ์ธ์. ์ด๋ค ๋ชจ๋ธ์ด ์์ฐ์ค๋ฝ๊ฒ ๋๊ปด์ง์ง, ์ด๋ค ๊ฒ์ด ๋์ค์ ๊ฐ๋น์ผ ์ฟผ๋ฆฌ๋ฅผ ๊ฐ์ํ ์ง ๋ฌ๋ผ์ง๋๋ค.
์ธ์ ๋ฆฌ์คํธ: ๋งค๋์ ์ ํ์ ์ ํฉํ ๋จ์ ์คํค๋ง
์ต์ํ์ ๊ตฌ์ฑ ์์๋ฅผ ์ํ๋ค๋ฉด ์ธ์ ๋ฆฌ์คํธ(adjacency list)๊ฐ ๊ณ ์ ์ ์ธ ์ถ๋ฐ์ ์ ๋๋ค. ๊ฐ ์ฌ๋์ด ์ง์ ๋งค๋์ ๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ๋ฅผ ์ ์ฅํ๊ณ , ๊ทธ ํฌ์ธํฐ๋ฅผ ๋ฐ๋ผ ํธ๋ฆฌ๋ฅผ ๋ง๋ค์ด ๊ฐ๋๋ค.
์ต์ํ์ ์ค์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
create table departments (
id bigserial primary key,
name text not null unique
);
create table teams (
id bigserial primary key,
department_id bigint not null references departments(id),
name text not null,
unique (department_id, name)
);
create table employees (
id bigserial primary key,
full_name text not null,
team_id bigint references teams(id),
manager_id bigint references employees(id)
);
๋ณ๋ ํ
์ด๋ธ์ ์๋ตํ๊ณ department_name๊ณผ team_name์ employees์ ์ปฌ๋ผ์ผ๋ก ๋๋ ๊ฒ๋ ๊ฐ๋ฅํฉ๋๋ค. ์์์ ๋น ๋ฅด์ง๋ง ์ ๋ฆฌ ์ ์ง๊ฐ ์ด๋ ต์ต๋๋ค(์คํ, ์ด๋ฆ ๋ณ๊ฒฝ, ๋ถ์ผ์น ๋ฑ). ๋ณ๋ ํ
์ด๋ธ์ ํํฐ๋ง๊ณผ ๊ถํ ๊ท์น์ ์ผ๊ด๋๊ฒ ํํํ๊ธฐ ์ฝ์ต๋๋ค.
์ด๊ธฐ๋ถํฐ ๊ฐ๋๋ ์ผ์ ์ถ๊ฐํ์ธ์. ์๋ชป๋ ๊ณ์ธต ๋ฐ์ดํฐ๋ ๋์ค์ ๊ณ ์น๊ธฐ ๊ณ ํต์ค๋ฝ์ต๋๋ค. ์ต์ํ ์๊ธฐ ์์ ์ ๋งค๋์ ๋ก ์ง์ ํ๋ ๊ฒ์ ๋ฐฉ์ง(manager_id <> id)ํ๊ณ , ๋งค๋์ ๊ฐ ๊ฐ์ ํ/๋ถ์ ๋ฐ์ ์์ ์ ์๋์ง, ์ํํธ ์ญ์ ๋ ๋ณ๊ฒฝ ์ด๋ ฅ์ด ํ์ํ์ง(๊ฐ์ฌ ๋ชฉ์ ) ๊ฒฐ์ ํ์ธ์.
์ธ์ ๋ฆฌ์คํธ์์๋ ๋๋ถ๋ถ์ ๋ณ๊ฒฝ์ด ๋จ์ํ ์ฐ๊ธฐ์
๋๋ค: ๋งค๋์ ๋ณ๊ฒฝ์ employees.manager_id๋ฅผ ์
๋ฐ์ดํธํ๊ณ , ํ ์ด๋์ employees.team_id๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค(์ข
์ข
๋งค๋์ ์ ํจ๊ป). ๋ฌธ์ ๋ ์์ ์ฐ๊ธฐ๊ฐ ํฐ ํ๋ฅ ์ํฅ์ ์ค ์ ์๋ค๋ ์ ์
๋๋ค. ๋ฆฌํฌํ
์ง๊ณ๊ฐ ๋ฐ๋๊ณ , "๋งค๋์ ๋ ๋ชจ๋ ๋ณด๊ณ ์๋ฅผ ๋ณผ ์ ์๋ค"๋ ๊ท์น์ ์๋ก์ด ์ฒด์ธ์ ๋ฐ๋ผ์ผ ํฉ๋๋ค.
์ด ๋จ์ํจ์ด ์ธ์ ๋ฆฌ์คํธ์ ์ต๋ ์ฅ์ ์ ๋๋ค. ๋ฐ๋ฉด ์ฝ์ ์ "์ด ๋งค๋์ ์๋์ ๋ชจ๋ ์ฌ๋"์ ์์ฃผ ํํฐ๋งํ ๋ ๋๋ฌ๋ฉ๋๋ค. ๋ณดํต ๋งค๋ฒ ํธ๋ฆฌ๋ฅผ ์ํํ๋ ์ฌ๊ท ์ฟผ๋ฆฌ์ ์์กดํด์ผ ํฉ๋๋ค.
์ธ์ ๋ฆฌ์คํธ: ํํฐ๋ง๊ณผ ๋ฆฌํฌํ ์ ์ํ ์ผ๋ฐ ์ฟผ๋ฆฌ๋ค
์ธ์ ๋ฆฌ์คํธ๋ก ๋ชจ๋ธ๋งํ๋ฉด ์์ฃผ ์ฐ๋ ์กฐ์ง๋ ์ง๋ฌธ๋ค์ด ์ฌ๊ท ์ฟผ๋ฆฌ ํจํด์ผ๋ก ๋ณํฉ๋๋ค. PostgreSQL์์ ์ด๋ ๊ฒ ๋ชจ๋ธ๋งํ๋ฉด ์์ฃผ ์ฌ์ฉํ๋ ํจํด์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ง์ ๋ณด๊ณ (ํ ๋จ๊ณ)
๊ฐ์ฅ ๋จ์ํ ๊ฒฝ์ฐ๋ ๋งค๋์ ์ ์ฆ๊ฐ์ ์ธ ํ์ ๋๋ค:
SELECT id, full_name, title
FROM employees
WHERE manager_id = $1
ORDER BY full_name;
์ด ์ฟผ๋ฆฌ๋ ๋น ๋ฅด๊ณ ์ฝ๊ธฐ ์ฝ์ง๋ง ํ ๋จ๊ณ๋ง ๋ด๋ ค๊ฐ๋๋ค.
๊ณ๋ณด(์๋ก ์ฌ๋ผ๊ฐ๊ธฐ)
๋๊ตฐ๊ฐ๊ฐ ๋๊ตฌ์๊ฒ ๋ณด๊ณ ํ๋์ง(๋งค๋์ , ๋งค๋์ ์ ๋งค๋์ ๋ฑ)๋ฅผ ๋ณด์ฌ์ฃผ๋ ค๋ฉด ์ฌ๊ท CTE๋ฅผ ์ฌ์ฉํ์ธ์:
WITH RECURSIVE chain AS (
SELECT id, full_name, manager_id, 0 AS depth
FROM employees
WHERE id = $1
UNION ALL
SELECT e.id, e.full_name, e.manager_id, c.depth + 1
FROM employees e
JOIN chain c ON e.id = c.manager_id
)
SELECT *
FROM chain
ORDER BY depth;
์น์ธ ๊ฒฝ๋ก, ์์ค์ปฌ๋ ์ด์ , ๋งค๋์ ๋ธ๋ ๋ํฌ๋ผ์ ์ ์ฉํฉ๋๋ค.
์ ์ฒด ์๋ธํธ๋ฆฌ(์๋๋ก)
๋ฆฌ๋ ์๋์ ๋ชจ๋ ์ฌ๋์ ์ป์ผ๋ ค๋ฉด ์ฌ๊ท๋ฅผ ๋ฐ๋๋ก ์ฌ์ฉํฉ๋๋ค:
WITH RECURSIVE subtree AS (
SELECT id, full_name, manager_id, department_id, 0 AS depth
FROM employees
WHERE id = $1
UNION ALL
SELECT e.id, e.full_name, e.manager_id, e.department_id, s.depth + 1
FROM employees e
JOIN subtree s ON e.manager_id = s.id
)
SELECT *
FROM subtree
ORDER BY depth, full_name;
ํํ ๋ฆฌํฌํธ๋ "๋ฆฌ๋ Y ์๋์ ๋ถ์ X์ ๋ชจ๋ ์ฌ๋"์ ๋๋ค:
WITH RECURSIVE subtree AS (
SELECT id, department_id
FROM employees
WHERE id = $1
UNION ALL
SELECT e.id, e.department_id
FROM employees e
JOIN subtree s ON e.manager_id = s.id
)
SELECT e.*
FROM employees e
JOIN subtree s ON s.id = e.id
WHERE e.department_id = $2;
์ธ์ ๋ฆฌ์คํธ ์ฟผ๋ฆฌ๋ ๊ถํ ๊ฒ์ฌ์์ ์ํํด์ง ์ ์์ต๋๋ค. ์ ๊ทผ ์ฒดํฌ๋ ์ข ์ข ์ ์ฒด ๊ฒฝ๋ก(๋ทฐ์ด๊ฐ ์ด ์ฌ๋์ ์ ์กฐ์ธ๊ฐ?)์ ์์กดํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๋ค ์๋ํฌ์ธํธ๊ฐ ์ฌ๊ท๋ฅผ ๋นผ๋จน๊ฑฐ๋ ํํฐ๋ฅผ ์๋ชป ์ ์ฉํ๋ฉด ํ์ด ๋ ธ์ถ๋ ์ ์์ต๋๋ค. ๋ํ ์ฌ์ดํด์ด๋ ๋๋ฝ๋ ๋งค๋์ ๊ฐ์ ๋ฐ์ดํฐ ๋ฌธ์ ๋ฅผ ์ฃผ์ํ์ธ์. ํ ๊ฑด์ ์๋ชป๋ ๋ ์ฝ๋๊ฐ ์ฌ๊ท๋ฅผ ๋ง์น๊ฑฐ๋ ๋๋ผ์ด ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์์ผ๋ฏ๋ก ๊ถํ ์ฟผ๋ฆฌ์๋ ์์ ์ฅ์น์ ์ข์ ์ ์ฝ์กฐ๊ฑด์ด ํ์ํฉ๋๋ค.
ํด๋ก์ ํ ์ด๋ธ: ์ ์ฒด ๊ณ์ธต์ ์ ์ฅํ๋ ๋ฐฉ๋ฒ
ํด๋ก์ ํ ์ด๋ธ์ ์ง์ ๋งค๋์ ๋งํฌ๋ฟ ์๋๋ผ ๋ชจ๋ ์ ์กฐ-ํ์ ๊ด๊ณ๋ฅผ ์ ์ฅํฉ๋๋ค. ํธ๋ฆฌ๋ฅผ ํ ๋จ๊ณ์ฉ ๊ฑท๋ ๋์ "์ด ๋ฆฌ๋ ์๋์ ๋๊ฐ ์๋๊ฐ?"๋ฅผ ํ ๋ฒ์ ์กฐ์ธ์ผ๋ก ๋ฐ๋ก ๋ฌผ์ด๋ณผ ์ ์์ต๋๋ค.
๋ณดํต ๋ ธ๋(์ฌ๋ ๋๋ ํ) ํ ์ด๋ธ ํ๋์ ๊ฒฝ๋ก๋ฅผ ์ ์ฅํ๋ ํด๋ก์ ํ ์ด๋ธ ํ๋๋ฅผ ๋ก๋๋ค.
-- nodes
employees (
id bigserial primary key,
name text not null,
manager_id bigint null references employees(id)
)
-- closure
employee_closure (
ancestor_id bigint not null references employees(id),
descendant_id bigint not null references employees(id),
depth int not null,
primary key (ancestor_id, descendant_id)
)
ํด๋ก์ ํ
์ด๋ธ์ (Alice, Bob)์ฒ๋ผ "Alice๊ฐ Bob์ ์ ์กฐ๋ค"๋ฅผ ๋ํ๋ด๋ ์์ ์ ์ฅํฉ๋๋ค. ๋ํ ancestor_id = descendant_id์ธ depth = 0 ํ๋ ์ ์ฅํฉ๋๋ค. ์ฒ์ ๋ณด๋ฉด ์ด์ํ์ง๋ง ๋ง์ ์ฟผ๋ฆฌ๋ฅผ ๋ ๊น๋ํ๊ฒ ๋ง๋ญ๋๋ค.
depth๋ ๋ ๋
ธ๋ ๊ฐ ๊ฑฐ๋ฆฌ๋ฅผ ์๋ ค์ค๋๋ค: depth = 1์ ์ง์ ๋งค๋์ , depth = 2๋ ๋งค๋์ ์ ๋งค๋์ ๋ฑ์
๋๋ค. ์ง์๊ณผ ๊ฐ์ ๊ด๊ณ๋ฅผ ๊ตฌ๋ถํด์ผ ํ ๋ ์ค์ํฉ๋๋ค.
์ฃผ์ ์ด์ ์ ์์ธก ๊ฐ๋ฅํ๊ณ ๋น ๋ฅธ ์ฝ๊ธฐ์ ๋๋ค:
- ์ ์ฒด ์๋ธํธ๋ฆฌ ์กฐํ๊ฐ ๋น ๋ฆ ๋๋ค(๋๋ ํฐ ์๋์ ๋ชจ๋ ์ฌ๋).
- ๊ณ๋ณด ์กฐํ๊ฐ ๋จ์ํฉ๋๋ค(์ด๋ค ์ง์ ์์ ๋ชจ๋ ๋งค๋์ ).
depth๋ก ์ง์/๊ฐ์ ๊ด๊ณ๋ฅผ ๊ตฌ๋ถํ ์ ์์ต๋๋ค.
๋์ ์ ๋ฐ์ดํธ ์ ์ ์ง๋น์ฉ์ด ๋ญ๋๋ค. Bob์ด Alice์์ Dana๋ก ๋งค๋์ ๋ฅผ ๋ฐ๊พธ๋ฉด Bob๊ณผ Bob ์๋์ ๋ชจ๋ ์ฌ๋์ ๋ํ ํด๋ก์ ํ์ ์ฌ๊ณ์ฐํด์ผ ํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์ ๊ทผ์ ํด๋น ์๋ธํธ๋ฆฌ์ ๋ํ ์ด์ ์ ์กฐ ๊ฒฝ๋ก๋ฅผ ์ญ์ ํ ๋ค, Dana์ ์ ์กฐ๋ค๊ณผ Bob์ ์๋ธํธ๋ฆฌ์ ๋ชจ๋ ๋ ธ๋๋ฅผ ๊ฒฐํฉํด ์ ๊ฒฝ๋ก๋ฅผ ์ฝ์ ํ๋ ๊ฒ์ ๋๋ค.
ํด๋ก์ ํ ์ด๋ธ: ๋น ๋ฅธ ํํฐ๋ง์ ์ํ ์ผ๋ฐ ์ฟผ๋ฆฌ๋ค
ํด๋ก์ ํ
์ด๋ธ์ ๋ชจ๋ ์ ์กฐ-ํ์ ์์ ์ฌ์ ์ ์ ์ฅํฉ๋๋ค(๋ณดํต org_closure(ancestor_id, descendant_id, depth)). ๋ฐ๋ผ์ ๋๋ถ๋ถ์ ์กฐ์ง ํํฐ๊ฐ ๋จ์ผ ์กฐ์ธ์ผ๋ก ํด๊ฒฐ๋์ด ๋น ๋ฆ
๋๋ค.
๋ฆฌ๋ ์๋์ ๋ชจ๋ ์ฌ๋์ ๋์ดํ๋ ค๋ฉด ํ ๋ฒ๋ง ์กฐ์ธํ๊ณ depth๋ก ํํฐ๋งํ์ธ์:
-- Descendants (everyone in the subtree)
SELECT e.*
FROM employees e
JOIN org_closure c
ON c.descendant_id = e.id
WHERE c.ancestor_id = :manager_id
AND c.depth > 0;
-- Direct reports only
SELECT e.*
FROM employees e
JOIN org_closure c
ON c.descendant_id = e.id
WHERE c.ancestor_id = :manager_id
AND c.depth = 1;
๊ณ๋ณด(ํ ์ง์์ ๋ชจ๋ ์ ์กฐ)๋ฅผ ๋ณด๋ ค๋ฉด ์กฐ์ธ์ ๋ค์ง์ต๋๋ค:
SELECT m.*
FROM employees m
JOIN org_closure c
ON c.ancestor_id = m.id
WHERE c.descendant_id = :employee_id
AND c.depth > 0
ORDER BY c.depth;
ํํฐ๋ง์ ์์ธก ๊ฐ๋ฅํด์ง๋๋ค. ์: "๋ฆฌ๋ X ์๋์ ๋ชจ๋ ์ฌ๋ ์ค ๋ถ์ Y์๋ง ์ํ ์ฌ๋":
SELECT e.*
FROM employees e
JOIN org_closure c ON c.descendant_id = e.id
WHERE c.ancestor_id = :leader_id
AND e.department_id = :department_id;
๊ณ์ธต์ด ์ฌ์ ๊ณ์ฐ๋์ด ์๊ธฐ ๋๋ฌธ์ ์นด์ดํธ๋ ๊ฐ๋จํฉ๋๋ค(์ฌ๊ท ๋ถํ์). ์ด๋ ๋์๋ณด๋์ ๊ถํ ๋ฒ์ ํฉ๊ณ์ ๋์์ด ๋๋ฉฐ, ํ์ด์ง๋ค์ด์
๊ณผ ๊ฒ์์์๋ ORDER BY, LIMIT/OFFSET, ํํฐ๋ฅผ ํ์ ์งํฉ์ ๋ฐ๋ก ์ ์ฉํ ์ ์์ด ์ ๋์ํฉ๋๋ค.
๊ฐ ๋ชจ๋ธ์ด ๊ถํ๊ณผ ์ ๊ทผ ๊ฒ์ฌ์ ๋ฏธ์น๋ ์ํฅ
์ผ๋ฐ์ ์ธ ์กฐ์ง ๊ท์น์ ๋จ์ํฉ๋๋ค: ๋งค๋์ ๋ ์์ ์ ์๋์ ์๋ ๋ชจ๋ ๊ฒ์ ๋ณผ ์ ์๋ค(๋๋ก๋ ํธ์ง๊น์ง ๊ฐ๋ฅ). ์ด๋ ์คํค๋ง๋ฅผ ์ ํํ๋๋์ ๋ฐ๋ผ "๋๊ฐ ๋๊ตฌ ์๋์ ์๋๊ฐ"๋ฅผ ์์๋ด๋ ๋น์ฉ์ ์ผ๋ง๋ ์์ฃผ ์น๋ฌ์ผ ํ๋์ง๊ฐ ๋ฌ๋ผ์ง๋๋ค.
์ธ์ ๋ฆฌ์คํธ์ ๊ฒฝ์ฐ ๊ถํ ๊ฒ์ฌ๋ ๋ณดํต ์ฌ๊ท๊ฐ ํ์ํฉ๋๋ค. ์ฌ์ฉ์๊ฐ 200๋ช ์ ์ง์ ๋ชฉ๋ก ํ์ด์ง๋ฅผ ์ด๋ฉด ๋ณดํต ์ฌ๊ท CTE๋ก ํ์ ์งํฉ์ ๋ง๋ค๊ณ ๋์ ํ์ ๊ทธ ์งํฉ์ผ๋ก ํํฐ๋งํฉ๋๋ค.
ํด๋ก์ ํ ์ด๋ธ์ ์ฐ๋ฉด ๊ฐ์ ๊ท์น์ ๋จ์ํ ์กด์ฌ์ฑ ๊ฒ์ฌ๋ก ํ์ธํ ์ ์์ต๋๋ค: "ํ์ฌ ์ฌ์ฉ์๊ฐ ์ด ์ง์์ ์ ์กฐ์ธ๊ฐ?"์ด๋ฉด ํ์ฉํฉ๋๋ค.
-- Closure table permission check (conceptual)
SELECT 1
FROM org_closure c
WHERE c.ancestor_id = :viewer_id
AND c.descendant_id = :employee_id
LIMIT 1;
์ด ๋จ์ํจ์ ํ ์์ค ๋ณด์(RLS)์ ๋์ ํ ๋ ์ค์ํฉ๋๋ค. ๋ชจ๋ ์ฟผ๋ฆฌ์ ๊ท์น์ด ์๋์ผ๋ก ํฌํจ๋๋ฉด ์ธ์ ๋ฆฌ์คํธ๋ณด๋ค ์ ์ฑ ์ด ํ๋ํ๊ธฐ ์ฝ์ต๋๋ค.
๊ฐ์ฅ ์์ฃผ ๋ฌธ์ ๋ฅผ ์ผ์ผํค๋ ์ฃ์ง ์ผ์ด์ค๋ค:
- ์ ์ ๋ณด๊ณ (dotted-line): ํ ์ฌ๋์ด ๋ ๋ช ์ ๋งค๋์ ๋ฅผ ์ค์ง์ ์ผ๋ก ๊ฐ์ง ๋.
- ์ด์์คํดํธ์ ๋๋ฆฌ: ์ ๊ทผ์ด ๊ณ์ธต์ ๊ธฐ๋ฐํ์ง ์๋ ๊ฒฝ์ฐ, ๋ง๋ฃ ์๊ฐ์ ๊ฐ์ง ๋ช ์์ ๊ถํ์ ๋ณ๋๋ก ์ ์ฅํ์ธ์.
- ์์ ์ ๊ทผ: ์๊ฐ ์ ํ ๊ถํ์ ์กฐ์ง ๊ตฌ์กฐ์ ํฌํจ์ํค์ง ๋ง์ธ์.
- ๊ต์ฐจ ํ ํ๋ก์ ํธ: ๊ด๋ฆฌ ์ฒด์ธ ๋์ ํ๋ก์ ํธ ๋ฉค๋ฒ์ญ์ผ๋ก ์ ๊ทผ์ ๋ถ์ฌํ์ธ์.
AppMaster๋ก ๊ตฌ์ถํ๋ค๋ฉด, ํด๋ก์ ํ ์ด๋ธ์ ์๊ฐ์ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๊น๋ํ๊ฒ ๋งคํ๋๊ณ ์ ๊ทผ ๊ฒ์ฌ๊ฐ ์น/๋ชจ๋ฐ์ผ ์ฑ ์ ๋ฐ์ ๊ฑธ์ณ ๋จ์ํ๊ฒ ์ ์ง๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
ํธ๋ ์ด๋์คํ: ์๋, ๋ณต์ก์ฑ, ์ ์ง๋ณด์
๊ฐ์ฅ ํฐ ์ ํ์ ๋ฌด์์ ์ต์ ํํ ์ง์ ๋๋ค: ๋จ์ํ ์ฐ๊ธฐ์ ์์ ์คํค๋ง์ธ๊ฐ, ์๋๋ฉด "์ด ๋งค๋์ ์๋์ ๋๊ตฌ"๋ฅผ ๋น ๋ฅด๊ฒ ์ฝ๋ ๊ฒ์ธ๊ฐ.
์ธ์ ๋ฆฌ์คํธ๋ ํ ์ด๋ธ์ด ์๊ณ ์ ๋ฐ์ดํธ๊ฐ ์ฌ์ด ๋ฐ๋ฉด, ์ฝ๊ธฐ์์๋ ์ ์ฒด ์๋ธํธ๋ฆฌ๋ฅผ ์ํด ์ฌ๊ท๊ฐ ํ์ํฉ๋๋ค. ์กฐ์ง์ด ์๊ฑฐ๋ UI๊ฐ ๋ช ๋จ๊ณ๋ง ๋ก๋ํ๊ฑฐ๋ ๊ณ์ธต ๊ธฐ๋ฐ ํํฐ๊ฐ ๋๋ฌผ๋ฉด ๊ด์ฐฎ์ต๋๋ค.
ํด๋ก์ ํ ์ด๋ธ์ ๋ฐ๋๋ก ์ฝ๊ธฐ๊ฐ ๋น ๋ฆ ๋๋ค. ํ์ง๋ง ์ด๋์ด๋ ์ฌ์กฐ์ง ์ ๋ง์ ๊ด๊ณ ํ์ ์ฝ์ /์ญ์ ํด์ผ ํด์ ์ฐ๊ธฐ๊ฐ ๋ณต์กํด์ง๋๋ค.
์ค๋ฌด์์๋ ๋ณดํต ๋ค์๊ณผ ๊ฐ์ ํจํด์ผ๋ก ๋ณด์ ๋๋ค:
- ์ฝ๊ธฐ ์ฑ๋ฅ: ์ธ์ ๋ฆฌ์คํธ๋ ์ฌ๊ท๊ฐ ํ์ํ๊ณ , ํด๋ก์ ๋ ์ฃผ๋ก ์กฐ์ธ์ผ๋ก ์กฐ์ง์ด ์ปค์ ธ๋ ๋น ๋ฆ ๋๋ค.
- ์ฐ๊ธฐ ๋ณต์ก์ฑ: ์ธ์ ๋ฆฌ์คํธ๋ ํ
parent_id๋ง ์ ๋ฐ์ดํธํ๋ฉด ๋์ง๋ง, ํด๋ก์ ๋ ๋จ์ผ ์ด๋์ ๋ง์ ํ์ ์ ๋ฐ์ดํธํด์ผ ํฉ๋๋ค. - ๋ฐ์ดํฐ ํฌ๊ธฐ: ์ธ์ ๋ฆฌ์คํธ๋ ์ฌ๋/ํ ์์ ๋น๋กํด ์ฆ๊ฐํ์ง๋ง, ํด๋ก์ ๋ ๊ด๊ณ ์(์ต์ ์ ๊ฒฝ์ฐ ๊น์ ํธ๋ฆฌ์์๋ ๋๋ต N^2)์ ๊ทผ์ ํ ์ ์์ต๋๋ค.
์ธ๋ฑ์ฑ์ ๋ ๋ชจ๋ธ ๋ชจ๋์์ ์ค์ํ์ง๋ง ํ๊ฒ์ด ๋ค๋ฆ ๋๋ค:
- ์ธ์ ๋ฆฌ์คํธ: ๋ถ๋ชจ ํฌ์ธํฐ(
manager_id)์ ํ์ฑ ํ๋๊ทธ ๊ฐ์ ์์ฃผ ์ฐ๋ ํํฐ์ ์ธ๋ฑ์ค๋ฅผ ๊ฑธ์ด๋ผ. - ํด๋ก์ ํ
์ด๋ธ:
(ancestor_id, descendant_id)์ ์ผ๋ฐ ์กฐํ๋ฅผ ์ํdescendant_id์ธ๋ฑ์ค๋ฅผ ์ค๋นํ๋ผ.
๊ฐ๋จํ ๊ท์น: ๊ณ์ธต์ผ๋ก ํํฐ๋ง์ ๊ฑฐ์ ํ์ง ์๊ณ ๊ถํ ๊ฒ์ฌ๊ฐ "๋งค๋์ ๋ ์ง์ ๋ณด๊ณ ๋ง ๋ณธ๋ค" ์ ๋๋ผ๋ฉด ์ธ์ ๋ฆฌ์คํธ๋ก ์ถฉ๋ถํฉ๋๋ค. ๋ฐ๋๋ก "VP X ์๋์ ๋ชจ๋ ์ฌ๋" ๊ฐ์ ๋ฆฌํฌํธ๋ฅผ ์์ฃผ ๋๋ฆฌ๊ฑฐ๋, ๋ง์ ํ๋ฉด์์ ๊ณ์ธต ๊ธฐ๋ฐ ๊ถํ์ ๊ฐ์ ํด์ผ ํ๋ค๋ฉด ํด๋ก์ ํ ์ด๋ธ์ด ์ถ๊ฐ ์ ์ง๋น์ฉ์ ์ ๋นํํ ์ ์์ต๋๋ค.
๋จ๊ณ๋ณ: ์ธ์ ๋ฆฌ์คํธ์์ ํด๋ก์ ํ ์ด๋ธ๋ก ์ด๋ํ๊ธฐ
์ฒซ๋ ๋ถํฐ ๋ชจ๋ธ์ ํ๋๋ก ๊ณ ์งํ ํ์๋ ์์ต๋๋ค. ์์ ํ ๊ฒฝ๋ก๋ ๊ธฐ์กด ์ธ์ ๋ฆฌ์คํธ(manager_id ๋๋ parent_id)๋ฅผ ์ ์งํ๋ฉด์ ์์ ํด๋ก์ ํ
์ด๋ธ์ ์ถ๊ฐํ๊ณ , ์ ์ง์ ์ผ๋ก ์ฝ๊ธฐ๋ฅผ ์ฎ๊ธฐ๋ ๊ฒ์
๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์๋ก์ด ๊ณ์ธต์ด ์ค์ ์ฟผ๋ฆฌ์ ๊ถํ ๊ฒ์ฌ์์ ์ด๋ป๊ฒ ๋์ํ๋์ง ๊ฒ์ฆํ๋ฉด์ ์ํ์ ๋ฎ์ถ ์ ์์ต๋๋ค.
์์ ๋ฐฉ๋ฒ:
- ํด๋ก์ ํ
์ด๋ธ(
org_closure)๊ณผ ์ธ๋ฑ์ค๋ฅผ ์์ฑํ๋, ์ธ์ ๋ฆฌ์คํธ๋ฅผ ์ง์ค์ ์ถ์ฒ๋ก ์ ์งํ์ธ์. - ํ์ฌ ๋งค๋์ ๊ด๊ณ๋ก๋ถํฐ ํด๋ก์ ํ์ ๋ฐฑํํ์ธ์. ์๊ธฐ ์์ ์ ๋ํ ํ(depth 0)๋ ํฌํจํ์ธ์.
- ๋ช๋ช ๋งค๋์ ๋ฅผ ์ํ๋ก ๊ณจ๋ผ ๋ ๋ชจ๋ธ์ด ๊ฐ์ ํ์ ์งํฉ์ ๋ฐํํ๋์ง ๊ฒ์ฆํ์ธ์.
- ์ฝ๊ธฐ ๊ฒฝ๋ก๋ถํฐ ์ ํํ์ธ์: ๋ฆฌํฌํธ, ํํฐ, ๊ณ์ธต ๊ถํ ๊ฒ์ฌ๋ ๋จผ์ ํด๋ก์ ์์ ์ฝ๊ฒ ํ์ธ์.
- ๋ชจ๋ ์ฐ๊ธฐ์ ๋ํด ํด๋ก์ ๋ฅผ ์ ๋ฐ์ดํธํ๋๋ก ํ์ธ์. ์์ ๋๋ฉด ์ฌ๊ท ๊ธฐ๋ฐ ์ฟผ๋ฆฌ๋ฅผ ํ๊ธฐํ์ธ์.
๊ฒ์ฆ ์ ๊ถํ ๊ท์น์ ๊ฐ์ฅ ์์ฃผ ๊นจ๋ ์ผ์ด์ค(๋งค๋์ ๋ณ๊ฒฝ, ์ต์์ ๋ฆฌ๋, ๋งค๋์ ๊ฐ ์๋ ์ฌ์ฉ์)์ ์ง์คํ์ธ์.
AppMaster๋ก ๊ตฌ์ถํ๋ค๋ฉด ๊ธฐ์กด ์๋ํฌ์ธํธ๋ฅผ ๊ณ์ ์ด์ํ๋ฉด์ ํด๋ก์ ์์ ์ฝ๋ ์ ์๋ํฌ์ธํธ๋ฅผ ์ถ๊ฐํ ๋ค ๊ฒฐ๊ณผ๊ฐ ์ผ์นํ๋ฉด ์ ํํ๋ ์์ผ๋ก ์งํํ ์ ์์ต๋๋ค.
์กฐ์ง ํํฐ๋ง์ด๋ ๊ถํ์ ๋ง์น๋ ํํ ์ค์๋ค
์กฐ์ง ๊ธฐ๋ฅ์ ๋ง์น๋ ๊ฐ์ฅ ๋น ๋ฅธ ๋ฐฉ๋ฒ์ ๊ณ์ธต์ ์ผ๊ด์ฑ ์์ด ๋ง๋๋ ๊ฒ์ ๋๋ค. ํ๋ณ๋ก ๋ฐ์ดํฐ๊ฐ ๋ฉ์ฉกํด ๋ณด์ฌ๋ ์์ ์ค์๋ ์๋ชป๋ ํํฐ, ๋๋ฆฐ ํ์ด์ง, ๊ถํ ๋์ถ์ ๋ง๋ค ์ ์์ต๋๋ค.
๊ณ ์ ์ ์ธ ๋ฌธ์ ๋ ์ฌ์ดํด์ด ์๊ธฐ๋ ๊ฒฝ์ฐ์ ๋๋ค: A๊ฐ B๋ฅผ ๊ด๋ฆฌํ๋๋ฐ ๋์ค์ ๋๊ตฐ๊ฐ B์ ๋งค๋์ ๋ฅผ A๋ก ์ค์ ํ๋ ๊ฒฝ์ฐ(๋๋ 3~4๋ช ์ ํตํด ๊ธด ๋ฃจํ๊ฐ ์๊ธฐ๋ ๊ฒฝ์ฐ). ์ฌ๊ท ์ฟผ๋ฆฌ๋ ๋ฌดํํ ์คํ๋๊ฑฐ๋ ์ค๋ณต ํ์ ๋ฐํํ๊ฑฐ๋ ํ์์์๋ ์ ์์ต๋๋ค. ํด๋ก์ ํ ์ด๋ธ์์๋ ์ฌ์ดํด์ ์ ์กฐ/ํ์ ํ์ ์ค์ผ์ํฌ ์ ์์ต๋๋ค.
๋ ๋ค๋ฅธ ํํ ๋ฌธ์ ๋ ํด๋ก์ ๋๋ฆฌํํธ์ ๋๋ค: ๋๊ตฐ๊ฐ์ ๋งค๋์ ๋ฅผ ๋ฐ๊ฟจ๋๋ฐ ์ง์ ์ ์ธ ๊ด๊ณ๋ง ์ ๋ฐ์ดํธํ๊ณ ์๋ธํธ๋ฆฌ์ ๋ํ ํด๋ก์ ํ์ ์ฌ๊ณ์ฐํ์ง ์์ ๊ฒฝ์ฐ์ ๋๋ค. ๊ทธ๋ฌ๋ฉด "์ด VP ์๋์ ๋ชจ๋ ์ฌ๋" ๊ฐ์ ํํฐ๊ฐ ์ ๊ตฌ์กฐ์ ์ ๊ตฌ์กฐ๊ฐ ์์ธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค. ๊ฐ์ธ ํ๋กํ์ ์ฌ์ ํ ์ฌ๋ฐ๋ฅด๊ฒ ๋ณด์ด๊ธฐ ๋๋ฌธ์ ๋ฐ๊ฒฌํ๊ธฐ ์ด๋ ต์ต๋๋ค.
๋ถ์์ ๋ณด๊ณ ๋ผ์ธ์ ๋ช ํํ ๊ท์น ์์ด ์์ด๋๋ฉด ์กฐ์ง๋๊ฐ ๋ณต์กํด์ง๋๋ค. ๋ถ์๋ ๋ณดํต ํ์ ์ ๊ทธ๋ฃน์ธ ๋ฐ๋ฉด ๋ณด๊ณ ๋ผ์ธ์ ๋งค๋์ ๊ด๊ณ์ ๋๋ค. ๋์ ๊ฐ์ ํธ๋ฆฌ๋ก ์ทจ๊ธํ๋ฉด "๋ถ์ ์ด๋"์ด ์ ๊ทผ ๊ถํ์ ์๊ธฐ์น ์๊ฒ ๋ฐ๊พธ๋ ์ผ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
๊ถํ์ ์ง์ ๋งค๋์ ๋ง ๋ณด๋์ง๋ก๋ง ํ๋ณํ ๋ ๊ฐ์ฅ ์์ฃผ ์คํจํฉ๋๋ค. viewer is manager of employee๋ง ๊ฒ์ฌํ๋ฉด ์ ์ฒด ์ฒด์ธ์ ๋ณด์ง ๋ชปํด ๋ถ๋น ์ฐจ๋จ๋๊ฑฐ๋(์์ ๋งค๋์ ๊ฐ ์์ ์ ์กฐ์ง์ ๋ณด์ง ๋ชปํจ) ๊ณผ๋ํ ๊ณต์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค(์์ ์ง์ ๋งค๋์ ์ค์ ์ผ๋ก ์ ๊ทผ์ด ์๊น).
๋๋ฆฐ ๋ชฉ๋ก ํ์ด์ง๋ ๋ณดํต ๋งค ์์ฒญ๋ง๋ค ์ฌ๊ท ํํฐ๋ง์ ์คํํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํฉ๋๋ค(๋ฐ์ํธ์งํจ, ํฐ์ผ ๋ชฉ๋ก, ์ง์ ๊ฒ์ ๋ฑ). ๊ฐ์ ํํฐ๋ฅผ ์ฌ๋ฌ ๊ณณ์์ ์ฐ๋ฉด ๋ฏธ๋ฆฌ ๊ณ์ฐ๋ ๊ฒฝ๋ก(ํด๋ก์ )๋ ํ์ฉ๋ ์ง์ ID ์งํฉ ์บ์๋ฅผ ๋ง๋ จํ๋ ํธ์ด ๋ซ์ต๋๋ค.
๋ช ๊ฐ์ง ์ค๋ฌด์ ์์ ์ฅ์น:
- ๋งค๋์ ๋ณ๊ฒฝ์ ์ ์ฅํ๊ธฐ ์ ์ ์ฌ์ดํด์ ๋ง๋ ๊ฒ์ฆ์ ํ์ธ์.
- "๋ถ์"๊ฐ ๋ฌด์์ธ์ง ์ ์ํ๊ณ ๋ณด๊ณ ๋ผ์ธ๊ณผ ๋ถ๋ฆฌํ์ธ์.
- ํด๋ก์ ํ ์ด๋ธ์ ์ด๋ค๋ฉด ๋งค๋์ ๋ณ๊ฒฝ ์ ์๋ธํธ๋ฆฌ์ ํ์ ํ์ ์ฌ๊ตฌ์ถํ์ธ์.
- ๊ถํ ๊ท์น์ ์ง์ ๋งค๋์ ๋ง ๋ณด์ง ๋ง๊ณ ์ ์ฒด ์ฒด์ธ์ ๊ธฐ์ค์ผ๋ก ์์ฑํ์ธ์.
- ๋ชฉ๋ก ํ์ด์ง์์ ์ฌ์ฉ๋๋ ์กฐ์ง ๋ฒ์๋ ๋งค๋ฒ ์ฌ๊ทํ๋ ๋์ ์ฌ์ ๊ณ์ฐํ์ธ์.
AppMaster์์ ์ด๋๋ฏผ ํจ๋์ ๋ง๋ ๋ค๋ฉด change manager ์์
์ ๋ฏผ๊ฐํ ์ํฌํ๋ก๋ก ๋ค๋ฃจ์ธ์: ๊ฒ์ฆ์ ํ๊ณ ๊ด๋ จ ๊ณ์ธต ๋ฐ์ดํฐ๋ฅผ ์
๋ฐ์ดํธํ ๋ค์์์ผ ํํฐ์ ์ ๊ทผ์ ๋ฐ์๋๋๋ก ํ์ธ์.
์ถ์ ์ ๋น ๋ฅธ ์ ๊ฒ ๋ชฉ๋ก
์กฐ์ง๋๋ฅผ "์๋ฃ"๋ผ๊ณ ๋ถ๋ฅด๊ธฐ ์ ์ ๋๊ฐ ๋ฌด์์ ๋ณผ ์ ์๋์ง ํ์ดํ ์ธ์ด๋ก ์ค๋ช ํ ์ ์์ด์ผ ํฉ๋๋ค. ๋๊ตฐ๊ฐ "X๋ฅผ ๋๊ฐ ๋ณผ ์ ์์ผ๋ฉฐ ๊ทธ ์ด์ ๋ ๋ฌด์์ธ๊ฐ์?"๋ผ๊ณ ๋ฌผ์ผ๋ฉด, ํ๋์ ๊ท์น๊ณผ ํ๋์ ์ฟผ๋ฆฌ(๋๋ ๋ทฐ)๋ฅผ ๊ฐ๋ฆฌ์ผ ์ฆ๋ช ํ ์ ์์ด์ผ ํฉ๋๋ค.
์ฑ๋ฅ๋ ํ์ค์ ์ธ ์ ๊ฒ ํญ๋ชฉ์ ๋๋ค. ์ธ์ ๋ฆฌ์คํธ์์๋ "์ด ๋งค๋์ ์๋์ ๋ชจ๋ ์ฌ๋"์ด ์ฌ๊ท ์ฟผ๋ฆฌ๊ฐ ๋์ด ๊น์ด์ ์ธ๋ฑ์ฑ์ ๋ฐ๋ผ ์๋๊ฐ ๋ฌ๋ผ์ง๋๋ค. ํด๋ก์ ํ ์ด๋ธ์์๋ ์ฝ๊ธฐ๊ฐ ๋ณดํต ๋น ๋ฅด์ง๋ง ์ฐ๊ธฐ ๊ฒฝ๋ก๊ฐ ๋ชจ๋ ๋ณ๊ฒฝ ํ์ ํ ์ด๋ธ์ ์ ํํ ์ ์งํ๋ค๊ณ ๋ฏฟ์ด์ผ ํฉ๋๋ค.
๊ฐ๋จํ ์ถ์ ์ ์ฒดํฌ๋ฆฌ์คํธ:
- ํ ๋ช ์ ์ง์์ ๊ณจ๋ผ ๊ฐ์์ฑ์ ๋๊น์ง ์ถ์ ํ์ธ์: ์ด๋ค ๊ณ๋ณด๊ฐ ์ ๊ทผ์ ํ์ฉํ๊ณ ์ด๋ค ์ญํ ์ด ์ ๊ทผ์ ๊ฑฐ๋ถํ๋๊ฐ?
- ์์ ๊ท๋ชจ(์: 5๋จ๊ณ, 50,000๋ช )๋ฅผ ์ฌ์ฉํด ๋งค๋์ ์๋ธํธ๋ฆฌ ์ฟผ๋ฆฌ ๋ฒค์น๋งํฌ๋ฅผ ํ์ธ์.
- ์๋ชป๋ ์ฐ๊ธฐ๋ฅผ ๋ง์ผ์ธ์: ์ฌ์ดํด, ์๊ธฐ ๊ด๋ฆฌ, ๊ณ ์ ๋ ธ๋๋ฅผ ์ ์ฝ๊ณผ ํธ๋์ญ์ ์ผ๋ก ์ฐจ๋จํ์ธ์.
- ์ฌ์กฐ์ง ์์ ์ฑ ํ ์คํธ: ์ด๋, ๋ณํฉ, ๋งค๋์ ๋ณ๊ฒฝ, ์ค๊ฐ ์คํจ ์ ๋กค๋ฐฑ์ ๊ฒ์ฆํ์ธ์.
- ํ์ค์ ์ธ ์ญํ (HR, ๋งค๋์ , ํ ๋ฆฌ๋, ์ง์)์ ๋ํด ํ์ฉ/๊ฑฐ๋ถ ์ ๊ทผ์ ๋จ์ ํ๋ ๊ถํ ํ ์คํธ๋ฅผ ์ถ๊ฐํ์ธ์.
๊ฒ์ฆํ ์ค์ฉ์ ์๋๋ฆฌ์ค: ์ง์ ๋ด๋น์๋ ์ง์ ๋ ๋ถ์์ ์ง์๋ง ๋ณผ ์ ์๊ณ , ๋งค๋์ ๋ ์์ ์ ์ ์ฒด ์๋ธํธ๋ฆฌ๋ฅผ ๋ณผ ์ ์๋ค. PostgreSQL์์ ์กฐ์ง๋๋ฅผ ๋ชจ๋ธ๋งํ๊ณ ๋ ๊ท์น์ ํ ์คํธ๋ก ์ฆ๋ช ํ ์ ์์ผ๋ฉด ์ถ์์ ๊ฐ๊น์์ง๋๋ค.
AppMaster๋ก ๋ด๋ถ ๋๊ตฌ๋ฅผ ๋ง๋ ๋ค๋ฉด, ์ด ์ฒดํฌ๋ค์ ๋จ์ํ DB ์ฟผ๋ฆฌ๊ฐ ์๋๋ผ ์กฐ์ง ๋ชฉ๋ก๊ณผ ์ง์ ํ๋กํ์ ๋ฐํํ๋ ์๋ํฌ์ธํธ ์ฃผ์์ ์๋ํ๋ ํ ์คํธ๋ก ์ ์งํ์ธ์.
์์ ์๋๋ฆฌ์ค์ ๋ค์ ๋จ๊ณ
์๋ฅผ ๋ค์ด Sales, Support, Engineering ์ธ ๋ถ์๊ฐ ์๊ณ , ๊ฐ ๋ถ์์ ๋ ํ์ด ์์ผ๋ฉฐ ๊ฐ ํ๋ง๋ค ๋ฆฌ๋๊ฐ ์๋ค๊ณ ํฉ์๋ค. Sales ๋ฆฌ๋ A๋ ํ์ ๋ํ ํ ์ธ ์น์ธ์ ํ ์ ์๊ณ , Support ๋ฆฌ๋ B๋ ๋ถ์์ ๋ชจ๋ ํฐ์ผ์ ๋ณผ ์ ์์ผ๋ฉฐ, Engineering VP๋ Engineering ์๋ ๋ชจ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
๊ทธ๋ฐ ๋ค์ ์ฌ์กฐ์ง์ด ์ผ์ด๋ฉ๋๋ค: ํ Support ํ์ด Sales ์๋๋ก ์ฎ๊ฒจ์ง๊ณ , Sales ๋๋ ํฐ์ ๋ ํ ๋ฆฌ๋ ์ฌ์ด์ ์ ๋งค๋์ ๊ฐ ์ถ๊ฐ๋ฉ๋๋ค. ๋ค์ ๋ ๋๊ตฐ๊ฐ๊ฐ ์ ๊ทผ์ ์์ฒญํฉ๋๋ค: "Jamie(์์ ๋ถ์๊ฐ)๊ฐ Sales ๋ถ์์ ๋ชจ๋ ๊ณ ๊ฐ ๊ณ์ ์ ๋ณด๊ฒ ํด๋ฌ๋ผ, Engineering์ ์๋." ๋ผ๊ณ ์.
์ธ์ ๋ฆฌ์คํธ๋ก ๋ชจ๋ธ๋งํ๋ฉด ์คํค๋ง๋ ๋จ์ํ์ง๋ง ์ฑ์์ ์ฟผ๋ฆฌ์ ๊ถํ ๊ฒ์ฆ ์์ ์ด ๋ ๋ง์ด ํ์ํฉ๋๋ค. "Sales ์๋์ ๋ชจ๋ ์ฌ๋" ๊ฐ์ ํํฐ๋ ๋ณดํต ์ฌ๊ท๊ฐ ํ์ํฉ๋๋ค. ์น์ธ ๊ท์น(์: ์์ฒญ์ ์์ ๊ฐ์ฅ ๊ฐ๊น์ด ๋งค๋์ ๋ง ์น์ธ ๊ฐ๋ฅ)์ด ์ถ๊ฐ๋๋ฉด ์ฌ์กฐ์ง ํ์ ์ฃ์ง ์ผ์ด์ค๊ฐ ์ค์ํด์ง๋๋ค.
ํด๋ก์ ํ ์ด๋ธ์ ์ฐ๋ฉด ์ฌ์กฐ์ง ์ ๋ ๋ง์ ์ฐ๊ธฐ ์์ (์ ์กฐ/ํ์ ํ ์ ๋ฐ์ดํธ)์ด ํ์ํ์ง๋ง ์ฝ๊ธฐ๋ ๊ฐ๋จํด์ง๋๋ค. ํํฐ๋ง๊ณผ ๊ถํ์ ์ข ์ข ๋จ์ํ ์กฐ์ธ์ผ๋ก ํด๊ฒฐ๋ฉ๋๋ค: "์ด ์ฌ์ฉ์๊ฐ ๊ทธ ์ง์์ ์ ์กฐ์ธ๊ฐ?" ๋๋ "์ด ํ์ด ์ด ๋ถ์ ์๋ธํธ๋ฆฌ ์์ ์๋๊ฐ?" ๊ฐ์ ๋ฐฉ์์ ๋๋ค.
์ด ์ฐจ์ด๋ ํ๋ฉด ์ค๊ณ์ ๋ฐ๋ก ๋ํ๋ฉ๋๋ค: ๋ถ์ ๋ฒ์์ ์ฌ๋ ์ ํ๊ธฐ, ์์ฒญ์ ์์ ๊ฐ์ฅ ๊ฐ๊น์ด ๋งค๋์ ๋ก ์น์ธ ๋ผ์ฐํ , ๋ถ์ ๋์๋ณด๋์ฉ ๊ด๋ฆฌ์ ๋ทฐ, ํน์ ๋ ์ง์ ์ ์ ๊ทผ์ด ์์๋์ง ์ค๋ช ํ๋ ๊ฐ์ฌ ๋ก๊ทธ ๋ฑ์ด ๊ทธ๋ ์ต๋๋ค.
๋ค์ ๋จ๊ณ ์ ์:
- ๊ถํ ๊ท์น์ ํ์ดํ ์ธ์ด๋ก ์์ฑํ์ธ์(๋๊ฐ ๋ฌด์์ ๋ณด๊ณ ์ ๋ณผ ์ ์๋์ง).
- ๊ฐ์ฅ ํํ ๊ฒ์ฌ์ ๋ง๋ ๋ชจ๋ธ์ ์ ํํ์ธ์(๋น ๋ฅธ ์ฝ๊ธฐ vs ๋จ์ํ ์ฐ๊ธฐ).
- ์ฌ์กฐ์ง, ์ ๊ทผ ์์ฒญ, ์น์ธ ํ๋ฆ์ ๋๊น์ง ํ ์คํธํ ์ ์๋ ๋ด๋ถ ๊ด๋ฆฌ์ ๋๊ตฌ๋ฅผ ๋ง๋์ธ์.
๋ด๋ถ ์กฐ์ง ์ธ์ํ ๊ด๋ฆฌ์ ํจ๋๊ณผ ํฌํธ์ ๋น ๋ฅด๊ฒ ๋ง๋ค๊ณ ์ถ๋ค๋ฉด AppMaster (appmaster.io)์ด ์ค์ฉ์ ์ธ ์ ํ์ผ ์ ์์ต๋๋ค: PostgreSQL ๊ธฐ๋ฐ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ธ๋งํ๊ณ , ์๊ฐ์ ๋น์ฆ๋์ค ํ๋ก์ธ์ค๋ก ์น์ธ ๋ก์ง์ ๊ตฌํํ๋ฉฐ, ๊ฐ์ ๋ฐฑ์๋๋ก ์น๊ณผ ๋ค์ดํฐ๋ธ ์ฑ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
์์ฃผ ๋ฌป๋ ์ง๋ฌธ
์ธ์ ๋ฆฌ์คํธ๋ ์กฐ์ง์ด ์๊ณ ์ ๋ฐ์ดํธ๊ฐ ์ฆ์ผ๋ฉฐ ๋๋ถ๋ถ์ ํ๋ฉด์ด ์ง์ ๋ณด๊ณ ๋ ๋ช ๋จ๊ณ๋ง ํ์ํ ๋ ์ ํฉํฉ๋๋ค. ๋ฐ๋ฉด ํด๋ก์ ํ ์ด๋ธ์ โ์ด ๋ฆฌ๋ ์๋์ ๋ชจ๋ ์ฌ๋โ ๊ฐ์ ์กฐํ๊ฐ ๋น๋ฒํ๊ณ , ๋ถ์ ๋ฒ์ ํํฐ๋ ๊ณ์ธต ๊ธฐ๋ฐ ๊ถํ์ ์ฌ๋ฌ ํ๋ฉด์์ ์ผ๊ด๋๊ฒ ์ ์ฉํด์ผ ํ ๋ ์ ํฉํฉ๋๋ค. ์ฝ๊ธฐ๋ ๊ฐ๋จํ ์กฐ์ธ์ผ๋ก ๋น ๋ฅด๊ฒ ํด๊ฒฐ๋์ง๋ง ์ฐ๊ธฐ(์ฌ๋ฐฐ์น)๋ ๋ ๋ง์ ์์ ์ด ํ์ํฉ๋๋ค.
employees(manager_id)์ฒ๋ผ ์์ํ๊ณ , ์ง์ ๋ณด๊ณ ์๋ WHERE manager_id = ?๋ก ๊ฐ์ ธ์ค๋ ๊ฒ์ด ๊ฐ์ฅ ๊ฐ๋จํ ๋ฐฉ๋ฒ์
๋๋ค. ์ ์ฒด ๊ณ์ธต(์์/ํ์ ๋ชจ๋)์ด ํ์ํ ๊ธฐ๋ฅ์ด ์๊ธธ ๋๋ง ์ฌ๊ท ์ฟผ๋ฆฌ๋ฅผ ์ถ๊ฐํ์ธ์(์น์ธ, โ๋ด ์กฐ์งโ ํํฐ, ๊ฑด๋๋ฐ๊ธฐ ๋ ๋ฒจ ๋์๋ณด๋ ๋ฑ).
์ต์ํ manager_id <> id ๊ฐ์ ๊ฒ์ฌ๋ฅผ ํตํด ์๊ธฐ ์์ ์ ๊ด๋ฆฌ์๋ก ์ค์ ํ๋ ๊ฒ์ ๋ง์ผ์ธ์. ์
๋ฐ์ดํธ ์์๋ ์ ๋งค๋์ ๊ฐ ์ด๋ฏธ ํด๋น ์ง์์ ํ์ํธ๋ฆฌ์ ์ํด ์๋์ง(์ฆ ๊ณ๋ณด์ ์ด๋ฏธ ํ์์ธ์ง) ํ์ธํ๋ ๊ฒ์ฆ์ ์ถ๊ฐํด์ผ ํฉ๋๋ค. ์ค์ ๋ก๋ ๋งค๋์ ๋ณ๊ฒฝ์ ์ ์ฅํ๊ธฐ ์ ์ ancestry(์ ์กฐ ๊ด๊ณ)๋ฅผ ํ์ธํ๋ ๊ฒ์ด ๊ฐ์ฅ ์์ ํฉ๋๋ค.
๊ถ์ฅ๋๋ ๊ธฐ๋ณธ์ ๋ถ์๋ฅผ ํ์ ์ ๊ทธ๋ฃน์ผ๋ก ๋ณด๊ณ , ๋ณด๊ณ ๋ผ์ธ์ ๋ณ๋์ ๋งค๋์ ํธ๋ฆฌ๋ก ์ ์งํ๋ ๊ฒ์ ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด โ๋ถ์ ์ด๋โ์ด ๋๊ตฐ๊ฐ์ ๋ณด๊ณ ๋ผ์ธ์ ์๋์น ์๊ฒ ๋ฐ๊พธ์ง ์๊ณ , ๋ณด๊ณ ๋ผ์ธ์ด ๋ถ์ ๊ฒฝ๊ณ์ ์ผ์นํ์ง ์์ ๋๋ "Sales์ ๋ชจ๋ ์ฌ๋" ๊ฐ์ ํํฐ๊ฐ ๋ช ํํด์ง๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ์ง์ ๋ ์ฝ๋์ ๊ธฐ๋ณธ ๋ณด๊ณ ๋งค๋์ (primary manager)๋ฅผ ์ ์ฅํ๊ณ , ์ ์ ๋ณด๊ณ (dotted-line) ๊ด๊ณ๋ ๋ณ๋์ ํ ์ด๋ธ(์: secondary manager ๋งคํ์ด๋ ํ ๋ฆฌ๋ ๋งคํ)๋ก ํํํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๊ธฐ๋ณธ ๊ณ์ธต ์ฟผ๋ฆฌ๋ฅผ ๊นจ๋จ๋ฆฌ์ง ์์ผ๋ฉด์ ํ๋ก์ ํธ ์ ๊ทผ์ด๋ ์น์ธ ์์ ๊ฐ์ ํน๋ณ ๊ท์น์ ๊ตฌํํ ์ ์์ต๋๋ค.
์ด์ ์กฐ์ ๊ฒฝ๋ก(์ด๋ํ ์ง์์ ํ์ ํธ๋ฆฌ์ ํด๋นํ๋ ancestor ๊ฒฝ๋ก)๋ฅผ ์ญ์ ํ ๋ค, ์๋ก์ด ๋งค๋์ ์ ์กฐ์๋ค๊ณผ ํด๋น ์ง์์ ์๋ธํธ๋ฆฌ ๋
ธ๋๋ค์ ๊ฒฐํฉํด ์ ๊ฒฝ๋ก๋ฅผ ์ฝ์
ํ๊ณ depth๋ฅผ ์ฌ๊ณ์ฐํฉ๋๋ค. ์ด ์์
์ ํธ๋์ญ์
์ผ๋ก ๋ฌถ์ด ์ค๊ฐ์ ์คํจํ์ ๋ ์ ๋ฐ๋ง ์
๋ฐ์ดํธ๋๋ ์ผ์ ๋ง์์ผ ํฉ๋๋ค.
์ธ์ ๋ฆฌ์คํธ์ ๊ฒฝ์ฐ ๊ฑฐ์ ๋ชจ๋ ์กฐ์ง ์ฟผ๋ฆฌ๊ฐ manager_id์์ ์์ํ๋ฏ๋ก ํด๋น ์นผ๋ผ์ ์ธ๋ฑ์ค๋ฅผ ๊ฑธ์ด์ผ ํฉ๋๋ค. ํด๋ก์ ํ
์ด๋ธ์์๋ (ancestor_id, descendant_id)์ ๊ธฐ๋ณธ ํค ์ธ๋ฑ์ค์ descendant_id ๋จ๋
์ธ๋ฑ์ค๊ฐ ์ค์ํฉ๋๋ค. ํ์๋ โ์ด ํ์ ๋๊ฐ ๋ณผ ์ ์๋?โ ๊ฐ์ ์กด์ฌ์ฑ ๊ฒ์ฌ์ ๋์๋ฉ๋๋ค.
ํด๋ก์ ํ
์ด๋ธ์ ์ธ ๋ ํํ ํจํด์ EXISTS๋ฅผ ์ด์ฉํ ๊ฒ์ฌ์
๋๋ค: ๋ทฐ์ด๊ฐ ๋์ ์ง์์ ์ ์กฐ์ธ์ง ํ์ธํ๋ฉด ์ ๊ทผ์ ํ์ฉํฉ๋๋ค. ์ด ๋ฐฉ์์ ํ ์์ค ๋ณด์(RLS)๊ณผ ๊ฒฐํฉํ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ผ๊ด๋๊ฒ ๊ท์น์ ์ ์ฉํ๋ฏ๋ก API๋ง๋ค ์ฌ๊ท ๋ก์ง์ ์ค๋ณตํ ํ์๊ฐ ์์ต๋๋ค.
-- ํด๋ก์ ํ
์ด๋ธ ๊ถํ ๊ฒ์ฌ(๊ฐ๋
)
SELECT 1
FROM org_closure c
WHERE c.ancestor_id = :viewer_id
AND c.descendant_id = :employee_id
LIMIT 1;
๊ฐ์ฌ์ ์ฌ์กฐ์ง ์ด๋ ฅ์ ์ํด์๋ ํ์ฌ ๊ฐ์ ๋ฎ์ด์ฐ์ง ๋ง๊ณ ๋ณ๋ ํ ์ด๋ธ์ ๋ณ๊ฒฝ ์ด๋ ฅ์ ๋ ์ง์ ํจ๊ป ๊ธฐ๋กํ์ธ์. ์ด๋ ๊ฒ ํ๋ฉด ํน์ ๋ ์ง์ ๋๊ฐ ๋๊ตฌ์๊ฒ ๋ณด๊ณ ํ๋์ง๋ฅผ ์ ํํ ์กฐํํ ์ ์์ด ๋ฆฌํฌํธ์ ๊ฐ์ฌ๊ฐ ์ผ๊ด๋ฉ๋๋ค.
๊ธฐ์กด manager_id๋ฅผ ์ง์ค์ ์ถ์ฒ(source of truth)๋ก ์ ์งํ๊ณ , ๊ทธ ์์ ํด๋ก์ ํ
์ด๋ธ์ ๋ง๋ค์ด ์ ์ง์ ์ผ๋ก ์ ํํ์ธ์. ์ ์ฐจ๋ ๋ณดํต ๋ค์๊ณผ ๊ฐ์ต๋๋ค: ํด๋ก์ ํ
์ด๋ธ ์์ฑ ๋ฐ ์ธ๋ฑ์ค ์ถ๊ฐ โ ํ์ฌ ํธ๋ฆฌ๋ก ๋ฐฑํ(backfill) โ ์ํ ๋งค๋์ ๋ก ๊ฒฐ๊ณผ ๊ฒ์ฆ โ ์ฝ๊ธฐ ๊ฒฝ๋ก๋ฅผ ํด๋ก์ ๋ก ์ ํ โ ์ฐ๊ธฐ ์ ๋ ์ชฝ์ ๋ชจ๋ ์
๋ฐ์ดํธ โ ์ถฉ๋ถํ ๊ฒ์ฆ๋๋ฉด ์ฌ๊ท ๊ธฐ๋ฐ ์ฟผ๋ฆฌ ํ๊ธฐ.


