[실전 DB 15] 데이터를 직접 건드릴 때의 원칙

지금까지는 읽기를 빠르고 싸게 만드는 이야기였다. 이번 편은 결이 조금 다르다. 데이터를 직접 건드릴 때, 즉 손으로 데이터를 지우거나 고치거나 넣을 때 지켜야 할 원칙들이다. 최적화만큼 눈에 띄지는 않지만, 이걸 어기면 데이터가 조용히 망가지고 앞서 쌓은 최적화도 무너진다. 데이터베이스를 오래 건강하게 유지하는 위생 수칙에 가깝다.


운영하다 보면 데이터를 직접 손대야 할 때가 반드시 온다. 그때마다 되풀이해 부딪힌 원칙들을 이번 편에 모았다.

1. 직접 손대는 일은 왜 위험한가

서비스 코드를 통해 데이터가 바뀔 때는, 미리 짜둔 흐름이 관련된 처리를 다 해준다. 그런데 데이터를 손으로 직접 건드리면 그 흐름을 건너뛴다. 딸린 처리가 다 빠진 채 원본만 바뀌는 것이다. 그래서 직접 조작은 편리하지만 위험하다.


예를 들어 서비스에서 글을 지우면 그에 딸린 댓글, 파일, 집계 값까지 정리되도록 흐름이 짜여 있다. 그런데 데이터베이스에서 글 한 줄만 직접 지우면, 그 딸린 것들은 그대로 남는다. 흐름을 안 거쳤으니 뒤처리가 안 된 것이다. 이렇게 남은 잔재가 나중에 문제를 일으킨다.


그래서 직접 조작의 첫 번째 원칙은 신중함이다. 손대기 전에 이 데이터에 무엇이 딸려 있는지, 이걸 바꾸면 무엇이 함께 바뀌어야 하는지 먼저 파악한다. 서비스 흐름이 대신 해주던 처리를 이제 내가 직접 챙겨야 하기 때문이다. 무엇이 딸려 있는지 모른 채 손대는 게 가장 위험하다.


내 경우 직접 조작을 하기 전에 반드시 먼저 조회부터 한다. 무엇을 바꾸려는지 정확히 몇 건인지, 딸린 것은 어디에 있는지 읽어서 확인한 다음에 손을 댄다. 조회 없이 곧장 고치거나 지우면, 예상보다 많은 걸 건드리거나 엉뚱한 걸 건드리기 쉽다. 보고 나서 만지는 것이 직접 조작의 기본자세다.


직접 조작이 위험한 또 다른 이유는 검증을 건너뛴다는 것이다. 서비스 흐름은 값이 올바른지, 권한이 있는지, 형식이 맞는지 확인한 뒤에 데이터를 바꾼다. 그런데 손으로 직접 넣으면 그 확인들이 다 빠진다. 엉뚱한 형식이나 말이 안 되는 값이 그대로 들어갈 수 있다. 편하다는 건 곧 안전장치가 없다는 뜻이기도 하다.

2. 지울 땐 딸린 데이터도 함께

가장 흔한 실수가 원본만 지우고 딸린 데이터를 남기는 것이다. 글을 지우면서 그 글의 댓글을 안 지우면, 주인 없는 댓글이 남는다. 그 글에 딸린 파일을 안 지우면, 아무도 안 보는 파일이 저장 공간을 계속 차지한다. 원본은 사라졌는데 부속물이 유령처럼 남는 것이다.


이 유령 데이터는 여러 문제를 낳는다. 저장 공간을 낭비하고, 집계를 어긋나게 하고, 때로는 없는 원본을 가리키다 오류를 일으킨다. 앞 시리즈에서 다룬, 원본이 지워졌는데 그 파일이 남아 저장소에 쌓이는 고아 파일이 대표적이다. 지울 때 딸린 걸 안 지운 대가가 이렇게 쌓인다.


