PostgreSQL 테이블 중복데이터 제거

설계, 운영이 잘 되는 DB에선 많이 발생하는 문제는 아닐테지만 테이블의 특정 컬럼값을 기준으로 중복된 데이터를 삭제해야 하는 경우가 있다.

필자의 경우 PostgreSQL을 사용하던 중 이전 담당자가 테이블을 TEST_01_TB ~ TEST_10_TB 이런식으로 물리적으로 10개로 나눠서 설계하여 사용하던걸 인수받았는데 감리 검수에서 10개의 테이블을 하나로 합치라는 개선안내를 받았다.

Hash Partition을 적용하여 테이블을 합쳤으나 파티션을 적용하니 기존에 복합키로 사용하던 Unique 조건이나 데이터를 생성 시 Insert쿼리문에서 ON CONFLICT 컬럼 DO NOTHING 옵션도 적용할 수 없어서 빠지게 되었는데 이 때문에 중복데이터가 발생하였다.

중복된 데이터를 어떻게 찾아서 지우느냐에 따라 수행시간에 큰 차이가 날거라고 생각해서 구글링을 해보니 몇가지 방법을 찾을 수 있었다.

Test Table Schema

1
2
3
4
5
6
7
8
9
10
CREATE TABLE MEMBER_TB (
MEM_ID BIGSERIAL PRIMARY KEY,
MEM_NAME VARCHAR(20) NOT NULL,
MEM_PNUM VARCHAR(11) NOT NULL,
MEM_EMAIL TEXT NOT NULL
);

CREATE TABLE BLACKLIST_TB (
MEM_PNUM VARCHAR(11) PRIMARY KEY
);

ROW_NUMBER()

유저 테이블에의 MEM_PNUM 컬럼을 기준으로 중복된 데이터가 있어서 이를 지우기 위해선 어떻게 해야할까? 구글링을 하고 제일먼저 찾은 방법은 ROW_NUMBER() 를 활용한 방법이었다.

1
2
3
4
5
6
7
DELETE FROM MEMBER_TB
WHERE MEM_ID IN ( SELECT MEM_ID
FROM (SELECT MEM_ID,
ROW_NUMBER() OVER(PARTITION BY MEM_PNUM ORDER BY MEM_ID ) RNUM
FROM MEMBER_TB )
WHERE RNUM > 1
);

바로 적용할까 싶었지만 타겟 테이블의 데이터건수는 수십억개라 좀 더 빠른 방법이 없는지 더 찾아보던 중 Self JoinDelete Using을 활용한 방법을 찾을 수 있었다.

DELETE USING

특정 테이블을 참조하여 데이터를 삭제할 때 PostgreSQL의 경우 MySQL처럼 DELETE JOIN을 제공하진 않지만 USING을 사용하여 DELETE JOIN과 유사한 기능을 지원한다.

1
2
3
DELETE FROM MEMBER_TB T1
USING BLACKLIST_TB T2
WHERE T1.MEM_PNUM = T2.MEM_PNUM;

예를 들면 이 처럼 USING 키워드를 사용하여 특정 테이블을 참조하여 유저테이블에서 블랙리스트 유저정보만 지울 수 있다.

그럼 여기서 SELF JOIN을 활용하여 MEM_PNUM, MEM_EMAIL 컬럼의 중복데이터를 삭제하고 싶으면 SQL문을 다음과 같은 식으로 작성할 수 있다.

1
2
3
4
5
DELETE FROM MEMBER_TB T1
USING MEMBER_TB T2
WHERE T1.CTID < T2.CTID
AND T1.MEM_PNUM = T2.MEM_PNUM
AND T1.MEM_EMAIL = T2.MEM_EMAIL;

참고한 자료에선 1000만건의 데이터 중 10만건이 중복발생했을 때 약 42초정도 걸렸다고 했고 적용 전 확인해보기 위해 샘플로 Row가 약 800만에 중복데이터가 32만건 정도 들어있는 테이블로 테스트를 해보니 쿼리 실행에 약 1분정도 소요된 것을 확인하고 본래 타겟 테이블에 적용하였다.

