Odoo 안내서

Odoo 안내서

1. Odoo ERP의 구조적 이해

1.1 Odoo의 정의: 통합 비즈니스 애플리케이션 스위트

Odoo는 단일 소프트웨어 패키지가 아닌, 기업 운영에 필요한 모든 기능을 포괄하는 통합 비즈니스 애플리케이션 스위트(Suite)이다.1 이는 고객 관계 관리(CRM), 전사적 자원 관리(ERP), 회계, 재고 관리, 프로젝트 관리, 제조, 전자상거래 등 수백 개의 개별 비즈니스 애플리케이션으로 구성된 생태계를 의미한다.3 현재 전 세계적으로 700만 명 이상의 사용자를 확보하며, 그 영향력을 빠르게 확장하고 있는 글로벌 플랫폼이다.1

Odoo의 핵심 가치는 사용자 친화성과 완벽한 통합성에 있다. 직관적으로 설계된 사용자 인터페이스(UI)는 새로운 사용자가 시스템에 신속하게 적응할 수 있도록 지원하며, 일반적으로 2일 이내에 기본적인 사용법을 익힐 수 있도록 설계되었다.1 또한, 각 애플리케이션(이하 ‘앱’)은 독립적으로 작동하면서도 상호 간에 데이터를 원활하게 공유하도록 설계되어, 부서 간의 정보 단절을 해소하고 전사적인 업무 흐름을 유기적으로 연결한다. 예를 들어, CRM 앱에서 발생한 영업 기회는 판매(Sales) 앱을 통해 견적으로 전환되고, 회계(Accounting) 앱과 연동되어 송장 발행 및 재무 관리가 이루어지는 식이다.2

1.2 핵심 패러다임: 모듈성, 개방성, 통합성

Odoo를 다른 ERP 시스템과 구별하는 가장 중요한 특징은 모듈성, 개방성, 통합성이라는 세 가지 핵심 패러다임에 기반을 두고 있다는 점이다.

모듈성(Modularity)

Odoo의 아키텍처는 모듈성을 기반으로 한다. 기업은 10,000개가 넘는 방대한 앱과 커뮤니티 모듈 중에서 현재 비즈니스에 필요한 기능만을 선택적으로 도입할 수 있다.1 이는 불필요한 기능을 제거하여 시스템을 가볍고 효율적으로 유지할 수 있게 하며, 기업의 고유한 요구사항과 프로세스에 정확히 부합하는 맞춤형 시스템 구축을 가능하게 한다.5 각 모듈은 독립적으로 작동하지만, 필요에 따라 다른 모듈과 완벽하게 통합되어 시너지를 창출한다.5 이러한 모듈식 접근 방식은 전통적인 일체형(Monolithic) ERP 시스템과 근본적인 차이를 보인다. 일체형 ERP가 거대하고 복잡한 단일 시스템을 한 번에 도입해야 하는 반면, Odoo는 단계적이고 점진적인 도입이 가능하다. 이는 초기 도입 비용과 시간을 절감하고, 시스템 변경에 따른 운영 리스크를 최소화하며, 시장 변화에 민첩하게 대응할 수 있는 유연성을 제공한다. 결과적으로 이러한 아키텍처 원칙은 총소유비용(TCO) 절감과 비즈니스 민첩성 향상에 직접적으로 기여한다.

개방성(Openness)

Odoo는 오픈 소스 개발 모델을 채택하고 있다.1 이는 소스 코드가 공개되어 있어 누구나 자유롭게 사용, 수정, 배포할 수 있음을 의미한다. 개방성은 특정 벤더에 대한 기술적 종속성을 탈피하게 하고, 기업이 자체적으로 시스템을 통제하고 발전시킬 수 있는 자율성을 부여한다.4 또한, 전 세계 수많은 개발자와 커뮤니티가 코드 개선에 참여하므로, 폐쇄적으로 개발되는 독점 소프트웨어에 비해 높은 안정성과 신뢰성을 기대할 수 있다.6 이러한 개방성의 철학은 Odoo가 데이터 계층의 기반으로 PostgreSQL과 같은 강력한 오픈 소스 데이터베이스를 채택한 이유와도 일맥상통한다.

통합성(Integration)

Odoo의 모든 공식 앱은 하나의 플랫폼 위에서 완벽하게 통합되도록 설계되었다.7 이는 데이터가 여러 시스템에 분산되어 발생하는 중복 입력, 데이터 불일치 등의 문제를 근본적으로 해결한다. CRM, 판매, 구매, 재고, 회계 등 모든 비즈니스 프로세스가 단일 데이터베이스를 공유하며 유기적으로 연결된다.2 나아가 Odoo의 개방성은 제3자 소프트웨어와의 통합을 용이하게 한다. 기업 내 여러 부서에서 각기 다른 전문 소프트웨어를 사용하더라도, Odoo를 중심으로 각 시스템의 데이터를 연결하고 통합하여 전사적인 데이터 흐름을 일관되게 관리할 수 있다.1

1.3 Odoo 에디션 비교: Community vs. Enterprise

Odoo는 두 가지 주요 에디션으로 제공된다: Community와 Enterprise.1 두 에디션 간의 선택은 단순히 기능의 차이를 넘어, 인프라 관리, 기술 지원, 장기적인 유지보수 전략에까지 영향을 미치는 중요한 전략적 결정이다.

  • Community Edition: 완전한 오픈 소스 버전으로, 라이선스 비용 없이 무료로 사용할 수 있다.4 핵심적인 ERP 기능을 제공하며, 소스 코드에 직접 접근하여 자유롭게 커스터마이징할 수 있다. 하지만 고급 기능(예: 회계, Odoo Studio 등)의 일부가 제한되며, 공식적인 기술 지원이나 버전 업그레이드 서비스가 제공되지 않는다.1 따라서 Community 에디션을 사용하는 기업은 서버 구축, 데이터베이스 튜닝, 보안, 백업, 업그레이드 등 시스템 인프라에 대한 모든 책임을 직접 져야 한다. 이 안내서에서 다루는 깊이 있는 기술적 지식은 Community 에디션 사용자에게 특히 필수적이다.

  • Enterprise Edition: Community 에디션의 모든 기능을 포함하며, 추가적인 고급 앱, 전문적인 기술 지원, 인프라 관리 서비스(Odoo.sh, Odoo Online)를 유료 구독 모델로 제공한다.1 Enterprise 에디션 사용자는 Odoo.sh와 같은 PaaS(Platform-as-a-Service)를 통해 서버 및 데이터베이스 관리에 대한 부담을 상당 부분 덜 수 있다. 이는 소프트웨어 라이선스뿐만 아니라 인프라 관리 서비스까지 포함하는 개념으로, 기업이 비즈니스 로직에 더 집중할 수 있도록 지원한다.

아래 표는 두 에디션의 핵심적인 차이점을 요약한 것이다.

항목 (Item)Community EditionEnterprise Edition
라이선스 비용 (License Cost)무료 (LGPLv3)사용자당 월/연간 구독료
핵심 기능 접근성 (Core Feature Access)대부분의 핵심 기능 제공모든 기능 제공
고급 기능 (Advanced Features)제한적 (예: 회계, Studio, 모바일 UI 등)전체 기능 제공 (회계, 고급 제조, 현장 서비스 등)
호스팅 옵션 (Hosting Options)자체 서버(On-premise), 제3자 클라우드Odoo.sh (PaaS), Odoo Online (SaaS), 자체 서버
공식 지원 (Official Support)커뮤니티 포럼을 통한 비공식 지원Odoo 공식 기술 지원팀 제공
업그레이드 서비스 (Upgrade Service)수동으로 직접 수행Odoo에서 업그레이드 스크립트 및 플랫폼 지원 제공

2. Odoo 아키텍처 심층 분석

Odoo의 강력한 기능과 유연성은 잘 설계된 기술 아키텍처에 기반한다. 이 아키텍처는 현대적인 웹 애플리케이션의 표준인 3계층 아키텍처와 MVC(Model-View-Controller) 디자인 패턴을 결합하여 구현되었다. 이 구조를 이해하는 것은 Odoo를 효과적으로 개발하고 운영하기 위한 첫걸음이다.

2.1 3계층 아키텍처: 프레젠테이션, 애플리케이션, 데이터