그래서 지울 때는 딸린 데이터를 빠짐없이 함께 지운다. 글을 지운다면 그 댓글, 추천 기록, 딸린 파일, 관련 알림까지 한 번에 정리한다. 무엇이 딸려 있는지 목록을 만들어두고, 지울 때마다 그 목록을 따라 다 지우는 것이다. 원본 하나가 아니라 그에 매달린 전체를 지운다는 감각이 필요하다.


서비스 코드에 이미 이 정리 흐름이 있다면, 직접 지우기보다 그 흐름을 태우는 게 낫다. 흐름이 딸린 걸 다 챙겨주기 때문이다. 직접 지워야만 하는 상황이라면, 그 흐름이 무엇을 지우는지 그대로 따라 해서 하나도 빠뜨리지 않는다. 이미 검증된 정리 순서를 재현하는 것이다.


딸린 데이터를 다 안다는 게 생각보다 어렵다. 시간이 지나며 기능이 붙으면 한 데이터에 매달린 것들이 늘어나기 때문이다. 처음엔 글에 댓글만 딸려 있었는데, 나중에 추천, 알림, 첨부, 신고 기록까지 붙는 식이다. 그래서 무엇이 딸려 있는지 목록을 만들어 관리하고, 기능을 더할 때마다 그 목록도 함께 갱신하는 게 좋다.

3. 시각은 표준 방식으로 저장한다

데이터를 넣을 때 특히 자주 실수하는 게 시각이다. 시각을 지역 시간으로 저장하면 나중에 큰 혼란이 온다. 저장한 사람의 지역과 읽는 사람의 지역이 다르면 시각이 어긋나고, 서버가 어디서 도는지에 따라서도 달라진다. 지역 시간으로 저장된 데이터는 기준이 흔들린다.


그래서 시각은 늘 하나의 표준 기준으로 저장한다. 세계 어디서나 같은 기준 시각으로 저장해두고, 사용자에게 보여줄 때만 그 사람의 지역 시간으로 바꾼다. 저장은 표준으로 통일하고 표시는 그때그때 변환하는 것이다. 이러면 저장된 시각의 기준이 흔들리지 않는다.


이 원칙을 어기면 데이터가 미묘하게 어긋난다. 어떤 시각은 이 기준, 어떤 시각은 저 기준으로 저장되면, 둘을 비교하거나 정렬할 때 틀린 결과가 나온다. 최신순 정렬이 어긋나거나, 기간으로 거르는 조건이 엉뚱한 걸 걸러낸다. 저장 기준이 섞이는 순간 시각을 다루는 모든 게 믿을 수 없게 된다.


직접 데이터를 넣을 때도 이 기준을 지켜야 한다. 손으로 시각을 넣으면서 무심코 내 지역 시간으로 넣으면, 서비스가 표준으로 넣은 다른 데이터와 기준이 어긋난다. 그래서 직접 넣을 때도 서비스와 똑같은 표준 기준으로 넣는다. 저장 기준을 온 데이터가 하나로 통일해야 시각이 믿을 만해진다.


표준 기준으로 저장하면 좋은 점이 하나 더 있다. 서버가 어디로 옮겨가든, 사용자가 어느 지역에서 접속하든 저장된 값이 흔들리지 않는다는 것이다. 저장은 세계 공통의 기준 하나로 통일해두고, 보여줄 때만 각자의 지역 시간으로 바꾸니, 저장된 데이터 자체는 언제 어디서 봐도 같은 의미를 갖는다. 기준이 하나여야 데이터를 믿을 수 있다.

4. 관련 작업을 원자적으로 묶기

직접 조작이 여러 단계로 이뤄질 때, 그 단계들을 한 덩어리로 묶는 게 중요하다. 앞서 비정규화와 캐시 무효화에서도 반복한 원리다. 관련된 작업이 함께 성공하거나 함께 실패해야지, 절반만 반영되면 데이터가 어중간하게 어긋난 상태가 된다.


