도라의 개발 블로그

소프트웨어 개발 12

커넥션 풀 크기와 운영 지표 | pgBouncer, VACUUM, Table Bloat, 모니터링

작업일2026. 07Connection Pool pgBouncer TPS / QPS Latency VACUUM 모니터링쿼리를 튜닝했더라도 트래픽이 몰리면 서비스 전체가 응답하지 않는 경우가 있습니다. 느려서가 아니라 연결을 더 받을 수 없어서입니다. 데이터베이스 연결은 무료가 아니고, 개수에 한계가 있습니다.동시 접속자가 2,000명이면 DB 연결도 2,000개가 필요할까요?아닙니다. 커넥션 풀을 쓰면 DB 연결 20개로 앱 연결 2,000개를 처리할 수 있습니다.인덱스와 실행계획이 쿼리 하나를 빠르게 만드는 일이라면, 여기서 정리하는 것은 서비스 전체의 처리량을 유지하는 일입니다. 연결을 어떻게 관리하고, 무엇을 보고 이상을 판단하는지입니다.연결 하나의 값PostgreSQL은 연결마다 별도의 프로세스를..

Java 메모리 구조와 == equals 차이 | Stack·Heap·Metaspace, Integer 캐시, String 불변, 가비지 컬렉션(Garbage Collection)

작업일2026. 08Stack·Heap Metaspace 기본형·참조형 == vs equals Integer 캐시 String 불변 StringBuilder Garbage CollectionJava 코드에서 Integer a = 100, b = 100 은 a == b 가 true 인데, 값만 1000으로 바꾸면 false 가 됩니다. 문법을 몰라서 생기는 일이 아니라 값이 어디에 저장되는지를 몰라서 생기는 일이라, 메모리 구조부터 잡고 거기서 갈라져 나오는 것들을 순서대로 정리했습니다.왜 == 로 문자열을 비교하면 안 될까요?== 는 변수에 담긴 값을 그대로 비교합니다. 기본형 변수에는 숫자가 들어 있지만 참조형 변수에 들어 있는 것은 객체의 주소라서, 내용이 같아도 객체가 두 개면 주소가 달라 fals..

DB Lock과 데드락 | 낙관적 락·비관적 락, SELECT FOR UPDATE, SKIP LOCKED

작업일2026. 07Lock Deadlock FOR UPDATE SKIP LOCKED Advisory Lock pg_locks재고가 1개 남았는데 두 사람이 같은 순간에 주문 버튼을 누릅니다. 둘 다 재고를 1로 읽고, 둘 다 0으로 고칩니다. 재고는 0이 되었는데 주문은 두 건 들어옵니다. Lock은 이 상황을 막기 위한 장치입니다.같은 행을 동시에 고치려는 트랜잭션이 둘이면 어떻게 될까요?충돌을 미리 막을지, 일어난 뒤에 잡아낼지부터 정해야 합니다.MVCC 덕분에 일반적인 읽기와 쓰기는 서로를 막지 않습니다. 일반 SELECT는 다른 트랜잭션의 UPDATE를 기다리지 않고 자신의 스냅샷을 읽습니다. 하지만 쓰기끼리의 충돌은 여전히 발생할 수 있습니다. 같은 행을 두 트랜잭션이 동시에 수정하려 하면, ..

묵시적 커밋과 AUTO COMMIT | TRUNCATE와 DELETE 차이, 롤백 안 되는 자리

작업일2026. 07트랜잭션 AUTO COMMIT 묵시적 커밋 DDL TRUNCATESQL 문법은 익숙해도 커밋이 정확히 언제 일어나는지 놓치기 쉽습니다. 그런데 데이터를 되돌릴 수 없게 만드는 사고는 대개 문법이 아니라 이쪽에서 납니다.BEGIN을 안 적고 UPDATE를 실행하면 어떻게 될까요?대부분의 DBMS에서 그 문장은 이미 확정된 상태입니다. ROLLBACK을 칠 기회가 없습니다.WHERE를 빼고 UPDATE를 날린 이야기는 실수담처럼 돌아다닙니다. 그게 왜 되돌릴 수 없는 사고가 되는지는 AUTO COMMIT을 알아야 설명이 됩니다. 그리고 트랜잭션을 제대로 열었는데도 중간에 조용히 끊기는 경우가 있는데, 그것이 묵시적 커밋입니다.AUTO COMMITDELETE와 TRUNCATE는 둘 다 데이..

트랜잭션 격리 수준과 MVCC | ACID, WAL, Dirty Read와 Phantom Read

작업일2026. 07트랜잭션 ACID 격리 수준 MVCC WAL PostgreSQL혼자 테스트할 때는 문제없던 코드도 사용자가 동시에 몰리면 예상치 못한 문제가 발생합니다. 같은 데이터를 여러 트랜잭션이 동시에 수정하면서 합계가 달라지거나, 방금 조회한 결과가 다시 조회했을 때 달라지는 현상이 생길 수 있습니다. 이처럼 여러 작업이 동시에 실행되는 환경에서는 데이터의 일관성을 어떻게 보장할지가 중요합니다. 트랜잭션은 이러한 문제를 포함해 데이터의 정확성을 보장하기 위한 기본 단위입니다.같은 조회를 두 번 했는데 결과가 다르면 버그일까요?격리 수준을 어디에 두었느냐에 따라 정상 동작일 수 있습니다. 무엇까지 허용할지 정하는 것이 격리 수준입니다.SQL을 공부할 때는 쿼리를 하나씩 순서대로 실행하므로 동시성..