Odoo는 시스템을 논리적, 물리적으로 분리된 세 개의 계층으로 구성하는 3계층 아키텍처(3-Tier Architecture)를 채택하고 있다.8 각 계층은 독립적인 인프라에서 실행될 수 있어 개발, 확장, 유지보수가 용이하다는 장점을 가진다.8

  • 프레젠테이션 계층 (Presentation Tier): 이 계층은 최종 사용자가 시스템과 직접 상호작용하는 사용자 인터페이스(UI)를 담당한다. Odoo에서는 웹 브라우저에서 실행되는 동적인 JavaScript 애플리케이션이 이 역할을 수행한다.9 사용자가 보는 화면, 입력 폼, 버튼 등 모든 시각적 요소가 이 계층에 속하며, HTML, CSS, JavaScript와 Odoo 고유의 템플릿 엔진인 QWeb, 그리고 최신 버전에서 도입된 OWL(Odoo Web Library) 프레임워크를 사용하여 개발된다.5

  • 애플리케이션 계층 (Application Tier): 시스템의 심장부로서, 모든 비즈니스 로직을 처리하는 계층이다. Odoo 서버가 이 계층에 해당하며, 주력 개발 언어인 Python으로 작성되었다.8 이 계층의 주요 역할은 프레젠테이션 계층으로부터 받은 사용자 요청을 해석하고, 비즈니스 규칙에 따라 데이터를 처리하며, 데이터 계층과의 통신을 관리하는 것이다. Odoo의 핵심 기능인 워크플로우 엔진, 접근 제어, 그리고 데이터베이스와의 상호작용을 추상화하는 ORM(Object-Relational Mapping) 엔진이 모두 이 계층에서 동작한다.11

  • 데이터 계층 (Data Tier): 애플리케이션에서 처리된 모든 데이터가 영구적으로 저장되고 관리되는 백엔드이다. Odoo는 이 데이터 계층을 위해 세계에서 가장 진보된 오픈 소스 관계형 데이터베이스인 PostgreSQL을 유일한 데이터베이스 시스템으로 사용한다.9 모든 비즈니스 데이터(고객, 제품, 주문, 회계 전표 등)와 시스템 설정 정보 대부분이 PostgreSQL 데이터베이스 내에 테이블 형태로 저장된다.9

이 3계층 아키텍처의 가장 중요한 원칙 중 하나는 계층 간의 엄격한 분리이다. 특히, 프레젠테이션 계층은 데이터 계층과 직접 통신할 수 없으며, 모든 요청은 반드시 애플리케이션 계층을 거쳐야 한다.8 이러한 제약은 시스템의 보안과 확장성에 지대한 영향을 미친다. 만약 프레젠테이션 계층이 데이터베이스에 직접 접근할 수 있다면, 애플리케이션 계층에 구현된 정교한 접근 권한 제어(Access Control)나 레코드 규칙(Record Rules)을 우회할 수 있는 심각한 보안 허점이 발생하게 된다. 또한, 각 계층이 독립적으로 확장될 수 있다는 점은 시스템의 확장성을 보장한다. 예를 들어, 데이터베이스의 부하가 높을 경우 데이터 계층의 PostgreSQL 서버만 증설하고, 비즈니스 로직 처리량이 부족할 경우 애플리케이션 계층의 Odoo 서버 워커(Worker) 수를 늘리는 등 병목 현상이 발생하는 지점을 특정하여 효율적으로 자원을 확장할 수 있다.

2.2 MVC(Model-View-Controller) 패턴의 적용

Odoo는 3계층 아키텍처의 논리적 구조 내에서 MVC 디자인 패턴을 적용하여 코드의 관심사를 분리한다.10 이는 데이터의 표현(View)과 비즈니스 로직(Controller), 그리고 데이터 자체(Model)를 분리하여 개발함으로써 코드의 재사용성과 유지보수성을 극대화하는 설계 방식이다.

  • Model: 데이터의 구조와 그 데이터를 다루는 비즈니스 로직을 정의한다. Odoo에서 모델은 두 가지 측면을 가진다. 첫째, 논리적 측면에서 모델은 models.Model을 상속하는 Python 클래스로 표현되며, 데이터의 필드(예: 고객 이름, 제품 가격), 관계, 제약 조건, 비즈니스 메서드 등을 정의한다.12 둘째, 물리적 측면에서 이 Python 클래스는 ORM에 의해 PostgreSQL 데이터베이스의 테이블로 매핑되어 실제 데이터를 저장한다.9

  • View: 모델의 데이터를 사용자에게 보여주는 방식을 정의한다. Odoo에서 뷰는 데이터 그 자체가 아니라, 데이터를 어떻게 렌더링할지에 대한 명세이며, 주로 XML 파일을 사용하여 선언적으로 정의된다.10 Odoo는 동일한 데이터 모델에 대해 다양한 형태의 뷰를 제공하는데, 단일 레코드를 상세히 보여주는 ‘폼(Form) 뷰’, 여러 레코드를 표 형태로 보여주는 ‘리스트(List/Tree) 뷰’, 카드를 드래그 앤 드롭하며 상태를 변경하는 ‘칸반(Kanban) 뷰’, 데이터를 시각화하는 ‘그래프(Graph) 뷰’ 등이 있다.12

  • Controller: 사용자의 입력을 받아 모델과 뷰 사이의 상호작용을 제어하는 역할을 한다. 웹 기반 시스템인 Odoo에서 컨트롤러는 주로 HTTP 요청을 처리하는 역할을 담당한다.12 사용자가 웹 페이지에서 버튼을 클릭하거나 데이터를 제출하면, 해당 요청은 특정 URL 경로에 매핑된 Python 컨트롤러 메서드로 전달된다. 이 메서드는 요청 데이터를 파싱하고, 필요한 비즈니스 로직을 수행하기 위해 모델의 메서드를 호출하며, 그 결과를 적절한 뷰를 통해 사용자에게 다시 렌더링하여 응답한다.10

Odoo의 아키텍처는 이처럼 이중적인 계층 구조를 가진다. 하나는 앞서 설명한 전통적인 웹 애플리케이션의 3계층 구조(프레젠테이션-애플리케이션-데이터)이고, 다른 하나는 Odoo의 기능을 구성하는 모듈식 애플리케이션 계층 구조(코어-앱-확장 모듈)이다.11 개발자는 이 두 가지 계층을 모두 고려해야 한다. 예를 들어, 새로운 기능을 추가하기 위해 커스텀 모듈(확장 모듈 계층)을 개발할 때, 새로운 데이터 구조를 위한 모델(애플리케이션/데이터 계층)을 정의하고, 이를 사용자에게 보여주기 위한 뷰(프레젠테이션 계층)를 생성하게 된다. 이러한 구조적 분리는 Odoo 코어 시스템을 변경하지 않고도 안전하게 기능을 확장할 수 있게 해주며, 향후 Odoo의 코어 버전이 업그레이드되더라도 커스텀 기능이 손상될 위험을 최소화하는 강력한 장점을 제공한다.

아래 표는 Odoo의 아키텍처 계층과 MVC 컴포넌트, 그리고 실제 기술 요소 간의 관계를 명확하게 매핑하여 보여준다.

아키텍처 계층 (Architectural Layer)MVC 컴포넌트 (MVC Component)Odoo 기술 요소 (Odoo Technology Element)역할 및 책임 (Role & Responsibility)
프레젠테이션 계층ViewXML 파일, QWeb/OWL 템플릿사용자 인터페이스 렌더링, 사용자 입력 수집
애플리케이션 계층ControllerPython 컨트롤러/메서드HTTP 요청 처리, 비즈니스 로직 실행, Model과 View 중재
애플리케이션 계층Model (Logic)Python 모델 클래스 (ORM)데이터 구조, 관계, 제약 조건 및 비즈니스 규칙 정의
데이터 계층Model (Storage)PostgreSQL 테이블/뷰영구 데이터 저장, 관리, 무결성 보장

2.3 서버-클라이언트 통신 및 ORM 엔진의 역할

Odoo 시스템에서 사용자와 데이터베이스 간의 상호작용은 클라이언트, Odoo 서버, 그리고 PostgreSQL 데이터베이스 서버 간의 정교한 통신 과정을 통해 이루어진다. 이 과정의 중심에는 Odoo 서버의 핵심 구성 요소인 ORM 엔진이 있다.

사용자가 웹 브라우저(클라이언트)에서 특정 작업을 수행하면(예: 새로운 고객 정보 저장), 이 요청은 JSON-RPC(Remote Procedure Call) 형식으로 Odoo 서버(애플리케이션 계층)에 전송된다.11 서버의 컨트롤러는 이 요청을 수신하여 해당 비즈니스 로직을 처리할 모델의 메서드를 호출한다.

이때, Odoo 서버가 직접 SQL 쿼리를 생성하여 데이터베이스와 통신하는 것이 아니라, ORM 엔진이라는 추상화 계층을 통해 상호작용한다.9 ORM 엔진은 개발자가 정의한 Python 모델 클래스를 기반으로 실제 데이터베이스 작업을 수행한다. 예를 들어, 개발자가 Python 코드로 customer.create({'name': 'NewCo'})와 같은 명령을 실행하면, ORM 엔진은 이를 해석하여 PostgreSQL이 이해할 수 있는 INSERT INTO res_partner (name) VALUES ('NewCo');와 같은 SQL 쿼리를 생성하고 실행한다.

이처럼 ORM 엔진은 개발자를 복잡하고 반복적인 SQL 작성으로부터 해방시키고, 데이터베이스 종류에 상관없이 일관된 방식으로 데이터를 다룰 수 있게 해준다. (물론 Odoo는 PostgreSQL만 지원한다.) 더 중요한 것은 ORM이 데이터 유효성 검사, 접근 권한 제어, 관계 무결성 유지 등 Odoo 프레임워크가 제공하는 다양한 서비스를 데이터베이스 작업에 자동으로 적용하는 역할을 한다는 점이다.9 따라서 ORM을 통하지 않고 데이터베이스에 직접 접근하는 것은 이러한 핵심적인 보호 장치를 우회하는 행위이므로, 특별한 경우를 제외하고는 지양해야 한다.

3. 데이터 계층의 기반: PostgreSQL