예를 들어 글을 지우면서 딸린 댓글도 지우고 집계도 줄이는 세 작업이 있다면, 이 셋이 다 되거나 다 안 돼야 한다. 글은 지웠는데 댓글이 안 지워지고 집계도 안 줄면, 유령 댓글과 어긋난 숫자가 동시에 생긴다. 중간에 멈춘 상태가 가장 나쁘다. 그래서 여러 작업을 하나의 원자적 단위로 묶는다.


원자적으로 묶으면 실패해도 안전하다. 중간에 문제가 생기면 전체가 없던 일이 되니, 어중간하게 어긋난 상태가 안 남는다. 다시 시도하면 되는 것이다. 반면 묶지 않으면 실패한 지점에 따라 데이터가 제각각 어긋나, 그걸 손으로 복구하는 더 큰 일이 생긴다.


여러 건을 한꺼번에 바꾸는 대량 작업일수록 이 원칙이 중요하다. 수천 건을 바꾸다 중간에 멈추면, 어디까지 바뀌었는지 알기 어렵다. 그래서 대량 작업은 적절한 크기로 나눠 각 묶음을 원자적으로 처리하고, 어디까지 됐는지 남겨서 멈춰도 이어서 할 수 있게 한다. 한 번에 다 하려다 중간에 터지는 것보다 안전하다.


원자적으로 묶는 것은 앞서 비정규화와 캐시 무효화에서도 나온 원리라, 이 시리즈를 관통하는 하나의 감각이라 할 만하다. 관련된 것들을 흩어두면 언젠가 절반만 반영된 상태가 생기고, 그게 조용히 데이터를 어긋나게 한다. 그래서 함께 바뀌어야 할 것은 함께 묶는다. 이 습관 하나가 나중에 데이터를 손으로 복구하는 큰 고생을 던다.

5. 직접 수정은 최후의 수단

이 모든 걸 종합하면, 데이터 직접 수정은 최후의 수단으로 두는 게 맞다. 가능하면 서비스가 제공하는 흐름을 통해 바꾸고, 그게 안 될 때만 직접 손댄다. 서비스 흐름은 딸린 처리를 다 챙기고 검증도 거치지만, 직접 조작은 그 안전장치를 다 건너뛰기 때문이다.


직접 손대야 한다면 절차를 지킨다. 먼저 조회해서 무엇을 몇 건 건드릴지 확인하고, 딸린 데이터를 함께 처리하고, 시각 같은 값은 표준 기준을 지키고, 관련 작업을 원자적으로 묶고, 끝나면 결과를 다시 조회해서 의도대로 됐는지 검증한다. 손대기 전 확인과 손댄 뒤 검증이 직접 조작의 양쪽 안전판이다.


특히 되돌리기 어려운 작업은 더 신중하게 한다. 지우는 건 되돌리기 어려우니, 지우기 전에 정말 그것만 지워지는지 조건을 거듭 확인한다. 조건을 잘못 걸어 엉뚱한 것까지 지우는 사고는 순식간에 일어난다. 그래서 나는 지우기 전에 같은 조건으로 먼저 조회해서, 지워질 목록을 눈으로 보고 나서 지운다.


이 원칙들은 화려한 최적화는 아니지만, 이걸 지키지 않으면 앞서 쌓은 최적화가 무너진다. 어긋난 집계, 남은 유령 데이터, 기준이 섞인 시각은 조용히 쌓여 언젠가 이상한 화면과 틀린 숫자로 드러난다. 그래서 나는 이걸 데이터베이스의 위생 수칙이라 부른다. 눈에 안 띄지만 지키면 오래 건강하고, 어기면 서서히 병든다.


정리하면 데이터를 직접 건드릴 때는 딸린 데이터까지 함께 처리하고, 시각은 표준 기준으로 저장하고, 관련 작업을 원자적으로 묶고, 손대기 전 조회와 손댄 뒤 검증을 지킨다. 직접 조작은 안전장치를 건너뛰는 일이라 최후의 수단으로 신중히 한다. 다음 편은 이 시리즈의 마지막으로, 데이터베이스의 한계와 그다음 단계를 다룬다.