그 후 데이터 생성 로직을 변경하여 중복데이터가 들어올 수 없도록 수정하였고 설계와 테스트를 더 잘 해야겠다는 생각이 절실하게 드는 하루였다.

Reference
PostgreSQL DELETE JOIN

중복된 관측치 제거하기

How to delete duplicate rows in postgresql?

Spring Framework란 무엇인가

기초가 부족한 관계로 기초부터 다시 정리도 하는 겸사겸사 첫주제는 spring framework로 정했다.

Srping Framework란

스프링 프레임워크(Spring Framework)는 자바 플랫폼을 위한 오픈 소스 애플리케이션 프레임워크로 간단히 스프링(Spring)이라고도 한다. 동적인 웹 사이트를 개발하기 위한 여러 가지 서비스를 제공하고 있다.

대한민국 공공기관의 웹 서비스 개발 시 사용을 권장하고 있는 전자정부 표준프레임우커의 기반 기술로서 쓰이고 있다.

특징

  1. 크기와 부하의 측면에서 경량 컨테이너로서 자바 객체를 직접관리한다.

    • 객체 생성, 소멸과 같은 라이프 사이클을 관리하며 스프링으로부터 필요한 객체를 얻어올 수 있다
  2. 제어 반전 혹은 제어 역행(IoC: Inversion of Control)을 지원한다.

    • 컨트롤의 제어권이 사용자가 아닌 프레임워크에 있어서 필요에 따라 스프링에서 사용자의 코드를 호출한다.
    • IoC는 DI와 DL에 의해 구현된다.
      • DL(Dependency Lookup) : 의존성 검색
        • 컨테이너에서는 객체들을 관리하기 위해 별도의 저장소에 빈을 저장하는데 저장소에 저장되어 있는 개발자들이 컨테이너에서 제공하는 API를 이용하여 사용하고자 하는 빈을 검색하는 방법
      • DI(Dependency Injection) : 의존성 주입
        • 의존성 주입이란 객체가 서로 의존하는 관계가 되게 의존성을 주입하는 것으로 객체지향 프로그램에서 의존성이란 하나의 객체가 어떠한 다른 객체를 사용하는 것을 의미한다.
        • IoC에선 각 클래스 사이에 필요로 하는 의존관계를 빈 설정 정보를 바탕으로 컨테이너가 자동으로 연결해 주는 것을 말한다.
  3. POJO(Plain Old Java Object) 방식의 프레임워크이다.

    • 직역하면 오래된 방식의 간단한 자바 오프젝트라는 말이다.

    • 일반적인 J2EE 프레임워크에 비해 구현을 위하여 특정한 인터페이스를 구현하거나 상속을 받을 필요가 없어 기존에 존재하는 라이브러리 등을 지원하기에 용이하고 객체가 가볍다.

    • 쉽게 이야기하면 getter/setter 메소드로 이루어진 Java Benas를 생각하면 된다.

    • 예를 들어 자바 서블릿 코드를 작성할 때는 보통 HttpServlet을 상속받아야 한다.

      1
      2
      3
      public TestServlet extends HttpServlet {
      ...
      }

      이처럼 서블릿 프로그래밍을 하는 것만으로 객체지향 프로그래밍의 가장 핵심적인 기능 중 하나인 상속을 할 수 없고 HttpServlet에서 제공하는 기능을 어떻게 재사용할 것인지 판단해야하는 부분도 생겼다.

    • POJO는 이러한 제약이 없는 일반적인 객체를 말하는데 여기서 상속이나 인터페이스 구현을 사용하지 않는 객체가 아니라 어떠한 라이브러리나 프레임워크 등 자바 언어 사양 외에 어떠한 제한을 강제받지 않는 자바 오브젝트를 뜻하는 것이다.

  4. 관점 지향 프로그래밍(AOP: Aspect Oriented Programming)을 지원한다.

    • 기존의 객체지향 프로그래밍(OOP: Object Oriented Programming) 에서는 객체의 재사용으로 인해 반복되는 코드의 양을 줄일 수 있었지만 여전히 많은 부분에서 중복된 코드가 발생한다.
    • 예를 들어 로그, 권한 체크, 인증, 예외 처리와 같은 소스상에서 반복될 수 밖에 없는 필수적인 요소들로 코드의 가독성이나 유지보수적인 측면에서 좋지 않았다.
    • AOP는 OOP를 대체하는 개념이 아닌 OOP를 좀 더 OOP처럼 사용하기 위하여 보완하는 개념으로 공통적으로 반드시 필요하지만 중복해서 작성해야하는 핵심 이외의 코드들을 외부로 분리하여 관리한다.
    • 이렇게 외부에서 관리하는 공통기능을 핵심 로직에 영향을 끼치지 않게 잘 끼워넣어 개발하면 무분별하게 중복되는 코드를 제거하면서 공통기능의 수정을 통해 모든 핵심 로직의 공통기능을 수정하여 효율적인 유지보수가 가능해지면서 재활용성이 극대화된다.
    • 즉, 위에서 예를 들었던 트랜잭션이나 로깅, 보안과 같이 여러 모듈에서 공통적으로 사용하는 기능의 경우 분리하여 관리할 수 있다는 것이다.
  5. MVC (Model2)

    • MVC는 Model, View, Controller 를 뜻하며 사용자 인터페이스와 비즈니스 로직을 분리하여 개발하는 것으로 웹 프로그래밍 개발에선 거의 표준처럼 사용되고 있으며 일반적으로 Model2를 지칭한다.
      • Model은 데이터를 처리하는 영역
      • View는 렌더링되서 실제로 보이는 화면
      • Controller는 사용자의 요청을 받고, 응답을 주는 로직을 담당
    • 이처럼 소스를 분리하여 각 소스의 목적을 명확히하면 모듈화를 통해 재사용성을 늘리고 유지보수를 쉽게 할 수 있으며 확정성도 좋은 장점이 있다.
    • 간단한 흐름을 살펴보면 요청 -> 컨트롤러 -> 모델 -> 컨트롤러 -> 뷰 의 흐름이라고 생각하면 된다.
      (MVC와 관련된 자세한 내용은 추후 기회가 된다면 별도로 포스트하겠다.)