Odoo가 데이터 계층의 기술 스택으로 PostgreSQL을 선택한 것은 단순한 선호의 문제가 아니라, Odoo의 핵심 아키텍처와 기능적 요구사항에 깊이 뿌리내린 필연적인 결정이다. Odoo의 ORM은 PostgreSQL의 고유하고 진보된 기능들을 최대한 활용하도록 설계되었으며, 이로 인해 두 시스템은 매우 긴밀하게 결합되어 있다.

3.1 Odoo가 PostgreSQL을 사용하는 이유: 기술적 당위성 분석

Odoo는 공식적으로 MySQL, MS SQL Server 등 다른 데이터베이스 관리 시스템(DBMS)을 지원하지 않는다.15 그 이유는 Odoo의 ORM과 핵심 모듈들이 PostgreSQL의 특정 SQL 방언(dialect)과 고급 기능에 깊이 의존하고 있기 때문이다.16 만약 다른 데이터베이스를 사용하려면 ORM의 상당 부분을 재작성해야 하며, 이는 사실상 Odoo를 포크(fork)하는 것과 같은 막대한 노력을 요구한다.15 Odoo가 PostgreSQL을 고수하는 기술적 당위성은 다음과 같다.

  • 비용 효율성 및 라이선스 자유: PostgreSQL은 BSD 라이선스를 따르는 완전한 오픈 소스 소프트웨어로, 어떠한 라이선스 비용도 발생하지 않는다.17 이는 초기 도입 비용을 없애고 데이터 볼륨이 증가하더라도 추가적인 라이선스 부담이 없어, 기업의 총소유비용(TCO)을 획기적으로 절감시킨다.6

  • 검증된 신뢰성과 안정성: PostgreSQL은 1996년 이전의 POSTGRES 프로젝트에서 파생되어 20년 이상 활발하게 개발되어 온 매우 성숙한 프로젝트이다.15 이러한 오랜 역사는 데이터베이스의 안정성과 데이터 무결성에 대한 높은 신뢰를 보장하며, 이는 기업의 핵심 데이터를 다루는 ERP 시스템에 있어 가장 중요한 요건 중 하나이다.

  • 탁월한 확장성과 유연성: PostgreSQL의 가장 큰 특징 중 하나는 극도로 높은 확장성이다. 사용자는 내장된 데이터 타입 외에도 자신만의 데이터 타입, 함수, 연산자, 인덱스 타입 등을 직접 정의하여 사용할 수 있다.18 이는 PostgreSQL을 단순한 데이터 저장소를 넘어, 특정 도메인에 최적화된 기능을 구현할 수 있는 하나의 프로그래밍 플랫폼처럼 활용할 수 있게 한다. Odoo의 ORM은 이러한 확장성을 적극적으로 활용하여 풍부한 기능을 제공한다.

  • 강력한 커뮤니티 생태계: PostgreSQL은 전 세계 수많은 개발자와 전문가로 구성된 활발한 커뮤니티의 지원을 받는다.19 이는 지속적인 기능 개선과 신속한 보안 패치, 그리고 문제 발생 시 참고할 수 있는 풍부한 자료와 지원 채널을 의미한다.

3.2 PostgreSQL의 핵심 특징

PostgreSQL은 현대적인 애플리케이션이 요구하는 다양한 고급 기능들을 지원하며, 이러한 기능들은 Odoo가 안정적이고 성능이 뛰어난 ERP 플랫폼으로 작동하는 데 필수적인 기반을 제공한다.

  • 객체-관계형 데이터베이스 (ORDBMS): PostgreSQL은 순수한 관계형 데이터베이스(RDBMS)를 넘어, 객체 지향 개념을 데이터베이스 모델에 통합한 객체-관계형 데이터베이스(ORDBMS)이다.17 이는 테이블 상속(table inheritance)과 같은 고급 기능을 지원하는데, 이를 통해 부모 테이블의 구조를 자식 테이블이 그대로 물려받고 추가적인 컬럼을 정의할 수 있다.17 이 기능은 Odoo ORM의 상속(

_inherit) 메커니즘과 철학적으로, 그리고 기술적으로 직접 연결된다. Odoo에서 한 모델이 다른 모델을 상속하여 필드를 추가하거나 메서드를 변경하는 기능은 PostgreSQL의 이러한 ORDBMS 특성이 있기에 효율적으로 구현될 수 있다.

  • 다중 버전 동시성 제어 (MVCC, Multiversion Concurrency Control): ERP 시스템은 다수의 사용자가 동시에 데이터를 읽고 쓰는 작업이 빈번하게 발생하는 고도의 동시성 환경이다. 전통적인 잠금(locking) 방식의 데이터베이스에서는 긴 시간이 소요되는 보고서 조회(읽기 작업)가 새로운 주문 입력(쓰기 작업)을 차단하는 등의 성능 저하가 발생할 수 있다. PostgreSQL은 MVCC 아키텍처를 사용하여 이 문제를 해결한다.21 MVCC는 각 트랜잭션이 데이터베이스의 특정 시점 스냅샷을 바라보게 함으로써, 읽기 작업이 쓰기 작업을 막지 않고, 쓰기 작업 또한 읽기 작업을 막지 않도록 보장한다.21 이는 Odoo가 수많은 동시 사용자의 요청을 효율적으로 처리할 수 있는 근본적인 이유이다.

  • 완벽한 ACID 준수: PostgreSQL은 데이터베이스 트랜잭션의 4대 원칙인 원자성(Atomicity), 일관성(Consistency), 고립성(Isolation), 영구성(Durability), 즉 ACID를 완벽하게 준수한다.17 이는 어떠한 상황(예: 시스템 장애)에서도 데이터의 무결성이 보장됨을 의미하며, 재무 데이터와 같이 정확성이 생명인 정보를 다루는 ERP 시스템에는 타협할 수 없는 필수 요건이다.

  • 풍부한 데이터 유형 지원: PostgreSQL은 정수, 문자열, 날짜/시간과 같은 표준 데이터 타입 외에도, 현대 웹 애플리케이션에서 널리 사용되는 JSON 및 JSONB, XML, 배열(Array), 범위(Range), 네트워크 주소, 지리 공간 데이터(PostGIS 확장) 등 매우 폭넓은 데이터 유형을 내장하고 있다.19 특히, 인덱싱이 가능하고 효율적인 이진(binary) 형식의 JSONB 데이터 타입은 Odoo가 구조화되지 않은 데이터를 유연하게 저장하고 쿼리할 수 있는 강력한 기반을 제공한다.

3.3 Odoo 환경에 특화된 PostgreSQL의 주요 기능

PostgreSQL의 여러 기능 중에서도 특히 Odoo와 같은 대규모 비즈니스 애플리케이션 환경에서 그 가치가 더욱 빛나는 기능들이 있다.

  • 확장 기능 (Extensions): PostgreSQL은 CREATE EXTENSION 명령어를 통해 데이터베이스의 기능을 손쉽게 확장할 수 있는 아키텍처를 가지고 있다. Odoo 환경에서는 다음과 같은 확장 기능들이 유용하게 사용될 수 있다.

  • pgcrypto: 데이터베이스 컬럼 수준에서 데이터를 암호화하는 기능을 제공하여, 민감한 정보를 보호하는 데 사용된다.24

  • pg_trgm: Trigram 매칭을 통해 문자열 유사도를 측정하고, LIKEILIKE 쿼리의 성능을 획기적으로 개선하여 Odoo의 텍스트 검색 기능을 강화한다.25

  • Apache AGE: 그래프 데이터베이스 기능을 추가하여 복잡한 관계 데이터를 분석하는 데 활용될 수 있다.6

  • 지정 시간 복구 (PITR, Point-In-Time Recovery): PostgreSQL은 모든 데이터 변경 사항을 미리 쓰기 로그(WAL, Write-Ahead Log)에 순차적으로 기록한다.21 이 WAL 아카이브를 활용하면, 관리자의 실수나 애플리케이션 오류로 인해 데이터가 손상되었을 경우, 데이터베이스 전체를 장애 발생 직전의 특정 시점으로 정확하게 복원할 수 있다. 이는 기업의 비즈니스 연속성을 보장하는 매우 강력한 재해 복구 기능이다.

  • 테이블 파티셔닝 (Table Partitioning): 기업이 성장함에 따라 판매 주문(sale_order), 회계 전표(account_move)와 같은 특정 테이블의 데이터는 수백만, 수천만 건을 넘어 기하급수적으로 증가할 수 있다. 이렇게 거대해진 단일 테이블은 쿼리 성능 저하와 유지보수 작업의 어려움을 야기한다. PostgreSQL의 네이티브 파티셔닝 기능은 이러한 대용량 테이블을 날짜 범위나 특정 값(예: 회사 ID)을 기준으로 여러 개의 작은 하위 테이블(파티션)로 분할하는 기능이다.6 쿼리 실행 시, 쿼리 플래너는 조건에 맞는 파티션만 스캔하여 전체적인 조회 성능을 크게 향상시킨다. 이는 대규모 Odoo 구현 환경의 확장성을 유지하는 데 필수적인 기술이다.

4. Odoo ORM: Python과 PostgreSQL의 가교

Odoo 개발의 핵심에는 ORM(Object-Relational Mapping) 계층이 자리 잡고 있다. ORM은 개발자가 데이터베이스의 복잡한 내부 구조나 SQL 언어에 대해 깊이 알지 못하더라도, 익숙한 객체 지향 언어인 Python을 사용하여 데이터베이스와 상호작용할 수 있도록 해주는 강력한 추상화 도구이다. 이 계층은 Python 코드와 PostgreSQL 데이터베이스 사이의 정교한 가교 역할을 수행한다.

