2024๋…„ 12์›” 12์ผยท6๋ถ„ ์ฝ๊ธฐ

PostgreSQL์—์„œ ์กฐ์ง๋„ ๋ชจ๋ธ๋ง: ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ vs ํด๋กœ์ €

์ธ์ ‘ ๋ฆฌ์ŠคํŠธ์™€ ํด๋กœ์ € ํ…Œ์ด๋ธ”์„ ๋น„๊ตํ•ด PostgreSQL์—์„œ ์กฐ์ง๋„๋ฅผ ๋ชจ๋ธ๋งํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ํ•„ํ„ฐ๋ง, ๋ฆฌํฌํŒ…, ๊ถŒํ•œ ๊ฒ€์‚ฌ ์˜ˆ์ œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

PostgreSQL์—์„œ ์กฐ์ง๋„ ๋ชจ๋ธ๋ง: ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ vs ํด๋กœ์ €

์กฐ์ง๋„์— ํ•„์š”ํ•œ ๊ฒƒ๋“ค

์กฐ์ง๋„๋Š” ๋ˆ„๊ฐ€ ๋ˆ„๊ตฌ์—๊ฒŒ ๋ณด๊ณ ํ•˜๋Š”์ง€, ํŒ€์ด ์–ด๋–ป๊ฒŒ ๋ถ€์„œ๋กœ ๋ฌถ์ด๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ์ง€๋„์ž…๋‹ˆ๋‹ค. 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์˜ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ๊ฒฐํ•ฉํ•ด ์ƒˆ ๊ฒฝ๋กœ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํด๋กœ์ € ํ…Œ์ด๋ธ”: ๋น ๋ฅธ ํ•„ํ„ฐ๋ง์„ ์œ„ํ•œ ์ผ๋ฐ˜ ์ฟผ๋ฆฌ๋“ค

์กฐ์ง๋„ API ์ƒ์„ฑ
ํ•ธ๋“œ์ฝ”๋”ฉ ์—†์ด ์กฐ์ง ๊ตฌ์กฐ๋ฅผ ํ”„๋กœ๋•์…˜์šฉ API๋กœ ๋ฐ”๊พธ์„ธ์š”.
๋ฐฑ์—”๋“œ ์ƒ์„ฑ

