지난번에 쓴 글 의 정리 버전이다.
어제는 강렬한 일을 겪고 온 뒤에 두서없이 쓴 글이라 제대로 정리해서 다시 작성해보았다.
DB랑 서버랑 요금을 비교해보라.
서버가 훨씬 저렴 할 것이다.
서버는 증설해도 부담이 덜하다.
서버가 연산을 해서 간단한 쿼리로 DB에 질의를 하는게 좋지,
DB에 일시켜서 버티지 못해 스펙을 높여야 하거나 클러스터링이나 샤딩 등으로 늘려야 하면 대가는 굉장히 비싸다.
로그 조회 전용 DB가 아니라면 로그를 넣으면 안된다.
여기서 DB란 물리적인 장비의 개념을 뜻한다.
로그 때문에 서비스중인 서버의 DB가 터지면 도망치고 싶어진다.
용량을 늘려서 복구해도 금새 또 터질게 보이기 때문이다.
필요한게 생겨서 컬럼을 추가하는건 너무 쉬운 일이다.
테이블에 아무 생각 없이 컬럼을 붙이다보면 어느새 컬럼이 30개 40개 50개 이렇게 되어버린다.
그렇게 거대한 테이블은 어떤 쿼리를 날려도 어떻게 인덱스를 걸어도 성능이 떨어질 수 밖에 없다.
시간이 갈 수록 이 테이블의 컬럼을 이용하는 코드는 늘어 갈 것이고, 분리하려면 신경써야 할 범위는 복리 이자가 붙듯이 계속 늘어난다.
인덱스로 설정된 컬럼은 UPDATE라는 개념이 사라진다.
"당신의 UPDATE 대체되었다. DELETE & INSERT로"
modify time을 담는 컬럼에 인덱스를 걸면...
그리고 컬럼 이야기를 할 때 언급한 '거대한 테이블'에 인덱스를 걸다보면 이리 검색하고 저리 검색하는 케이스가 생기기 때문에 경우의 수 만큼 multi key index 를 만들게 된다.
용량문제보단 메모리 문제 때문에 괴로워 질 것이다.
DB는 검색엔진이 아니다.
검색엔진으로 쓰려면 엘라스틱서치같은 것을 이용하는게 더 좋다.
어떤 목적으로 ngram인덱스를 생성하려는지 한번 더 생각해야 한다.
개인적으로는 Stored Procedure를 잘 쓰는 케이스를 경험하지 못해서 좋아하진 않지만, 단일 책임 원칙을 지키면서 요긴하게 쓴다면 좋을수도 있다.
하지만, Stored Procedure 안에 절차지향적 코딩으로 변수에 할당에 재할당을 해가며 이리저리 INSERT와 UPDATE, DELETE 해대면 성능에도 좋지 않고, 분리해내기도 쉽지 않다.
그런 Stored Procedure 라면 곧 DB 전체에 성능저하를 미칠텐데 의존하는 쿼리들 때문에 조치하기도 쉽지 않다.
AUTO_INCREMENT로 id를 매기는 테이블인데 create timestamp 컬럼에 인덱스를 걸어서 검색하는 쿼리를 본 적이 있다.
컬럼이 30개나 되고 인덱스도 40개나 걸린 테이블 때문에 메모리가 자꾸 터져서 고생한 일도 있다.
300줄이 넘어가는 Stored Procedure 때문에 애먹은적도 있다.
(한두개가 아니었다.)
DB에 로그도 같이 넣어서 조치해주려 했더니 용량을 늘리려면 스펙도 늘려야 성능을 유지할 수 있어서 엄청난 요금을 지불한 일도 있었다.
생각 하지 않고 손가락부터 움직이면 그게 차곡차곡 쌓여서 나중에 엄청난 이자와 함께 빚을 징수하러 찾아 올 것이다.
현실에서 빚 독촉을 당하면 괴로운 것 처럼 기술부채는 서비스를 불안정하게 만드는 것으로 빚 독촉을 한다.
현실에서의 빚 처럼 기술부채도 일시불로 상환할 수 없다.
그러니 손가락을 움직이기 전에 생각하고 계획을 세워야 한다.
부디 *WISCA 신드롬이나 *WIMP 신드롬에 빠지지 않길 바란다.
* WISCA: Why Isn't Sam Coding Anything?
* WIMP: Why Isn't Mary Programming?
(코드 컴플리트2에 수록된 표현)
안녕하세요. 지나가는 DBA 입니다. ^^*
작성해주신 글 잘 읽어봤어요. 새롭게 알게된 정보로 도움이 많이 되었습니다~ :)
생활코딩에서 지난번 쓰신글과 이번에 쓰신글을 읽고 제 주관적인 의견을 말씀드려 보려고 해요.
쓰다보니 장황해졌네요. ㅠㅠ
컬럼이 추가되는 부분
컬럼이 추가되는 것은 성능에 크게 영향을 미치지 않습니다. (컬럼 추가시 default null 옵션 필요)
물론 하나의 레코드를 조회하기 위해 읽어야 하는 page 수는 늘어나겠지만요..
제가 관리하는 테이블에도 50개정도의 컬럼과 억대의 데이터 건수가 있지만,
인덱스는 효율적으로 관리되고 있어 지연쿼리는 발생하고 있지 않습니다.
오히려 컬럼이 너무 많아진다고 테이블을 분리하다보면, 나중에 관리비용이 더 증가할 수 있습니다.
그래서 컬럼이 많아서 나눠야 한다기 보단, 용도에 맞는지를 보시는것도 좋지 않을까 합니다.
(테이블을 여러개 조인하면서 조회하는 방식의 연산 증가 등)
컬럼이 추가될 때 주의해야 할 점이 하나 더 있는데요.
테이블을 * 로 조회하는 쿼리가 있다면, 관련된 소스나 테이블들을 함께 봐줘야 한다는 것 입니다.
예를들어 INSERT INTO A SELECT * FROM B 라는 쿼리가 있었는데, B 테이블에 컬럼이 추가되면 A 테이블에도 컬럼을 추가해 줘야 오류가 발생하지 않습니다.
Stored Procedure (이하 SP)
SP 는 DB 상에 있어 꼭 필요한 기능입니다. 물론 복잡성을 줄이는 것도 당연히 필요합니다.
꼭 필요한 기능이라고 말씀드리는 이유는 쿼리를 정형화 시킬수 있다는 건데요.
DB에 어떤 쿼리만 수행될 수 있는지 확실하게 관리가 된다는 된다는 겁니다.
또 한가지, SP 는 실행계획을 재사용할 수 있습니다.
물론 코드소스에서도 실행계획을 재사용할 수 있게 구현할 수 있지만 (예: java - preparedstatement)
위에서 말씀드린 것처럼 DML 권한은 막아놓기 때문에 SP 사용을 추천드립니다.
마지막으로 DB계정에 DDL, DML 권한을 막고 SP Execute 권한만 있다면,
A 테이블의 컬럼이 추가될 때, A 테이블을 참조하는 SP 만 확인하여 이슈없을지를 확인해 보면 되기 때문에 관리 비용이 확실히 줄어들 수 있게 됩니다.
소스코드 모두를 뒤져야 할 필요는 없게 되는거죠~
하나의 SP 가 너무 길어서 부담이 많이 될거 같으시면, SP 를 2개로 분리하는 것도 추천드립니다.
어제 봤던 글인데 정리해서 다시 올려주셨네요. 감사합니다.