4.1 ORM의 개념과 Odoo에서의 역할

ORM은 이름 그대로 객체(Object)와 관계형(Relational) 데이터베이스를 매핑(Mapping)하는 기술이다.27 즉, Python의 클래스(Class)와 객체(Object)를 PostgreSQL의 테이블(Table)과 행(Row)에 자동으로 연결해준다.

Odoo에서 ORM의 역할은 다음과 같이 요약할 수 있다 28:

  • 생산성 향상: 개발자는 INSERT, UPDATE, DELETE와 같은 SQL 쿼리를 직접 작성하는 대신, create(), write(), unlink()와 같은 직관적인 Python 메서드를 사용하여 데이터베이스 작업을 수행할 수 있다. 이는 반복적인 코드 작성을 줄여 개발 속도를 크게 향상시킨다.27

  • 보안 강화: ORM은 모든 데이터베이스 요청을 매개변수화(parameterize)하여 처리하므로, 웹 애플리케이션의 가장 흔한 보안 취약점 중 하나인 SQL 인젝션(SQL Injection) 공격을 원천적으로 방지한다.27 사용자 입력을 SQL 쿼리의 일부로 직접 조합하지 않기 때문에 악의적인 코드가 실행될 가능성이 차단된다.

  • 데이터베이스 추상화: ORM은 데이터베이스의 세부 구현을 감추는 역할을 한다. 비록 Odoo는 PostgreSQL만 지원하지만, ORM을 사용함으로써 개발자는 PostgreSQL의 특정 SQL 문법에 얽매이지 않고 일관된 Python API를 통해 작업할 수 있다.

  • 자동화된 스키마 관리: 개발자가 Python으로 모델을 정의하면, Odoo의 ORM은 해당 정의를 바탕으로 필요한 데이터베이스 테이블, 컬럼, 인덱스, 제약 조건 등을 자동으로 생성하거나 변경한다.12 이는 데이터베이스 스키마와 애플리케이션 코드가 항상 동기화되도록 보장한다.

  • 비즈니스 로직 통합: Odoo의 ORM은 단순한 데이터 매핑을 넘어, 접근 권한 제어(ACL), 데이터 유효성 검사, 워크플로우 로직 등 Odoo 프레임워크의 핵심 서비스를 데이터베이스 작업과 통합하여 실행한다.9

4.2 모델과 테이블 매핑

Odoo에서 데이터 모델은 models.Model을 상속하는 Python 클래스를 통해 정의된다.30 이 Python 클래스가 어떻게 PostgreSQL 테이블과 연결되는지 이해하는 것은 Odoo 개발의 기본이다.

  • 모델 정의: 모든 Odoo 모델은 고유한 이름을 가지며, 이는 _name 클래스 속성을 통해 지정된다. 이 이름은 Odoo 시스템 전체에서 해당 모델을 식별하는 키로 사용된다.
from odoo import models, fields

class SaleOrder(models.Model):
_name = 'sale.order'
_description = 'Sales Order'

name = fields.Char(string='Order Reference', required=True)
partner_id = fields.Many2one('res.partner', string='Customer')
  • 테이블 이름 변환: ORM은 모델의 _name 속성값에 있는 점(.)을 밑줄(_)로 변환하여 PostgreSQL 테이블 이름을 자동으로 생성한다.32 따라서 위 예시에서

sale.order 모델은 PostgreSQL 데이터베이스 내에 sale_order라는 이름의 테이블과 매핑된다.

  • 필드와 컬럼 매핑: 모델 클래스에 정의된 각 필드(예: name, partner_id)는 sale_order 테이블의 컬럼(column)에 해당한다.31 Odoo는 필드의 타입(

Char, Many2one 등)에 따라 적절한 PostgreSQL 컬럼 타입(VARCHAR, INTEGER 등)을 결정하여 테이블을 생성한다.

이러한 자동 매핑 규칙 덕분에 개발자는 데이터베이스 스키마를 직접 관리할 필요 없이 Python 코드에만 집중하여 비즈니스 로직을 구현할 수 있다.

4.3 핵심 ORM 메서드 분석: CRUD와 실제 SQL 쿼리

ORM은 데이터 조작을 위한 기본적인 CRUD(Create, Read, Update, Delete) 연산을 직관적인 메서드로 제공한다. 이러한 고수준의 Python 메서드 호출이 내부적으로 어떻게 저수준의 SQL 쿼리로 변환되는지 이해하는 것은 성능 문제를 진단하고 최적화하는 데 매우 중요하다.

ORM 메서드 (ORM Method)설명 (Description)Python 코드 예시 (Example Python Code)생성되는 SQL (개념) (Generated SQL (Conceptual))
create()딕셔너리 형태의 값을 받아 새로운 레코드를 생성한다.self.env['res.partner'].create({'name': 'New Partner', 'is_company': True})INSERT INTO res_partner (name, is_company,...) VALUES ('New Partner', TRUE,...)
search()도메인(domain)이라는 조건식을 만족하는 레코드들의 ID를 검색한다.self.env['res.partner'].search()SELECT id FROM res_partner WHERE is_company = TRUE
write()특정 레코드의 필드 값을 딕셔너리 형태로 받아 업데이트한다.partner.write({'phone': '123-456-7890'})UPDATE res_partner SET phone = '123-456-7890' WHERE id =...
unlink()특정 레코드를 데이터베이스에서 영구적으로 삭제한다.partner.unlink()DELETE FROM res_partner WHERE id =...
search_read()search()read()를 결합한 메서드로, 조건에 맞는 레코드를 찾아 지정된 필드 값을 바로 반환하여 효율적이다.self.env['res.partner'].search_read([('country_id', '=', 1)], ['name', 'email'])SELECT name, email FROM res_partner WHERE country_id = 1

ORM이 제공하는 편리함과 보안성에도 불구하고, 때로는 그 추상화가 불완전할 수 있다. 대량의 데이터를 처리하거나 복잡한 보고서를 생성하는 경우, ORM이 생성하는 쿼리가 비효율적일 수 있다. 이러한 상황을 위해 Odoo는 ORM을 우회하여 직접 SQL 쿼리를 실행할 수 있는 통로를 제공한다 (self.env.cr.execute()).33 이는 ORM이 만능 해결책이 아니며, 숙련된 Odoo 개발자는 ORM의 편리함과 원시 SQL의 성능 사이에서 적절한 균형을 잡을 수 있는 판단력을 갖추어야 함을 시사한다.

4.4 관계형 필드 심층 탐구

기업 데이터는 본질적으로 서로 연결되어 있다. Odoo ORM은 이러한 데이터 간의 관계를 표현하기 위해 Many2one, One2many, Many2many라는 세 가지 핵심적인 관계형 필드를 제공한다. 이 필드들은 단순한 Python 속성이 아니라, 데이터베이스 정규화와 외래 키 제약 조건 같은 표준 관계형 데이터베이스 설계 원칙을 지능적으로 반영하고 구현하는 매핑 도구이다.

4.4.1 Many2one (다대일 관계)

  • 개념: ‘다(Many)’ 쪽의 여러 레코드가 ‘일(One)’ 쪽의 단일 레코드에 연결되는 관계를 정의한다. 가장 흔한 관계 유형으로, 예를 들어 여러 개의 판매 주문(sale.order)은 단 하나의 고객(res.partner)에게 속한다.35

  • 구현: Many2one 필드는 PostgreSQL 테이블에 INTEGER 타입의 컬럼을 생성한다. 이 컬럼에는 연결된 ‘일(One)’ 쪽 테이블의 기본 키(id) 값이 저장된다. 데이터베이스 용어로는 이것이 바로 외래 키(Foreign Key)이다.36 ORM은 이 외래 키 제약 조건을 자동으로 생성하여, 존재하지 않는 고객 ID를 판매 주문에 저장하려는 시도를 데이터베이스 수준에서 차단함으로써 데이터 무결성을 보장한다.

  • 코드 예시: sale.order 모델에 고객을 연결하는 Many2one 필드는 다음과 같이 정의한다. 관례적으로 필드명은 _id 접미사를 사용한다.35

class SaleOrder(models.Model):
_name = 'sale.order'
partner_id = fields.Many2one(
comodel_name='res.partner',
string='Customer',
required=True
)

이 정의는 sale_order 테이블에 partner_id라는 INTEGER 컬럼을 생성하고, 이 컬럼이 res_partner 테이블의 id 컬럼을 참조하도록 하는 외래 키 제약 조건을 설정한다.

4.4.2 One2many (일대다 관계)

  • 개념: Many2one 관계의 반대 방향을 표현한다. ‘일(One)’ 쪽의 단일 레코드가 ‘다(Many)’ 쪽의 여러 레코드에 연결되는 관계이다. 예를 들어, 한 명의 고객(res.partner)은 여러 개의 판매 주문(sale.order)을 가질 수 있다.35

  • 구현: One2many 필드는 데이터베이스에 실제 컬럼을 생성하지 않는 ‘가상(virtual)’ 관계이다.35 이 필드의 값은 실시간으로 쿼리를 통해 계산된다. 즉,

