IT_Tech_AI

주니어 때 트리 구조 모르고 만든 쿼리, 왜 10초씩 걸렸을까?

kanez 2025. 10. 14. 14:41
반응형

배열·트리·해시 테이블, 내가 3년간 실무에서 부딪히며 깨달은 것들

입사 3년 차, 데이터 구조를 몰라서 10초 쿼리를 짰던 흑역사부터 지금까지

 

데이터 구조의 중요성

주니어 개발자 시절, 나는 "데이터 구조? 그거 면접용 아니야?"라고 생각했다. 배열, 트리, 해시 테이블이 뭔지는 알았지만, 실무에서 왜 중요한지 몰랐다. 그러다가 직접 사고를 쳐봤다. 사용자가 100명일 때는 괜찮았던 쿼리가 1만 명이 되자 10초씩 걸렸고, 상사한테 불려가서 "왜 이렇게 짰어?"라는 질문에 대답하지 못했다. 그때 깨달았다. 데이터 구조는 교과서 지식이 아니라 생존 스킬이라는 걸.

프로그래밍 코드와 데이터 구조 이미지

입사 첫해, 배열 하나 못 써서 욕먹은 이야기

신입 때 받은 첫 과제가 "엑셀 데이터 5만 행을 읽어서 중복 제거하고 정렬하기"였다. 나는 자신만만하게 for문을 중첩해서 돌렸다. 결과는? 프로그램이 3분 동안 멈춰있었다. 선배가 내 코드를 보더니 한숨을 쉬었다.

"야, 넌 지금 50,000 × 50,000번 비교하고 있어. 25억 번이야. 배열 하나면 되는 걸..."

그 말을 듣고 배열로 인덱싱을 구현했더니, 실행 시간이 3분에서 0.2초로 줄었다. 이게 내가 처음으로 "아, 데이터 구조가 이래서 중요하구나"라고 체감한 순간이었다. 지금 생각하면 부끄럽지만, 그때 배운 교훈 덕분에 이후 3년간 비슷한 실수는 안 했다.

배열, 내가 실무에서 쓰는 진짜 이유

배열의 가장 큰 장점은 "인덱스만 알면 즉시 접근"이다. O(1) 시간 복잡도라는 말은 교과서적이고, 실전에서는 이렇게 설명하는 게 맞다: "주소만 알면 바로 찾는다."

  • 이미지 픽셀 처리: 사진 필터 앱 만들 때, 각 픽셀에 즉시 접근해야 한다. 배열 아니면 불가능.
  • 게임 타일맵: 2D 게임에서 맵[x][y]로 타일 정보 바로 가져오기. 속도가 생명.
  • 센서 데이터 수집: IoT 기기에서 1초마다 온도 측정값 저장. 배열이 제일 단순하고 빠름.

하지만 배열의 함정도 있다. 중간에 데이터를 넣거나 빼면 뒤의 모든 요소를 이동시켜야 한다. 내가 처음 사용자 목록 기능을 만들 때, 중간에 사용자 추가/삭제가 빈번하게 일어나는데도 배열을 고집했다가, 사용자가 1000명 넘어가자 앱이 버벅거렸다. 그때 연결 리스트로 바꿨고, 문제가 해결됐다.

배열과 데이터 구조를 표현하는 추상적 이미지

트리 구조 몰라서 쿼리가 10초 걸렸던 날

2년 차 때, 회사에서 "부서별 직원 검색" 기능을 만들었다. 나는 단순하게 생각했다. "그냥 전체 직원 리스트 가져와서 부서명으로 필터링하면 되지." 그래서 이렇게 짰다:

SELECT * FROM employees WHERE department LIKE '%영업%'

직원이 100명일 때는 괜찮았다. 그런데 회사가 성장해서 직원이 10,000명이 되자, 이 쿼리가 10초씩 걸렸다. 이유? 데이터베이스가 전체 테이블을 처음부터 끝까지 스캔하고 있었던 것. 선배 개발자가 알려준 해결책은 인덱스를 트리 구조로 만드는 것이었다.

💡 내가 배운 교훈: 데이터베이스의 인덱스는 내부적으로 B-트리라는 트리 구조를 쓴다. 10,000개 데이터를 순차 탐색하면 최악 10,000번 비교하지만, 트리는 약 13번(log₂10000 ≈ 13.3)이면 찾는다.

트리, 계층 구조가 필요할 때 꺼내 쓴다