이상으로 스프링 프레임워크의 특징에 대하여 대략적으로 정리를 해보았다.


Reference


Git-flow의 활용

회사에서 내부서버에 Gitlab을 활용하여 Git Server를 구축하여 형상관리를 하고 있는데 특별한 관리나 체계없이 브랜치 관리를 하다보니 히스토리 파악하기도 힘들기도 하고 형상관리를 제대로 하고 있다는 느낌이 들지 않아 효율적인 형상관리 시스템의 사용을 위하여 방법을 찾던 중 우아한형제들 기술블로그의 “우린 Git-flow를 사용하고 있어요” 라는 글을 보고 해당 전략을 도입하면서 각 브랜치에 대해 간략하게 정리를 해보았다.

Git-flow

Git-flow에는 5가지 종류의 브랜치가 존재한다. 항상 유지되는 메인 브랜치들(master, develop)과 일정 기간 동안만 유지되는 보조 브랜치들(feature, release, hotfix)이 있다.

  • master : 제품으로 출시될 수 있는 브랜치
  • develop : 다음 출시 버전을 개발하는 브랜치
  • feature : 기능을 개발하는 브랜치
  • release : 이번 출시 버전을 준비하는 브랜치
  • hotfix : 출시 버전에서 발생한 버그를 수정 하는 브랜치