res.partner 모델의 sale_order_ids 필드에 접근하면, Odoo ORM은 sale_order 테이블에서 partner_id가 현재 고객의 id와 일치하는 모든 레코드를 검색하여 반환한다. 이러한 작동 방식 때문에 One2many 필드를 정의하기 위해서는 반드시 상대방 모델(‘다’ 쪽)에 자신을 가리키는 Many2one 필드가 존재해야만 한다.35

  • 코드 예시: res.partner 모델에서 해당 고객의 모든 판매 주문 목록을 나타내는 One2many 필드는 다음과 같이 정의한다.
class ResPartner(models.Model):
_inherit = 'res.partner'
sale_order_ids = fields.One2many(
comodel_name='sale.order',
inverse_name='partner_id',
string='Sales Orders'
)

여기서 comodel_name은 상대방 모델을, inverse_name은 상대방 모델에 정의된 Many2one 필드의 이름을 지정한다.

4.4.3 Many2many (다대다 관계)

  • 개념: 양쪽 모델의 레코드가 서로에게 여러 개씩 연결될 수 있는 복잡한 관계를 정의한다. 예를 들어, 하나의 블로그 게시물(blog.post)은 여러 개의 태그(blog.tag)를 가질 수 있고, 동시에 하나의 태그는 여러 게시물에 사용될 수 있다.

  • 구현: Many2many 관계는 관계형 데이터베이스 설계의 정석적인 방법을 따른다. 즉, 두 모델의 테이블을 직접 연결하는 것이 아니라, 두 테이블의 기본 키를 외래 키로 갖는 별도의 ’연결 테이블(Junction Table 또는 Relation Table)’을 생성하여 관계를 관리한다.40 이 연결 테이블은 일반적으로 두 개의 컬럼(예:

blog_post_id, blog_tag_id)으로 구성되며, 각 행은 특정 게시물과 특정 태그 간의 연결 하나를 의미한다.

  • 코드 예시: blog.post 모델에 태그를 연결하는 Many2many 필드는 다음과 같이 정의할 수 있다.
class BlogPost(models.Model):
_name = 'blog.post'
tag_ids = fields.Many2many(
comodel_name='blog.tag',
relation='blog_post_tag_rel',  # 연결 테이블 이름 (선택 사항)
column1='post_id',            # 연결 테이블에서 자신을 참조하는 컬럼명 (선택 사항)
column2='tag_id',             # 연결 테이블에서 상대를 참조하는 컬럼명 (선택 사항)
string='Tags'
)

relation, column1, column2 인자는 선택 사항이며, 지정하지 않을 경우 Odoo가 규칙에 따라 자동으로 이름을 생성한다 (예: blog_post_blog_tag_rel).42

이처럼 Odoo ORM의 관계형 필드는 데이터베이스 이론에 충실한 방식으로 구현되어 있으며, 개발자가 이러한 기본 원리를 이해할 때 ORM을 더욱 강력하고 효율적으로 활용할 수 있다.

5. Odoo 및 PostgreSQL 성능 최적화 전략

Odoo 시스템의 성능은 애플리케이션 서버의 효율성과 데이터베이스의 응답성에 직접적으로 좌우된다. 따라서 최적의 성능을 유지하기 위해서는 Odoo 서버와 PostgreSQL 데이터베이스를 하나의 통합된 시스템으로 보고, 양쪽 모두에 대한 종합적인 튜닝 전략을 수립해야 한다. 어느 한쪽의 설정만으로는 최적의 결과를 얻기 어렵고, 두 구성 요소 간의 자원 할당과 상호작용을 고려한 균형 잡힌 접근이 필수적이다.

5.1 Odoo 서버 튜닝: Worker 프로세스 및 메모리 설정

Odoo는 동시 다발적인 사용자 요청을 처리하기 위해 멀티프로세스(multiprocess) 아키텍처를 사용한다. ’워커(Worker)’라고 불리는 다수의 프로세스를 미리 실행시켜 놓고, 각 요청을 개별 워커에 할당하여 처리하는 방식이다. 이 워커의 수와 자원 제한을 적절하게 설정하는 것이 Odoo 서버 튜닝의 핵심이다.

  • 워커(Worker) 수 계산: 워커의 수는 서버의 하드웨어 사양, 특히 CPU 코어 수에 따라 결정하는 것이 일반적이다. 너무 적으면 CPU 자원을 충분히 활용하지 못하고, 너무 많으면 프로세스 간의 문맥 교환(context switching) 오버헤드로 인해 오히려 성능이 저하될 수 있다. 널리 알려진 경험적 공식은 다음과 같다.44
    \text{workers} = (\text{CPU 코어 수} \times 2) + 1
    예를 들어, 8코어 CPU를 가진 서버에서는 약 17개의 워커를 설정할 수 있다. 이 워커들은 주로 사용자 요청을 처리하는 HTTP 워커와 예약된 작업을 수행하는 Cron 워커로 나뉜다.46 부하가 높은 프로덕션 환경에서는 이 공식을 기준으로 하되, 실제 시스템의 부하 패턴을 모니터링하며 워커 수를 미세 조정해야 한다.

  • 메모리 및 시간 제한 설정: 각 워커는 독립적인 프로세스이므로, 특정 워커에서 발생하는 문제(예: 메모리 누수, 무한 루프)가 전체 시스템에 영향을 미치지 않도록 자원 제한을 설정하는 것이 매우 중요하다. odoo.conf 설정 파일에서 다음 파라미터를 조정한다.46

  • limit_memory_soft: 워커가 사용할 수 있는 가상 메모리의 ‘소프트’ 한계. 이 한계를 초과하면, 해당 워커는 현재 요청 처리를 마친 후 자동으로 재시작되어 메모리 누수를 방지한다.

  • limit_memory_hard: 가상 메모리의 ‘하드’ 한계. 이 한계를 초과하면 워커가 즉시 강제 종료된다. 일반적으로 limit_memory_soft보다 약간 높은 값으로 설정한다.

  • limit_time_cpu: 단일 요청이 소모할 수 있는 최대 CPU 시간(초). 비효율적인 코드나 무한 루프로 인해 서버 자원이 고갈되는 것을 방지한다.

  • limit_time_real: 단일 요청이 소요될 수 있는 실제 시간(wall-clock time). 데이터베이스 대기, 외부 API 호출 시간 등을 포함한다.

이러한 Odoo 서버의 튜닝은 PostgreSQL의 설정과 밀접한 관련이 있다. 예를 들어, Odoo 워커 수를 늘리면 더 많은 RAM과 데이터베이스 연결이 필요하게 된다. 이는 PostgreSQL의 shared_buffersmax_connections 설정에 직접적인 영향을 미친다. 만약 시스템의 총 RAM을 고려하지 않고 무작정 워커 수만 늘리면, Odoo 프로세스가 RAM을 과도하게 점유하여 정작 중요한 데이터베이스 캐시 공간이 부족해지는 현상이 발생할 수 있다. 이는 디스크 I/O를 증가시켜 시스템 전체의 성능 저하를 초래한다. 따라서 Odoo와 PostgreSQL의 자원 할당은 상호 보완적으로, 시스템 전체의 관점에서 조율되어야 한다.

5.2 PostgreSQL 성능 튜닝: 주요 파라미터 해설

PostgreSQL은 설치 시 매우 보수적인 기본 설정값을 가지고 있어, 프로덕션 환경에서는 반드시 Odoo 워크로드에 맞게 설정을 최적화해야 한다. 주요 튜닝 파라미터는 postgresql.conf 파일에서 수정할 수 있다.

파라미터 (Parameter)설명 (Description)권장 설정 가이드 (Recommended Setting Guide)영향 (Impact)
shared_buffersPostgreSQL이 데이터 페이지 캐싱을 위해 할당하는 공유 메모리 크기.Odoo와 DB가 동일 서버에 있을 경우 총 RAM의 20-25%, DB 전용 서버일 경우 25-40%.46값이 클수록 디스크 I/O가 줄어들어 읽기 성능이 향상되나, 너무 크면 OS 캐시와 경쟁하여 역효과 발생 가능.
effective_cache_sizeOS 파일 시스템 캐시를 포함하여 PostgreSQL 쿼리 플래너가 가정하는 총 사용 가능 캐시 크기.총 RAM의 50-75%.44쿼리 플래너가 인덱스 스캔과 같은 비용이 높은 계획을 더 적극적으로 선택하도록 유도하여 쿼리 계획을 최적화.
work_mem정렬(ORDER BY), 해시 조인, 비트맵 스캔 등 개별 쿼리 작업에 할당되는 메모리.서버 RAM과 동시 접속자 수를 고려하여 점진적으로 증가 (예: 16GB RAM 서버에서 32-64MB).46복잡한 정렬이나 조인이 포함된 쿼리가 임시 디스크 파일을 사용하지 않고 메모리 내에서 처리되도록 하여 성능 향상.
maintenance_work_memVACUUM, CREATE INDEX, ALTER TABLE 등 유지보수 작업에 사용되는 메모리.대용량 테이블 유지보수 작업을 위해 충분히 큰 값으로 설정 (예: 1GB 이상).48인덱스 생성이나 대규모 데이터 정리 작업 시간을 단축.
checkpoint_completion_target체크포인트 I/O 부하를 분산시키는 시간 비율.0.9 (90%).48체크포인트 발생 시 발생하는 급격한 I/O 부하를 완화하여 시스템 전반의 응답성을 안정적으로 유지.
random_page_cost쿼리 플래너가 랜덤 디스크 I/O의 비용을 계산할 때 사용하는 가중치.SSD/NVMe 환경에서는 1.1 ~ 1.5로 낮춤.46스토리지 성능을 정확히 반영하여 플래너가 순차 스캔보다 인덱스 스캔을 더 선호하도록 유도.