PostgreSQL 쿼리 튜닝 | EXPLAIN ANALYZE, Buffers, Nested Loop·Hash·Merge

작업일2026. 07EXPLAIN ANALYZE 실행계획 Seq Scan 복합 인덱스 Hash Join Materialized View 안티패턴 pg_stat_statements인덱스를 걸었는데도 쿼리가 그대로 느릴 때가 있습니다. 인덱스가 없어서가 아니라 만들어 둔 인덱스를 쿼리가 안 타서 생기는 일입니다. 탔는지 안 탔는지는 추측할 필요 없이 실행계획에 그대로 적혀 있습니다.이 쿼리가 왜 느린지 어떻게 알 수 있을까요?실행계획에서 버려진 행의 개수를 먼저 확인합니다. 5만 행을 읽어 4만 행을 버리고 있다면 대부분의 비용이 불필요한 행을 읽는 데 사용되고 있는 것입니다.느린 쿼리를 고치는 순서는 정해져 있습니다. 어떤 쿼리가 느린지 찾고, 실행계획으로 왜 느린지 확인하고, 원인에 맞는 방법으로 고칩니..

SQL JOIN 실수 패턴 | LEFT JOIN과 WHERE, 중복 행, NOT IN NULL, EXISTS

작업일2026. 07JOIN LEFT JOIN NULL EXISTS NOT INJOIN 문법은 금방 익숙해지는데, 결과 행 수가 예상과 다르게 나오는 일은 계속 생깁니다. 오류가 안 나고 결과만 조용히 틀리기 때문에 찾기도 어렵습니다.LEFT JOIN을 걸어놓고 WHERE로 조건을 하나 붙였는데, 왜 결과가 줄어들까요?그 순간 LEFT JOIN이 INNER JOIN으로 바뀌었기 때문입니다.문법이 틀린 것이 아니라 같은 문법이 다른 결과를 내는 자리가 몇 군데 있습니다. 전부 실행은 잘 되고 오류도 없어서, 알고 있지 않으면 그냥 지나갈 수 밖에 없죠.ON 절과 WHERE 절모든 학생을 보여주되 CS101 성적만 함께 보고 싶다고 해보겠습니다. 수강하지 않은 학생도 목록에는 있어야 합니다.-- 의도와 다른..

PostgreSQL 인덱스 설계 | 선택도, 복합 인덱스 순서, 커버링 인덱스, 쓰기 비용

작업일2026. 07인덱스 B-Tree 선택도 복합 인덱스 커버링 인덱스 PostgreSQL쿼리가 느릴 때 가장 먼저 나오는 답이 인덱스를 걸라는 것입니다. 그런데 인덱스를 만들면 조회는 빨라지지만 쓰기가 느려지고 저장 공간이 늘어납니다. 어느 컬럼에 걸어야 하고 어디까지 걸어도 되는지 정리해보겠습니다.인덱스를 걸었는데 왜 더 느려졌을까요?조건에 맞는 행이 전체의 20%를 넘으면 인덱스를 타도 순차 읽기와 속도가 비슷해집니다.수백만 행짜리 테이블에서 조건 하나로 행을 찾는다고 해봅시다. 인덱스가 없으면 데이터베이스는 첫 행부터 마지막 행까지 전부 확인합니다. 행이 두 배가 되면 걸리는 시간도 두 배가 되는 O(N) 구조입니다.인덱스가 있으면 탐색 횟수가 O(log N)으로 줄어듭니다. B-Tree는 노드..

ERD와 SQL 기초: 데이터 모델링부터 JOIN까지

작업일2026. 07ERD SQL SELECT WHERE JOIN DBeaver데이터 모델을 설계한 뒤에는 테이블 관계를 ERD로 문서화하고, SQL로 필요한 데이터를 조회합니다.고객 이름과 주문 상품처럼 여러 테이블에 나뉜 데이터를 함께 조회하려면 어떻게 할까요?JOIN은 공통 키를 기준으로 여러 테이블의 데이터를 결합합니다.기본키와 외래키로 테이블을 분리하면 데이터 중복과 불일치를 줄일 수 있습니다. 조회 시에는 필요한 데이터를 결합해야 합니다. 예를 들어 고객 이름은 customers에, 주문 상품은 orders에 있으므로 두 테이블을 연결하는 조건이 필요합니다.이 글에서는 설계를 표현하는 ERD와 데이터를 조회하는 SQL의 기본 문법을 정리합니다. 문법 자체보다 쿼리가 처리되는 순서를 이해하는 것..

JavaScript 비동기 처리| 이벤트 루프, Promise, async/await, Fetch

작업일2026. 07이벤트 루프 Promise async / await Fetch JSON 모듈서버가 하는 일의 대부분은 기다리는 것입니다. DB 응답을 기다리고, 외부 API 응답을 기다리고, 모델 추론 결과를 기다립니다. 그 기다림을 어떻게 다루느냐가 서버가 버티는 요청 수를 결정합니다.비동기와 모듈은 직무를 가리지 않고 필요한 부분입니다.화면을 만들든 서버를 만들든, 무언가를 기다렸다가 결과를 받아 처리하는 일은 똑같이 일어납니다.JavaScript를 브라우저에서 화면 움직이는 언어로만 알고 있으면 이 부분이 왜 중요한지 잘 안 보입니다. 그런데 비동기 처리와 모듈 시스템은 언어를 옮겨도 그대로 따라오는 개념입니다. Python의 asyncio나 Java의 CompletableFuture로도 같은 ..