가장 중심이 되는 브랜치는 masterdevelop 브랜치이며, 이 두 개 브랜치는 무조건 있어야 한다. 이름은 바뀔 수 있다만 웬만해서는 변경하지 않고 진행하도록 하자. Git도 Production에서 사용하는 브랜치는 master를 사용하게 되니 관련된 부분을 변경하면 새로운 사람이 왔을때 스터디 커브가 존재할 수 있다.

병합된 feature, release, hotfix 브랜치는 삭제하도록 한다. (클라이언트 툴에서 git flow제공한다면 merge 하면 삭제하는 옵션을 제공한다.)

Feature 브랜치

  • 브랜치 나오는 곳 : develop
  • 브랜치가 들어가는 곳 : develop
  • 이름 지정 : master, develop, release-*, hotfix-*를 제외한 어떤 것이든 가능.

새로운 기능을 추가하는 브랜치이다.feature브랜치는 origin에는 반영하지 않고, 개발자의 reop애만 존재하도록 한다.

여기서 머지를 할 때, --no-ff 옵션을 이용하여 브랜치에서 머지가 되었음을 git 기록에 남겨두도록 한다.

Release 브랜치

  • 브랜치 나오는 곳 : develop
  • 브랜치가 들어가는 곳 : develop, master
  • 이름 지정 : release-*

새로운 Production 릴리즈를 위한 브랜치이다.지금까지 한 기능을 묶어 develop 브랜치에서 release 브랜치를 따내고, develop 브랜치에서는 다음번 릴리즈에서 사용할 기능을 추가한다.release 브랜치에서는 버그 픽스에 대한 부분만 커밋하고, 릴리즈가 준비되었다고 생각하면 master로 머지를 진행한다. (이때도 --no-ff 옵션을 이용하여 머지하였음을 남긴다.)master로 머지 후 tag 명령을 이용하여 릴리즈 버전에 대해 명시를 하고, -s-u <key> 옵션을 이용하여 머지한 사람의 정보를 남겨두도록 한다. 그런 뒤 develop 브랜치로 머지하여, release 브랜치에서 수정된 내용이 develop 브랜치에 반영한다.

Hotfix 브랜치

  • 브랜치 나오는 곳 : master
  • 브랜치가 들어가는 곳 : develop, master
  • 이름 지정 : hotfix-*

Production에서 발생한 버그들은 전부 여기로… 수정 끝나면, develop, master 브랜치에 반영하고, master에 다가는 tag 를 추가해준다.만약 release 브랜치가 존재한다면, release 브랜치에 hotfix 브랜치를 머지하여 릴리즈 될 때 반영이 될 수 있도록 한다.


Reference
우아한형제들 기술블로그의 “우린 Git-flow를 사용하고 있어요”

Github Page와 Hexo를 활용하여 블로그 개설하기

블로그를 시작하며

그동안 OneNote, Notion 등 노트프로그램을 사용하여 단편적으로 공부하던 내용을 블로그를 통해 좀 더 체계적으로 정리하고 다른사람들과 공유하고 싶은 생각에 블로그를 시작하기로 했다.(끈기가 부족한 편이라 얼마나 갈진 모르겠다^^;;)

Github + Hexo

일반적인 블로그를 생각하면 네이버 블로그, 티스토리, 혹은 미디엄, 브런치 등을 떠올릴 수 있지만 기술블로그를 표방하는만큼 github page를 이용하기로 마음먹었다. github page에서는 username.github.io 도메인을 무료로 제공하여 정적 웹페이지를 무료 호스팅해주고 있다.

github page에서 사용할 정적 웹페이지 생성기는 생각보다 다양한 종류가 있지만 마크다운 문서를 지원하면서 국내에서 가장 많이 사용되는 두가지는 다음과 같다.

  1. Jekyll
    1. Ruby 기반
    2. 다양한 테마, 플러그인 지원
    3. 환경설정 및 커스터마이징이 다소 복잡하며(특히 윈도우에서) 글이 많아지면 빌드속도가 느려진다는 이야기가 있다.
  2. Hexo
    1. Javascript(Node.js) 기반
    2. 마찬가지로 다양한 테마, 플러그인 지원
    3. npm을 통해 쉽게 설치 가능하며 Github 배포과정도 편하다.