5.3 쿼리 성능 향상을 위한 인덱싱 전략

잘 설계된 인덱스(Index)는 대용량 테이블에서 특정 데이터를 찾는 속도를 극적으로 향상시키는 가장 효과적인 방법이다. 하지만 인덱스는 데이터를 추가하거나 수정할 때마다 함께 업데이트되어야 하므로, 쓰기 성능에는 약간의 부하를 준다. 따라서 무분별한 인덱스 생성은 피하고, 워크로드를 분석하여 전략적으로 생성해야 한다.49

  • 기본 인덱싱 원칙:

  • 외래 키(Foreign Keys): Many2one 필드에 해당하는 모든 컬럼에는 반드시 인덱스를 생성해야 한다. 이는 조인(JOIN) 성능에 결정적인 영향을 미친다.49

  • 자주 필터링되는 컬럼: WHERE 절에 자주 사용되는 컬럼(예: state, date_order)에 인덱스를 생성하면 검색 성능이 크게 향상된다. Odoo 모델 필드 정의 시 index=True 속성을 추가하면 간단하게 B-Tree 인덱스를 생성할 수 있다.25

  • 고급 인덱싱 전략:

  • 부분 인덱스(Partial Index): 테이블의 특정 부분집합에만 인덱스를 생성한다. 예를 들어, state = 'done'인 레코드만 자주 검색한다면, 해당 조건에 맞는 레코드에 대해서만 인덱스를 생성하여 인덱스의 크기를 줄이고 효율성을 높일 수 있다.49

  • 표현식 인덱스(Expression Index): 특정 함수나 표현식의 결과에 대해 인덱스를 생성한다. 예를 들어, 대소문자를 구분하지 않는 검색을 위해 LOWER(name)에 대한 인덱스를 생성할 수 있다.50

  • GIN/GiST 인덱스: 전문 검색(Full-text search)이나 JSONB, 배열 데이터 타입의 검색 성능을 높이는 데 사용되는 특수한 인덱스 타입이다.49

5.4 성능 병목 현상 식별

성능 최적화의 첫 단계는 병목 지점을 정확히 식별하는 것이다. Odoo와 PostgreSQL은 이를 위한 강력한 도구들을 제공한다.

  • Odoo 프로파일러(Profiler): Odoo 개발자 모드에서 활성화할 수 있는 내장 성능 분석 도구이다.51 특정 웹 요청이 처리되는 동안 실행된 모든 SQL 쿼리, 각 쿼리의 실행 시간, 그리고 Python 코드의 어느 부분에서 해당 쿼리가 호출되었는지를 상세하게 추적하여 보여준다.51 이를 통해 비효율적인 쿼리나 불필요한 반복 호출(N+1 문제)을 쉽게 찾아낼 수 있다.

  • EXPLAIN ANALYZE: PostgreSQL의 강력한 쿼리 분석 명령어이다. 최적화하려는 SQL 쿼리 앞에 이 명령어를 붙여 실행하면, PostgreSQL 쿼리 플래너가 해당 쿼리를 실행하기 위해 어떤 계획을 세웠고(예: 어떤 인덱스를 사용했는지, 어떤 조인 방식을 선택했는지), 각 단계에서 실제 얼마나 많은 시간과 비용이 소요되었는지를 상세히 보여준다.49 ‘Sequential Scan’(테이블 전체 스캔)이 예상치 않게 발생하거나, 특정 연산의 비용이 비정상적으로 높게 나타난다면 해당 부분이 최적화 대상이다.

  • ORM 코드 최적화: 성능 문제의 상당수는 하드웨어나 서버 설정이 아닌, 비효율적인 애플리케이션 코드에서 비롯된다.

  • N+1 쿼리 문제 해결: 가장 흔한 성능 저하 패턴 중 하나는 루프(loop) 안에서 각 레코드에 대해 개별적으로 쿼리를 실행하는 것이다. 예를 들어, 100개의 판매 주문을 가져와 각 주문의 고객 이름을 출력하기 위해 루프를 돌며 100번의 추가 쿼리를 실행하는 식이다. Odoo ORM의 prefetch 메커니즘은 이러한 문제를 해결하기 위해 관련 레코드를 미리 한 번의 쿼리로 가져와 캐시에 저장한다.51

  • 배치(Batch) 연산 활용: 여러 레코드를 한 번에 수정할 때는 루프를 돌며 각 레코드에 대해 write() 메서드를 호출하는 대신, 레코드셋(recordset) 전체에 대해 write()를 한 번만 호출해야 한다. 이는 여러 개의 UPDATE 문을 하나의 UPDATE 문으로 통합하여 데이터베이스 부하를 크게 줄여준다.45

  • 데이터베이스 내 연산 활용: Python으로 대량의 데이터를 가져와 집계(합계, 평균 등)하는 것은 매우 비효율적이다. 이러한 작업은 데이터베이스가 훨씬 더 잘 수행한다. Odoo ORM의 read_group() 메서드는 SQL의 GROUP BY 절을 사용하여 데이터베이스 수준에서 데이터를 집계한 후 결과만 가져오므로, 네트워크 트래픽과 애플리케이션 서버의 부하를 크게 줄일 수 있다.45

궁극적으로, 성능 최적화의 핵심 원리는 데이터 처리를 가능한 한 애플리케이션 계층(Python)에서 데이터 계층(PostgreSQL)으로 옮기는 것이다. 데이터베이스는 대규모 데이터 집합을 처리하는 데 특화된 시스템이므로, 이러한 원칙을 따르는 것이 가장 효과적인 최적화 전략이 된다.

6. 시스템 관리 및 운영 모범 사례

안정적이고 안전한 Odoo 시스템을 운영하기 위해서는 일회성의 구축 및 튜닝을 넘어, 지속적인 관리와 운영 절차를 수립하는 것이 필수적이다. 여기에는 정기적인 데이터 백업 및 복원, 체계적인 버전 업그레이드, 그리고 다층적인 보안 강화 조치가 포함된다.

6.1 데이터베이스 백업 및 복원

데이터는 기업의 가장 중요한 자산이며, 이를 보호하기 위한 백업 및 복원 전략은 재해 복구 계획의 핵심이다. Odoo 시스템의 백업은 데이터베이스와 파일스토어(filestore)라는 두 가지 핵심 구성 요소를 원자적 단위(atomic unit)로 취급해야 한다.

  • 백업 구성 요소:

  • 데이터베이스: PostgreSQL 데이터베이스는 고객, 제품, 주문, 회계 데이터 등 모든 정형 데이터를 포함한다.

  • 파일스토어(Filestore): 제품 이미지, 문서 첨부 파일, 보고서 등 비정형 데이터(바이너리 파일)가 저장되는 디렉토리이다.53 데이터베이스에는 이 파일들에 대한 참조만 저장된다.

데이터베이스만 백업하고 파일스토어를 백업하지 않으면, 복원 시 시스템은 정상적으로 작동하는 것처럼 보일 수 있지만 모든 이미지와 첨부 파일이 누락된 불완전한 상태가 된다. 따라서 이 둘은 항상 함께 백업하고 복원해야 한다.

  • 백업 방법:

  • Odoo 인터페이스를 통한 백업: Odoo의 데이터베이스 관리자 화면(http://<your_domain>/web/database/manager)에서 백업을 수행할 수 있다.54 이 방법은 데이터베이스 덤프(

dump.sql)와 파일스토어 전체를 하나의 .zip 압축 파일로 만들어주어 가장 간편하고 안전하다.53

  • 명령줄 도구를 이용한 수동 백업: 자동화된 스크립트나 대용량 데이터베이스 백업에는 PostgreSQL의 표준 명령줄 유틸리티가 더 적합하다.
  1. 데이터베이스 백업 (pg_dump): pg_dump 유틸리티를 사용하여 데이터베이스를 백업한다. 압축된 커스텀 포맷(-Fc)으로 백업하는 것이 용량과 유연성 면에서 권장된다.56
pg_dump -h localhost -U odoo_user -Fc -f database_backup.dump database_name
  1. 파일스토어 백업 (tar): 파일 시스템의 tar와 같은 명령어를 사용하여 파일스토어 디렉토리를 압축 백업한다.56 파일스토어의 경로는 odoo.conf 파일의 data_dir 설정에서 확인할 수 있다.
tar -czf filestore_backup.tar.gz /path/to/odoo/filestore/database_name
  • 복원 방법:

  • Odoo 인터페이스를 통한 복원: 데이터베이스 관리자 화면에서 ‘Restore Database’ 기능을 사용하여 .zip 백업 파일을 업로드하면 데이터베이스와 파일스토어가 한 번에 복원된다.53

  • 명령줄 도구를 이용한 수동 복원:

  1. 새 데이터베이스 생성: 복원을 위한 빈 데이터베이스를 먼저 생성한다.
createdb -U postgres -O odoo_user new_database_name
  1. 데이터베이스 복원 (pg_restore): pg_dump로 생성한 .dump 파일을 pg_restore 유틸리티를 사용하여 복원한다.53