ํด๋กœ์ € ํ…Œ์ด๋ธ”์€ ๋ชจ๋“  ์„ ์กฐ-ํ›„์† ์Œ์„ ์‚ฌ์ „์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค(๋ณดํ†ต 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 ์•„๋ž˜์˜ ๋ชจ๋“  ์‚ฌ๋žŒ" ๊ฐ™์€ ํ•„ํ„ฐ๋Š” ๋ณดํ†ต ์žฌ๊ท€๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์Šน์ธ ๊ทœ์น™(์˜ˆ: ์š”์ฒญ์ž ์œ„์˜ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋งค๋‹ˆ์ €๋งŒ ์Šน์ธ ๊ฐ€๋Šฅ)์ด ์ถ”๊ฐ€๋˜๋ฉด ์žฌ์กฐ์ง ํ›„์— ์—ฃ์ง€ ์ผ€์ด์Šค๊ฐ€ ์ค‘์š”ํ•ด์ง‘๋‹ˆ๋‹ค.

ํด๋กœ์ € ํ…Œ์ด๋ธ”์„ ์“ฐ๋ฉด ์žฌ์กฐ์ง ์‹œ ๋” ๋งŽ์€ ์“ฐ๊ธฐ ์ž‘์—…(์„ ์กฐ/ํ›„์† ํ–‰ ์—…๋ฐ์ดํŠธ)์ด ํ•„์š”ํ•˜์ง€๋งŒ ์ฝ๊ธฐ๋Š” ๊ฐ„๋‹จํ•ด์ง‘๋‹ˆ๋‹ค. ํ•„ํ„ฐ๋ง๊ณผ ๊ถŒํ•œ์€ ์ข…์ข… ๋‹จ์ˆœํ•œ ์กฐ์ธ์œผ๋กœ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค: "์ด ์‚ฌ์šฉ์ž๊ฐ€ ๊ทธ ์ง์›์˜ ์„ ์กฐ์ธ๊ฐ€?" ๋˜๋Š” "์ด ํŒ€์ด ์ด ๋ถ€์„œ ์„œ๋ธŒํŠธ๋ฆฌ ์•ˆ์— ์žˆ๋Š”๊ฐ€?" ๊ฐ™์€ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

์ด ์ฐจ์ด๋Š” ํ™”๋ฉด ์„ค๊ณ„์— ๋ฐ”๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค: ๋ถ€์„œ ๋ฒ”์œ„์˜ ์‚ฌ๋žŒ ์„ ํƒ๊ธฐ, ์š”์ฒญ์ž ์œ„์˜ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋งค๋‹ˆ์ €๋กœ ์Šน์ธ ๋ผ์šฐํŒ…, ๋ถ€์„œ ๋Œ€์‹œ๋ณด๋“œ์šฉ ๊ด€๋ฆฌ์ž ๋ทฐ, ํŠน์ • ๋‚ ์งœ์— ์™œ ์ ‘๊ทผ์ด ์žˆ์—ˆ๋Š”์ง€ ์„ค๋ช…ํ•˜๋Š” ๊ฐ์‚ฌ ๋กœ๊ทธ ๋“ฑ์ด ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ๋‹จ๊ณ„ ์ œ์•ˆ:

  1. ๊ถŒํ•œ ๊ทœ์น™์„ ํ‰์ดํ•œ ์–ธ์–ด๋กœ ์ž‘์„ฑํ•˜์„ธ์š”(๋ˆ„๊ฐ€ ๋ฌด์—‡์„ ๋ณด๊ณ  ์™œ ๋ณผ ์ˆ˜ ์žˆ๋Š”์ง€).
  2. ๊ฐ€์žฅ ํ”ํ•œ ๊ฒ€์‚ฌ์— ๋งž๋Š” ๋ชจ๋ธ์„ ์„ ํƒํ•˜์„ธ์š”(๋น ๋ฅธ ์ฝ๊ธฐ vs ๋‹จ์ˆœํ•œ ์“ฐ๊ธฐ).
  3. ์žฌ์กฐ์ง, ์ ‘๊ทผ ์š”์ฒญ, ์Šน์ธ ํ๋ฆ„์„ ๋๊นŒ์ง€ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๋‚ด๋ถ€ ๊ด€๋ฆฌ์ž ๋„๊ตฌ๋ฅผ ๋งŒ๋“œ์„ธ์š”.

๋‚ด๋ถ€ ์กฐ์ง ์ธ์‹ํ˜• ๊ด€๋ฆฌ์ž ํŒจ๋„๊ณผ ํฌํ„ธ์„ ๋น ๋ฅด๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด AppMaster (appmaster.io)์ด ์‹ค์šฉ์ ์ธ ์„ ํƒ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: PostgreSQL ๊ธฐ๋ฐ˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋ธ๋งํ•˜๊ณ , ์‹œ๊ฐ์  ๋น„์ฆˆ๋‹ˆ์Šค ํ”„๋กœ์„ธ์Šค๋กœ ์Šน์ธ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๋ฉฐ, ๊ฐ™์€ ๋ฐฑ์—”๋“œ๋กœ ์›น๊ณผ ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธ

์–ธ์ œ ์กฐ์ง๋„์— ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋ฅผ ์“ฐ๊ณ  ์–ธ์ œ ํด๋กœ์ € ํ…Œ์ด๋ธ”์„ ์จ์•ผ ํ•˜๋‚˜์š”?

์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋Š” ์กฐ์ง์ด ์ž‘๊ณ  ์—…๋ฐ์ดํŠธ๊ฐ€ ์žฆ์œผ๋ฉฐ ๋Œ€๋ถ€๋ถ„์˜ ํ™”๋ฉด์ด ์ง์† ๋ณด๊ณ ๋‚˜ ๋ช‡ ๋‹จ๊ณ„๋งŒ ํ•„์š”ํ•  ๋•Œ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด ํด๋กœ์ € ํ…Œ์ด๋ธ”์€ โ€œ์ด ๋ฆฌ๋” ์•„๋ž˜์˜ ๋ชจ๋“  ์‚ฌ๋žŒโ€ ๊ฐ™์€ ์กฐํšŒ๊ฐ€ ๋นˆ๋ฒˆํ•˜๊ณ , ๋ถ€์„œ ๋ฒ”์œ„ ํ•„ํ„ฐ๋‚˜ ๊ณ„์ธต ๊ธฐ๋ฐ˜ ๊ถŒํ•œ์„ ์—ฌ๋Ÿฌ ํ™”๋ฉด์—์„œ ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉํ•ด์•ผ ํ•  ๋•Œ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ์ฝ๊ธฐ๋Š” ๊ฐ„๋‹จํ•œ ์กฐ์ธ์œผ๋กœ ๋น ๋ฅด๊ฒŒ ํ•ด๊ฒฐ๋˜์ง€๋งŒ ์“ฐ๊ธฐ(์žฌ๋ฐฐ์น˜)๋Š” ๋” ๋งŽ์€ ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

PostgreSQL์— "๋ˆ„๊ฐ€ ๋ˆ„๊ตฌ์—๊ฒŒ ๋ณด๊ณ ํ•˜๋Š”๊ฐ€"๋ฅผ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ธ๊ฐ€์š”?

employees(manager_id)์ฒ˜๋Ÿผ ์‹œ์ž‘ํ•˜๊ณ , ์ง์† ๋ณด๊ณ ์ž๋Š” WHERE manager_id = ?๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ „์ฒด ๊ณ„์ธต(์ƒ์œ„/ํ•˜์œ„ ๋ชจ๋‘)์ด ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์ด ์ƒ๊ธธ ๋•Œ๋งŒ ์žฌ๊ท€ ์ฟผ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”(์Šน์ธ, โ€œ๋‚ด ์กฐ์งโ€ ํ•„ํ„ฐ, ๊ฑด๋„ˆ๋›ฐ๊ธฐ ๋ ˆ๋ฒจ ๋Œ€์‹œ๋ณด๋“œ ๋“ฑ).

์‚ฌ์ดํด(์˜ˆ: A๊ฐ€ B๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  B๊ฐ€ A๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ)์„ ์–ด๋–ป๊ฒŒ ๋ฐฉ์ง€ํ•˜๋‚˜์š”?

์ตœ์†Œํ•œ 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) โ†’ ์ƒ˜ํ”Œ ๋งค๋‹ˆ์ €๋กœ ๊ฒฐ๊ณผ ๊ฒ€์ฆ โ†’ ์ฝ๊ธฐ ๊ฒฝ๋กœ๋ฅผ ํด๋กœ์ €๋กœ ์ „ํ™˜ โ†’ ์“ฐ๊ธฐ ์‹œ ๋‘ ์ชฝ์„ ๋ชจ๋‘ ์—…๋ฐ์ดํŠธ โ†’ ์ถฉ๋ถ„ํžˆ ๊ฒ€์ฆ๋˜๋ฉด ์žฌ๊ท€ ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ ํ๊ธฐ.

์‰ฌ์šด ์‹œ์ž‘
๋ฉ‹์ง„๋งŒ๋“ค๊ธฐ

๋ฌด๋ฃŒ ์š”๊ธˆ์ œ๋กœ AppMaster๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.
์ค€๋น„๊ฐ€ ๋˜๋ฉด ์ ์ ˆํ•œ ๊ตฌ๋…์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹œ์ž‘ํ•˜๋‹ค
PostgreSQL์—์„œ ์กฐ์ง๋„ ๋ชจ๋ธ๋ง: ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ vs ํด๋กœ์ € | AppMaster