트리는 "부모-자식" 관계가 명확할 때 진가를 발휘한다. 내가 실무에서 트리를 쓴 경우들:

  • 조직도 시스템: CEO → 임원 → 부서장 → 팀장 → 팀원. 이건 트리가 아니면 표현하기 어렵다.
  • 파일 탐색기: 폴더 안에 폴더, 그 안에 또 폴더. 윈도우 탐색기가 바로 트리 구조다.
  • 댓글 시스템: 대댓글, 대대댓글을 구현할 때 트리 구조를 썼다. 깊이 제한을 5단계로 뒀더니 관리가 편했다.

하지만 트리도 함정이 있다. 데이터를 순서대로 넣으면 한쪽으로 쏠린다. 예를 들어, 1, 2, 3, 4, 5 순서로 넣으면 트리가 일자로 늘어서서 사실상 연결 리스트가 된다. 검색 속도가 O(log n)에서 O(n)으로 떨어진다. 이 문제를 해결하려면 AVL 트리나 레드-블랙 트리 같은 "자가 균형 트리"를 써야 하는데, 직접 구현하기엔 너무 복잡해서 라이브러리를 쓰는 게 현실적이다.

해시 테이블, 내가 가장 자주 쓰는 데이터 구조

솔직히 말하면, 실무에서 내가 제일 많이 쓰는 건 해시 테이블이다. Python의 딕셔너리(dictionary), JavaScript의 객체(object), Java의 HashMap이 전부 해시 테이블이다. 왜? 키만 알면 값을 바로 찾기 때문이다.

로그인 세션 관리, 해시 없이는 불가능

웹사이트 로그인 기능을 만들 때, "세션 ID로 사용자 정보 찾기"를 해야 한다. 만약 배열로 관리한다면? 세션 ID가 "abc123"인 사용자를 찾으려면 배열 전체를 순회해야 한다. 사용자가 10,000명이면 최악의 경우 10,000번 비교. 하지만 해시 테이블이라면 단 한 번에 찾는다.

sessions = { "abc123": {"user_id": 1, "name": "홍길동"}, "def456": {"user_id": 2, "name": "김철수"} } # 해시 테이블 덕분에 즉시 찾음 user = sessions["abc123"] # O(1)

해시 충돌, 직접 겪어본 악몽

해시 테이블의 유일한 약점은 해시 충돌이다. 내가 직접 겪은 사례: 회사 내부 도구에서 사용자 ID를 해시 키로 쓰는데, 해시 함수를 잘못 설계해서 여러 사용자가 같은 해시 값을 가졌다. 결과? 특정 사용자의 데이터가 다른 사용자 데이터로 덮어씌워졌다. 이 버그 찾느라 이틀을 날렸다.

교훈: 해시 함수는 절대 직접 만들지 말고, 검증된 라이브러리를 쓰자. Python의 hash(), Java의 hashCode() 같은 내장 함수가 훨씬 안전하다.

내가 해시 테이블 쓰는 실전 사례들

  • API 응답 캐싱: 같은 API 요청이 반복되면, 해시 테이블에 저장해뒀다가 재사용. 서버 부하 90% 감소.
  • 중복 제거: 대량의 데이터에서 중복 값 찾기. 해시 테이블 써서 O(n) 시간에 해결.
  • 사용자 권한 체크: user_id를 키로, 권한 정보를 값으로 저장. 매 요청마다 DB 조회 대신 메모리에서 즉시 확인.

언제 뭘 써야 할까? 내 경험상 선택 기준

이론은 이론이고, 실무는 다르다. 내가 3년간 부딪히며 세운 선택 기준:

상황 선택 이유 (경험담)
크기가 고정되고 인덱스로 접근 배열 이미지 픽셀 처리할 때 배열 말고는 답이 없었음
부서-팀-직원 같은 계층 구조 트리 조직도 기능 만들 때 트리 안 쓰면 코드가 지옥
키로 값 찾기 (순서 무관) 해시 테이블 세션 관리, API 캐싱 등 실무의 90%가 이거
정렬된 상태로 검색 트리 DB 인덱스가 B-트리 쓰는 이유. 범위 검색에 강함
중간 삽입/삭제 빈번 연결 리스트 사용자 목록 기능에서 배열 고집했다가 망함

3년 차가 말하는 데이터 구조 공부법