pg_restore -h localhost -U odoo_user -d new_database_name database_backup.dump
  1. 파일스토어 복원 (tar): 백업한 파일스토어 압축 파일을 새로운 데이터베이스 이름의 디렉토리로 풀어준다.
tar -xzf filestore_backup.tar.gz -C /path/to/odoo/filestore/
mv /path/to/odoo/filestore/database_name /path/to/odoo/filestore/new_database_name

6.2 데이터 마이그레이션 및 Odoo 버전 업그레이드

기존 시스템에서 Odoo로 전환하거나, 구버전의 Odoo를 최신 버전으로 업그레이드하는 작업은 신중한 계획과 체계적인 절차를 요구하는 복잡한 프로젝트이다.

  • 데이터 마이그레이션 절차: 성공적인 데이터 마이그레이션은 단순히 데이터를 옮기는 것이 아니라, 데이터의 품질을 보장하고 새로운 시스템에 맞게 변환하는 과정이다. 이 과정은 일반적으로 추출(Extraction), 변환(Transformation), 로드(Loading)의 3단계(ETL)로 구성된다.59
  1. 사전 계획 및 데이터 감사: 마이그레이션할 데이터의 범위(고객, 제품, 재고, 재무 데이터 등)를 명확히 정의하고, 원본 데이터의 품질을 분석한다. 중복되거나 오래되어 불필요한 데이터, 오류가 있는 데이터를 식별하는 과정이 필수적이다.59

  2. 데이터 정제 및 매핑: 식별된 오류를 수정하고, 데이터 형식을 Odoo가 요구하는 표준에 맞게 변환한다(예: 날짜 형식, 전화번호 형식 통일). 이후 원본 시스템의 각 데이터 필드를 Odoo의 어떤 모델과 필드에 대응시킬지 상세한 매핑 문서를 작성한다.60

  3. 마이그레이션 실행 및 검증: Odoo의 CSV 가져오기 도구나 커스텀 스크립트, ETL 도구를 사용하여 데이터를 로드한다.60 로드 후에는 원본 데이터와 Odoo에 로드된 데이터가 정확히 일치하는지, 데이터 간의 관계(예: 주문과 고객의 연결)가 올바르게 유지되는지 철저히 검증해야 한다.

  • Odoo 버전 업그레이드 모범 사례: Odoo는 매년 새로운 버전을 출시하므로, 최신 기능과 보안 패치를 적용받기 위한 업그레이드 전략이 필요하다.
  1. 코드 동결 및 분석: 업그레이드 프로세스를 시작하기 전에 모든 커스텀 모듈 개발을 중단한다. 새로운 Odoo 버전의 릴리스 노트를 분석하여, 기존 커스텀 기능 중 표준 기능으로 대체 가능한 부분을 식별하고 제거하여 기술 부채를 줄인다.61

  2. 커스텀 모듈 호환성 확보: 새로운 Odoo 버전의 빈 데이터베이스에 커스텀 모듈을 하나씩 설치해보며, 변경된 API나 프레임워크 구조로 인해 발생하는 오류를 수정한다.61

  3. 데이터 마이그레이션 및 테스트: Odoo의 공식 업그레이드 플랫폼이나 수동 스크립트를 사용하여 기존 버전의 데이터베이스를 새 버전으로 마이그레이션한다. 마이그레이션된 테스트 데이터베이스에 수정된 커스텀 모듈을 설치하고, 모든 비즈니스 프로세스가 정상적으로 작동하는지 광범위하게 테스트한다.61

  4. 프로덕션 업그레이드: 충분한 테스트와 리허설을 거쳐 안정성이 확인되면, 계획된 다운타임 동안 실제 운영 데이터베이스를 업그레이드한다.

6.3 보안 강화: Odoo 접근 제어와 PostgreSQL 보안 설정

Odoo 시스템의 보안은 애플리케이션 계층과 데이터베이스 계층 모두에서 다층적으로 이루어져야 한다. Odoo의 정교한 접근 제어 기능은 PostgreSQL의 견고한 보안 설정이라는 기반 위에서만 완벽하게 작동할 수 있다. 만약 데이터베이스 계층이 침해당하면, 애플리케이션 수준의 모든 보안 장치는 무력화될 수 있다.

  • Odoo 애플리케이션 보안:

  • 접근 제어 목록 (ACL, Access Control Lists): Odoo 보안의 가장 기본적인 단위로, 사용자 그룹별로 특정 모델에 대한 읽기(read), 쓰기(write), 생성(create), 삭제(unlink) 권한을 부여하거나 제한한다.29 접근 권한은 누적 적용되므로, 사용자는 자신이 속한 모든 그룹의 권한을 합한 권한을 갖게 된다.29

  • 레코드 규칙 (Record Rules): ACL보다 더 세분화된 행 수준 보안(Row-Level Security)을 제공한다. 특정 도메인 규칙을 정의하여, 사용자가 접근 권한이 있는 모델 내에서도 특정 조건(예: ‘자신이 담당자인 레코드만’)을 만족하는 레코드에만 접근할 수 있도록 제한한다.29

  • 프레임워크 내장 보안: Odoo 프레임워크 자체는 ORM을 통해 SQL 인젝션을, QWeb 템플릿 엔진의 자동 이스케이핑(escaping) 기능을 통해 사이트 간 스크립팅(XSS) 공격을 방지하도록 설계되었다.62

  • PostgreSQL 데이터베이스 보안 (기반 강화):

  • 네트워크 접근 제어: PostgreSQL 서버가 외부 네트워크에 불필요하게 노출되지 않도록 postgresql.conf 파일의 listen_addresses 설정을 Odoo 서버의 IP 주소나 localhost로 제한해야 한다.24 더 나아가,

pg_hba.conf (Host-Based Authentication) 파일을 수정하여 특정 IP 주소에서 특정 사용자 및 데이터베이스로의 연결만 허용하도록 엄격하게 제어해야 한다.63

  • 강력한 인증: 모든 데이터베이스 사용자에 대해 추측하기 어려운 강력한 암호를 사용하고, 암호화 방식으로는 MD5보다 안전한 scram-sha-256을 사용하도록 설정해야 한다.24

  • 전송 계층 암호화 (SSL/TLS): Odoo 서버와 PostgreSQL 서버 간의 모든 네트워크 통신을 SSL/TLS로 암호화하여, 중간자 공격(man-in-the-middle attack)을 통해 데이터를 탈취하거나 변조하는 것을 방지해야 한다. odoo.conf 파일에서 db_sslmode 파라미터를 require 또는 verify-full로 설정하여 암호화된 연결을 강제할 수 있다.64

  • 최소 권한의 원칙 (Principle of Least Privilege): Odoo 애플리케이션이 데이터베이스에 연결할 때 사용하는 PostgreSQL 사용자는 절대로 슈퍼유저(superuser) 권한을 가져서는 안 된다.65 해당 사용자는 Odoo가 작동하는 데 필요한 최소한의 권한(테이블 생성, 데이터 CRUD 등)만을 가져야 한다. 이는 애플리케이션의 취약점을 통해 데이터베이스 접근 권한이 탈취되더라도 그 피해를 최소화하기 위한 필수적인 조치이다.24

결론적으로, Odoo 시스템의 관리와 운영은 기술적 깊이와 체계적인 절차를 요구하는 전문적인 영역이다. 데이터의 안전한 보관과 복구, 원활한 시스템 업그레이드, 그리고 겹겹이 쌓인 보안 장벽 구축은 기업이 Odoo를 통해 비즈니스 가치를 지속적으로 창출하기 위한 필수적인 전제 조건이다.