처음엔 Jekyll을 사용하여 초기설정을 해봤는데 윈도우에서 설정이 너무 복잡하고 오류도 많이나서 익숙한 Node.js기반의 Hexo로 시작하기로 했다.

1. 설치

1.1 사전준비

  • Node.js 설치
  • Git 설치
  • Github 가입 후 신규 Repository 2개 생성

각 프로그램 설치는 이미 많은 문서들이 있기 때문에 별도로 언급하진 않겠다. Repository를 2개 생성하는 이유는 각각 블로그 운영, hexo 설정을 저장할 목적이며 블로그로 운영할 Repository name은 USERNAME.github.io 의 Public으로 생성한다.

2. Hexo 설치 및 블로그 생성

Hexo설정을 저장할 github repository를 clone 한 후 해당 위치에서 작업한다.

1
2
3
4
npm install -g hexo-cli
hexo init $디렉토리명
cd $디렉토리명
npm install

2.1 설정파일 수정

블로그 생성이 정상적으로 완료되었으면 이제 설정파일을 수정해보자.

root 경로에 _config.yml파일을 확인할 수 있는데 기본적인 블로그 설정은 이곳에서 관리한다. 자세한 내용은 공식문서에서 확인할 수 있다.

Site 설정

블로그 이름 및 간략한 소개를 설정한다.

1
2
3
4
5
title: Hello World
subtitle: No pain, No gain
description:
author: Jaeyong Yoo
...

URL 설정

블로그 URL 정보를 설정한다.

1
2
3
4
url: https://USERNAME.github.io
root: /
permalink: :year/:month/:day/:title/
permalink_defaults:

Github 설정

배포할 Github Page의 Repository 정보를 입력한다.

1
2
3
deploy:
type: git
repo: https://github.com/yoo0926/yoo0926.github.io

정상적으로 설치와 설정이 끝났다면 아래 명령어로 서버를 실행시켜 웹브라우저에서 http://localhost:4000 으로 접속하여 확인할 수 있다.

1
hexo server #or hexo s
  • 만약 로컬에서 실행 시 permission denied 가 발생하는 경우가 있다면 그냥 port를 변경해서 테스트하자
1
hexo server -p 8088

3. Github에 배포하기

로컬에서 테스트가 완료되었다면 이제 앞서 언급한 Github Page의 정적 웹페이즈 호스팅을 사용해보자.

Hexo Generate and Deploy

github에 배포하기 위해선 hexo-deployer-git 이라는 플러그인을 설치해야 한다.

1
npm install hexo-deployer-git

플러그인 설치가 완료되면 배포할 리소스를 생성하여 앞서 _config.yml 파일에서 설정한 배포설정의 저장소로 배포하게 된다.

1
2
3
4
hexo generate #hexo g
hexo deploy #hexo d
#동시에 하고 싶으면
hexo deploy --generate #hexo d -g

생성된 리소스는 USERNAME.github.io 저장소에 배포되며 https://USERNAME.github.io로 접속하게되면 블로그를 확인할 수 있다.

주의

간혹 deploy가 정상적으로 되지 않는다면 아래 명령어로 clean 후 다시 배포를 해보자.

1
2
hexo clean
hexo d -g

이상으로 기본적인 블로그 생성과 관련된 내용을 마무리 한다.


  • 추가메모
1
2
hexo new 포스트명 //기본설정값 draft 로 바꿔놓음
hexo publish 포스트명 //draft -> posts 로 이동

Reference
Hexo로 github 블로그 만들기 (Hueman 테마)
Github Page와 Hexo를 통해 30분만에 기술 블로그 만들기
Hexo 공식문서