책이나 강의로 이론만 공부하면 실무에서 못 쓴다. 내가 추천하는 방법:

  1. 작은 프로젝트 하나 정해서 직접 구현: "연락처 관리 프로그램" 같은 걸 만들어보면서 배열, 해시 테이블 직접 써보기
  2. 기존 코드의 성능 문제 찾기: 내 코드 중에서 느린 부분 찾아서 "왜 느릴까?" 분석. 대부분 데이터 구조 선택 실수다
  3. 알고리즘 문제 풀되, 목적을 명확히: LeetCode 같은 데서 문제 풀 때 "이 문제는 왜 이 자료구조를 쓸까?"에 집중
  4. 실무 코드 뜯어보기: 오픈소스 프로젝트(예: Django, Flask)의 코드를 읽으면서 "여기선 왜 딕셔너리를 썼을까?" 질문하기

나도 처음엔 "데이터 구조 공부해야 하나?"라고 회의적이었다. 하지만 직접 사고 치고, 코드 고치고, 성능 개선하면서 깨달았다. 데이터 구조는 선택이 아니라 필수라는 걸. 지금 이 글을 읽는 당신도, 나처럼 시행착오를 겪기 전에 미리 공부해두길 바란다.

자주 묻는 질문 (내가 실제로 받은 질문들)

Q1. 실무에서 정말로 데이터 구조가 중요한가요?

내 경험상 절대적으로 중요하다. 신입 때는 몰랐는데, 사용자가 늘어나고 데이터가 쌓이면 데이터 구조 잘못 선택한 게 티 난다. 내가 짠 쿼리가 10초 걸렸던 게 바로 트리 구조(인덱스)를 안 써서였다. 면접용 지식이 아니라 생존 스킬이다.

Q2. 배열이랑 리스트랑 뭐가 다른가요?

내가 신입 때 헷갈렸던 부분이다. 배열은 메모리에서 연속적으로 붙어있고, 리스트는 흩어져 있다. 배열은 arr[5] 하면 바로 찾지만, 크기 고정. 리스트는 크기 자유롭지만 5번째 찾으려면 1번부터 순회해야 함. Python의 list는 사실 동적 배열(크기 조절 가능한 배열)이라 좀 특수한 케이스다.

Q3. 해시 충돌을 완전히 방지할 수 있나요?

불가능하다. 내가 직접 해시 함수 만들어봤는데 충돌 안 나게 하려면 배열 크기를 엄청나게 크게 해야 한다. 메모리 낭비가 심함. 그래서 대부분은 충돌을 "해결"하는 방식(체이닝, 개방 주소법)을 쓴다. 중요한 건 좋은 해시 함수 쓰는 것. 직접 만들지 말고 검증된 라이브러리 쓰자.

Q4. 트리가 한쪽으로 쏠리면 어떻게 하나요?

AVL 트리나 레드-블랙 트리 같은 자가 균형 트리를 써야 한다. 근데 솔직히 직접 구현하기엔 너무 복잡해서, 나는 Python의 bisect 모듈이나 Java의 TreeMap 같은 라이브러리를 쓴다. 회사에서 "바퀴를 다시 발명하지 마라"는 말 자주 듣는데, 이게 딱 그런 케이스다.

Q5. 실무에서 가장 많이 쓰는 자료구조는?

내 경험상 해시 테이블이 압도적 1위다. Python 딕셔너리, JavaScript 객체가 전부 해시 테이블이고, 웹 개발에서 세션 관리, 캐싱, API 응답 저장 등 거의 모든 곳에 쓴다. 그다음이 배열(리스트), 세 번째가 트리 정도? 스택, 큐도 간혹 쓰긴 하는데 빈도는 낮다.

Q6. 공부는 어떻게 해야 하나요?

이론 → 코딩 문제 → 실전 프로젝트 순서를 추천한다. 나는 처음에 책만 읽었는데 실무에서 못 썼다. 그러다가 LeetCode에서 문제 풀면서 "아, 이럴 때 이걸 쓰는구나" 감이 왔고, 실제 프로젝트에 적용하면서 완전히 체화됐다. 특히 내 코드가 느릴 때 "왜 느릴까?" 분석하는 게 제일 큰 공부였다.

Q7. 언제부터 데이터 구조가 중요해지나요?

사용자가 100명 넘어가면 체감된다. 내가 만든 앱이 사용자 10명일 땐 for문 중첩해도 괜찮았는데, 100명 넘어가자 버벅거리기 시작했다. 1000명 넘어가면 데이터 구조 잘못 선택하면 서비스가 마비된다. 그래서 처음부터 제대로 공부해두는 게 나중에 코드 갈아엎는 것보다 훨씬 이득이다.

반응형