7. 참고 자료

  1. Odoo란 무엇인가? Odoo ERP 소프트웨어의 장단점, https://paraceltech.com/ko/odoo%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-odoo-erp-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4%EC%9D%98-%EC%9E%A5%EB%8B%A8%EC%A0%90/
  2. Odoo : 사용자 후기, 주요 기능, 가격 - 테크뷰, https://www.techview.best/software/608
  3. Architecture Firm - Odoo, https://www.odoo.com/industries/architecture-firm
  4. Odoo: Open Source ERP and CRM, https://www.odoo.com/
  5. Modular architecture in Odoo: How it works and why It’s key | Rootstack, https://rootstack.com/en/blog/modular-architecture-odoo-how-it-works-and-why-its-key-successful-implementation
  6. 기업 데이터 환경에 PostgreSQL이 최적인 이유, https://blog.skaiworldwide.com/516
  7. Odoo에서의 모듈 탐험: 효율적인 비즈니스 관리를 위한 다양한 응용, https://paraceltech.com/ko/odoo%EC%97%90%EC%84%9C%EC%9D%98-%EB%AA%A8%EB%93%88-%ED%83%90%ED%97%98-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EB%B9%84%EC%A6%88%EB%8B%88%EC%8A%A4-%EA%B4%80%EB%A6%AC%EB%A5%BC-%EC%9C%84%ED%95%9C/
  8. What Is Three-Tier Architecture? | IBM, https://www.ibm.com/think/topics/three-tier-architecture
  9. Architecture - OpenERP Server Developers Documentation - Read the Docs, https://odoo-docs.readthedocs.io/en/latest/02_architecture.html
  10. MVC Architecture of Odoo - Technaureus, https://www.technaureus.com/blog-detail/mvc-architecture-of-odoo
  11. Odoo - Modified web architecture of the HR toolkit - desosa 2021, https://2021.desosa.nl/projects/odoo/posts/essay_2/
  12. Odoo Architecture: A Deep Dive into MVC and Core Components | by Aymen FARHANI, https://medium.com/@aymenfarhani28/odoo-architecture-a-deep-dive-into-mvc-and-core-components-cde2ee3bde6d
  13. View architectures — Odoo 18.0 documentation, https://www.odoo.com/documentation/18.0/developer/reference/user_interface/view_architectures.html
  14. Odoo Studio가 제공하는 모든 멋진 기능을 확인하세요, https://www.odoo.com/ko_KR/app/studio-features
  15. Why Use PostgreSQL With Odoo? - Geminate Consultancy Services, https://www.geminatecs.com/blog/why-use-postgresql-with-odoo
  16. Replacement for OpenERP PostgreSQL database [closed] - Stack Overflow, https://stackoverflow.com/questions/21576709/replacement-for-openerp-postgresql-database
  17. [PostgreSQL] PostgreSQL의 특징과 장단점 - YSY의 데이터분석 블로그 - 티스토리, https://ysyblog.tistory.com/390
  18. [PostgreSQL] 포스트그레스큐엘(PostgreSQL)의 정의 및 특징 , 설치방법 - 미생 - 티스토리, https://hyunmin1906.tistory.com/220
  19. PostgreSQL의 장점과 단점 - 비트나인, https://bitnine.net/blog-postgresql/postgresql%EC%9D%98-%EC%9E%A5%EC%A0%90%EA%B3%BC-%EB%8B%A8%EC%A0%90/
  20. PostgreSQL 16.10 Documentation, https://www.postgresql.org/files/documentation/pdf/16/postgresql-16-A4.pdf
  21. PostgreSQL이란 무엇인가요? | IBM, https://www.ibm.com/kr-ko/think/topics/postgresql
  22. PostgreSQL이란? - Microsoft Azure, https://azure.microsoft.com/ko-kr/resources/cloud-computing-dictionary/what-is-postgresql
  23. PostgreSQL과 MySQL 비교 - 관계형 데이터베이스 관리 시스템(RDBMS) 간의 차이점 - AWS, https://aws.amazon.com/ko/compare/the-difference-between-mysql-vs-postgresql/
  24. How to Master PostgreSQL Security - Cybrosys Technologies, https://www.cybrosys.com/research-and-development/postgres/how-to-master-postgresql-security
  25. ORM API — Odoo 18.0 documentation, https://www.odoo.com/documentation/18.0/developer/reference/backend/orm.html
  26. Large Dataset Handling & Partitioning for Odoo - Cybrosys Technologies, https://www.cybrosys.com/postgres/large-dataset-handling/
  27. How ORM Methods Streamline Database Operations in Odoo 18 ? - CandidRoot Solutions, https://www.candidroot.com/blog/our-candidroot-blog-1/how-orm-methods-streamline-database-operations-in-odoo-18-744
  28. Mastering ORM Method in Odoo - DevIntelle Consulting, https://www.devintellecs.com/es/blog/odoo-technical-4/mastering-orm-methods-in-odoo-14
  29. Security in Odoo — Odoo 18.0 documentation, https://www.odoo.com/documentation/18.0/developer/reference/backend/security.html
  30. Chapter 3: Models And Basic Fields — Odoo 18.0 documentation, https://www.odoo.com/documentation/18.0/developer/tutorials/server_framework_101/03_basicmodel.html
  31. Building a Module — Odoo 18.0 documentation, https://www.odoo.com/documentation/18.0/developer/tutorials/backend.html
  32. List of Tables of Odoo in Postgres Database, https://www.odoo.com/forum/help-1/list-of-tables-of-odoo-in-postgres-database-218948
  33. 6# How to Execute SQL Queries in Odoo | by Muhammad Abdullah Arif - Medium, https://smuhabdullah.medium.com/how-to-execute-sql-queries-in-odoo-1a2e69317085
  34. Performance SQL Query versus ORM Search Method - Odoo, https://www.odoo.com/forum/help-1/performance-sql-query-versus-orm-search-method-210821
  35. Chapter 7: Relations Between Models — Odoo 18.0 documentation, https://www.odoo.com/documentation/18.0/developer/tutorials/server_framework_101/07_relations.html
  36. Odoo - Many2one implementation in database - Stack Overflow, https://stackoverflow.com/questions/45924288/odoo-many2one-implementation-in-database
  37. Create Foreign Key of ID in Odoo Model Tables - Stack Overflow, https://stackoverflow.com/questions/71866460/create-foreign-key-of-id-in-odoo-model-tables
  38. How does Odoo store One2Many fields?, https://www.odoo.com/forum/help-1/how-does-odoo-store-one2many-fields-84936
  39. How to Create One2Many Field in Odoo 17 Website - Cybrosys Technologies, https://www.cybrosys.com/blog/how-to-create-one2many-field-in-odoo-17-website
  40. How to implement a many-to-many relationship in PostgreSQL? - Stack Overflow, https://stackoverflow.com/questions/9789736/how-to-implement-a-many-to-many-relationship-in-postgresql
  41. How to find out the table name for a many2many relation (Where is the many2many table name stored?) | Odoo, https://www.odoo.com/forum/help-1/how-to-find-out-the-table-name-for-a-many2many-relation-where-is-the-many2many-table-name-stored-85712
  42. Connecting 2 Many2many Fields - Odoo, https://www.odoo.com/forum/help-1/connecting-2-many2many-fields-177310
  43. 2 or more many2many fields in table/view - Odoo, https://www.odoo.com/forum/help-1/2-or-more-many2many-fields-in-tableview-103542
  44. Optimizing The Odoo Server With PostgreSQL - Oodles ERP, https://erpsolutions.oodles.io/blog/optimize-odoo-server-postgresql/
  45. Odoo Performance Optimization Strategies and Techniques - Pysquad, https://odoo.pysquad.com/blogs/odoo-performance-optimization-strategies-and-techn
  46. Optimize Odoo and PostgreSQL: Performance Tuning Guide - Cloudpepper, https://cloudpepper.io/blog/optimize-odoo-and-postgresql-performance-tuning-guide/
  47. Odoo Server and PostgreSQL Optimization - Cybrosys Technologies, https://www.cybrosys.com/blog/how-to-optimize-an-odoo-server-postgresql
  48. How to Boost PostgreSQL Query Performance with Simple Tuning Techniques, https://www.cybrosys.com/research-and-development/postgres/how-to-boost-postgresql-query-performance-with-simple-tuning-techniques
  49. Optimizing Odoo Performance SQL Query Tuning & PostgreSQL Best Practices, https://arsalanyasin.com.au/optimizing-odoo-performance-sql-query-tuning/
  50. Custom Odoo Database Indexing: Boost Performance & Speed Up Your Odoo ERP, https://www.cybrosys.com/postgres/custom-database-indexing/
  51. Performance — Odoo 18.0 documentation, https://www.odoo.com/documentation/18.0/developer/reference/backend/performance.html
  52. ORM API — odoo 10.0 documentation, https://www.odoo.com/documentation/saas-13/reference/orm.html
  53. How to Restore a Database in Odoo 18 ERP - Cybrosys Technologies, https://www.cybrosys.com/blog/how-to-restore-a-database-in-odoo-18-erp
  54. Back up and restore - Odoo, https://www.odoo.com/forum/help-1/back-up-and-restore-254482
  55. Odoo Data Backup- How to Create and Restore Data in Odoo - Webkul, https://webkul.com/blog/odoo-data-backup-how-to-create-and-restore-data-in-odoo/
  56. Backup/Restoring a Large Database using PSQL dump with Filestore? - Odoo, https://www.odoo.com/forum/help-1/backuprestoring-a-large-database-using-psql-dump-with-filestore-129458
  57. How To Backup and Restore Odoo Database From Terminal using Command, https://www.odoo.com/forum/help-1/how-to-backup-and-restore-odoo-database-from-terminal-using-command-241445
  58. How can i restore ODOO Database?, https://www.odoo.com/forum/help-1/how-can-i-restore-odoo-database-177805
  59. Data Migration in Odoo: A Step-by-Step Guide to Best Practices - CandidRoot Solutions, https://www.candidroot.com/blog/our-candidroot-blog-1/data-migration-in-odoo-a-step-by-step-guide-to-best-practices-732
  60. Data Migration to Odoo: A Step-by-Step Guide to Best Practices - Shiv Technolabs Pvt. Ltd., https://shivlab.com/blog/data-migration-odoo-step-by-step-guide/
  61. Upgrade a customized database — Odoo 18.0 documentation, https://www.odoo.com/documentation/18.0/developer/howtos/upgrade_custom_db.html
  62. Odoo Security, https://www.odoo.com/security
  63. Secure PostgreSQL - Bitnami Documentation, https://docs.bitnami.com/aws/apps/odoo/administration/secure-server/
  64. Odoo 16.0 and Postgresql SSL authentification - Dator.lu, https://www.dator.lu/blog/blog-1/odoo-16-0-and-postgresql-ssl-authentification-8
  65. System configuration — Odoo 18.0 documentation, https://www.odoo.com/documentation/18.0/administration/on_premise/deploy.html