안녕하세요! 그로스로그 입니다!😊 🌱
버전을 하나씩 올리는 대신 데이터만 통째로 옮기는 판단, 송금 절차를 전부 되거나 전부 안 되게 묶는 방법, 그리고 행렬 전체를 숫자 하나로 요약하는 계산. 4기 6회차 세 편입니다.
4기 6회차는 2025년 12월입니다. 세 편이 각자 다른 자리에서 여러 단계를 한 덩어리로 다루는 이야기를 하고 있어요.
01
🍃 몽고DB 데이터 덤프
노현주 님
MongoDB를 5버전에서 7버전으로 올려야 하는 상황에서, 중간 버전을 거치는 대신 데이터만 뽑아 새 서버로 옮기기로 한 기록입니다.
판단을 첫 두 줄에 적었어요. "5 → 6 → 7 로 가는 대신 데이터만 덤프하여 7버전으로 이관하기로 결정."
준비물 네 가지, 명령 두 개, 옵션 설명, 그리고 결과 확인 방법까지 순서대로 있습니다.
도구가 많이 들어 있는 폴더에서 "지금은 딱 두 개만 사용하면 된다" 고 범위를 그었습니다.
4회차에서 크롤러를 고친 기록으로 만났던 분입니다. 이번에도 성격이 같아요. 이미 돌아가고 있는 것을 다뤄야 하는 상황입니다.
그리고 이 글의 값어치는 첫 두 줄에 다 있습니다. 선택지가 둘이었고 하나를 골랐다는 것이 명시돼 있거든요.
조금 더 들어가 보면
🪜 한 칸씩 올릴 것인가, 건너뛸 것인가
데이터베이스 버전을 올릴 때 정석은 한 단계씩 올리는 것입니다. 5에서 6으로, 6에서 7로요.
이유가 있습니다. 버전이 올라갈 때 내부 저장 형식이 바뀌는 경우가 있고, 그 변환 절차가 바로 앞 버전에서 올라오는 경우만 준비돼 있기 때문입니다. 두 칸을 건너뛰면 그 변환을 아무도 보장해주지 않아요.
그런데 이 방식에는 비용이 붙습니다.
· 중간 버전을 실제로 설치하고 띄워야 합니다
· 각 단계마다 문제가 없는지 확인해야 합니다
· 단계가 늘어날수록 어느 지점에서 틀어졌는지 찾기 어려워집니다
저자가 고른 다른 길이 데이터만 꺼내서 새 곳에 붓는 것입니다. 이러면 중간 단계가 통째로 사라져요. 5에서 데이터를 빼고, 7을 새로 깔고, 거기에 넣으면 끝입니다.
대신 포기하는 게 있습니다. 데이터만 옮기는 것이라 서버 설정, 인덱스 정의 중 일부, 사용자 계정 같은 것들은 따라오지 않습니다. 새 쪽에서 다시 만들어야 해요.
그래서 이건 상황에 따라 갈리는 판단입니다. 데이터가 아주 크면 뽑고 붓는 시간이 길어져 서비스 중단 시간이 문제가 되고, 설정이 복잡하면 옮길 것이 많아집니다. 반대로 데이터가 감당할 만하고 설정이 단순하면 이 길이 훨씬 빠르고 안전합니다.
⬆️ 새 곳에 붓는 방식의 숨은 이점
이 방식에는 저자가 적지 않은 이점이 하나 더 있습니다. 원본이 그대로 남아 있다는 것이요.
한 칸씩 올리는 방식은 원본을 고쳐가며 진행합니다. 5를 6으로 바꾸고, 그 6을 7로 바꿉니다. 중간에 실패하면 이미 형식이 바뀐 상태라 되돌리기가 어렵습니다.
덤프와 복원은 다릅니다. 읽기만 하고, 붓는 곳은 새 곳입니다. 잘못돼도 원래 서버는 그대로 돌아가고 있어요. 마음에 안 들면 새로 깐 쪽을 지우고 다시 하면 됩니다.
되돌릴 수 있는 절차와 없는 절차의 차이입니다. 5회차에서 무상태 서버 이야기를 하며 짚었던 것과 같은 결이에요. 운영 중인 것을 다룰 때는 작업 자체의 속도보다 실패했을 때 어디로 돌아갈 수 있는지가 먼저입니다.
🧰 "딱 두 개만 쓰면 된다"
도구 폴더에 여러 실행 파일이 들어 있는데 저자는 두 개만 지목했습니다. 데이터를 뽑는 것과 붓는 것이요.
사소해 보이는데 이런 문장이 시간을 아껴줍니다. 처음 하는 사람은 폴더를 열면 뭐가 뭔지 몰라 문서를 다 읽게 되거든요. "이 상황에서는 이 둘만"이라고 짚어주면 나머지는 나중에 필요할 때 보면 됩니다.
옵션 설명을 표로 정리한 것도 같은 성격입니다. 특히 이 항목이 실전적이에요.
--uri "..." — (선택 사항) 만약 사용자 인증(Username/Password)을 사용한다면 --uri "mongodb://user:pass@localhost:<port>" 형식을 사용인증이 걸려 있으면 기본 명령이 안 먹는다는 걸 미리 알려주는 것이죠. 실제로 여기서 막히는 경우가 흔합니다. 로컬에서 연습할 땐 인증이 없어서 잘 되다가, 실제 서버에서 붙을 때 갑자기 안 되거든요.
✅ 끝났는지 확인하는 절차까지
이 기록에서 마지막 부분이 중요합니다. 옮기고 나서 확인하는 방법을 적어뒀어요. 셸에 접속해서 데이터베이스 목록을 보고, 하나 골라 들어가 컬렉션을 확인합니다.
이관 작업은 "끝났다"를 판정하기 어려운 일입니다. 명령이 오류 없이 끝났다고 데이터가 다 왔다는 뜻은 아니거든요. 그래서 확인 절차가 함께 있어야 합니다.
여기서 한 단계 더 나가면 실무에서 쓰는 방법이 있습니다. 개수를 세어 비교하는 것이요. 옮기기 전 각 컬렉션의 문서 수를 적어두고, 옮긴 뒤 같은 숫자가 나오는지 보는 겁니다. 목록만 확인하면 "있다"까지만 알 수 있고, 개수까지 보면 "다 왔다"를 알 수 있어요.
목록 확인이 있는 것과 없는 것의 차이가 크고, 개수 비교까지 있으면 더 낫습니다.
⏸️ 옮기는 동안 서비스는 어떻게 하는가
이 방식에서 남는 질문이 하나 있습니다. 뽑고 붓는 동안 데이터가 계속 들어오면 어떻게 되는가요.
뽑기 시작한 뒤에 들어온 데이터는 덤프에 없습니다. 그래서 붓고 나서 새 서버로 갈아타면 그 사이의 기록이 사라집니다.
그래서 실제 이관에서는 셋 중 하나를 고릅니다.
· 잠깐 멈춥니다 — 가장 확실합니다. 새벽에 서비스를 잠시 내리고 옮기는 방식이요. 데이터가 크지 않으면 이게 제일 낫습니다
· 읽기만 허용합니다 — 쓰기만 막아두면 사용자는 조회는 할 수 있습니다. 완전 중단보다 체감이 낫습니다
· 차이만 다시 옮깁니다 — 한 번 크게 옮긴 뒤, 그 사이 바뀐 것만 골라 한 번 더 옮기는 방식입니다. 중단 시간이 가장 짧은 대신 절차가 복잡해집니다
어느 쪽이든 "언제부터 언제까지 새 데이터를 안 받을 것인가"를 정해야 합니다. 이걸 안 정하고 시작하면 옮기는 데 성공하고도 데이터가 어긋나요.
저자가 "버전 5에서 7로 업그레이드한다는 가정 하에"라고 조건을 붙여 시작한 게 이 점에서도 정확합니다. 전제를 밝혀두면 읽는 사람이 자기 전제와 다른 부분을 찾을 수 있습니다.
🔙 되돌아갈 계획을 같이 세워둡니다
이관 작업에서 사람들이 자주 빠뜨리는 게 하나 더 있습니다. 잘 옮겼는데 나중에 문제가 생기면 어떻게 하느냐요.
옮기고 나서 며칠 뒤에 새 버전에서만 나타나는 문제를 발견하는 경우가 있습니다. 동작이 미묘하게 바뀌었거나, 예전 쿼리 중 하나가 더 이상 같은 결과를 안 주거나요. 그때 돌아갈 방법이 있어야 합니다.
그래서 실무에서는 이렇게 준비해둡니다.
· 옛 서버를 바로 안 지웁니다 — 일정 기간 켜두거나, 최소한 지우기 전에 백업을 남깁니다
· 되돌리는 절차를 미리 적어둡니다 — 급할 때 즉흥적으로 하면 반드시 실수합니다
· 되돌릴 수 있는 기한을 정합니다 — 새 쪽에 데이터가 쌓이기 시작하면 그때부터는 못 돌아갑니다. 그 시점이 언제인지 알고 있어야 해요
세 번째가 특히 중요합니다. 이관 직후에는 되돌리기가 쉬운데, 며칠 지나 새 데이터가 쌓이면 되돌리는 순간 그 데이터가 사라집니다. 되돌릴 수 있는 창이 시간과 함께 닫힙니다.
저자가 고른 방식은 이 창을 넓게 열어둡니다. 원본을 안 건드리니까요. 그래서 작업 자체가 안전할 뿐 아니라 작업 뒤에도 한동안 안전합니다.
📌 버전을 올리는 이유도 적어두면 좋습니다
마지막으로 하나만 덧붙이면, 이런 기록에 왜 올리는가까지 한 줄 있으면 더 좋습니다.
보안 문제 때문인지, 새 기능이 필요해서인지, 지원 종료가 다가와서인지에 따라 서두를 정도가 달라지거든요. 그리고 나중에 같은 판단을 할 때 근거가 됩니다.
이 기록은 방법이 아주 깔끔하게 정리돼 있어서, 거기에 이유 한 줄만 붙으면 판단과 절차가 모두 남는 기록이 됩니다.
그리고 이런 기록은 다음에 같은 일을 할 때 그대로 재사용됩니다. 버전 올리기는 한 번으로 끝나는 일이 아니라 몇 년에 한 번씩 돌아오는 일이거든요. 그때 처음부터 알아보는 것과 이 문서를 여는 것의 차이가 큽니다. 명령 두 줄과 확인 네 줄이면 다시 할 수 있게 적혀 있으니까요.
📝 원문에서는 이렇게 씁니다
명령 두 개로 끝냅니다.
# 뽑기 ./mongodump --uri "mongodb://localhost:<포트>" --out /mongodb_dump # 붓기 ./mongorestore --port <포트> --dir ~/mongodb_dump/
그리고 확인은 이렇게 합니다.
./mongosh # 셸 접속 show dbs # 데이터베이스 목록 use <이름> # 하나 선택 show collections # 컬렉션 확인
작업 명령 두 줄과 확인 명령 네 줄. 확인 쪽이 더 긴 게 이 기록의 성격을 보여줍니다.
큐레이터 노트
선택지가 둘이었고 하나를 골랐다는 것이 첫 줄에 적힌 기록이라 뽑았습니다. "5 → 6 → 7로 가는 대신 데이터만 덤프하여 이관하기로 결정"이요. 무엇을 했는지가 아니라 무엇 대신 무엇을 했는지가 적혀 있어서, 읽는 사람이 자기 상황에 맞는지 판단할 수 있습니다.
「선택과 그 근거가 남아 있는가」에 해당하는 자리입니다. 그리고 도구 여러 개 중 둘만 지목한 것, 확인 절차를 함께 적은 것도 뒤에 오는 사람의 시간을 아껴줍니다.
02
🏦 [RDB] MySQL Procedure
박현구 님
저장 프로시저를 은행 송금 시스템으로 실습한 기록입니다. 계좌 테이블과 송금 내역 테이블을 만들고, 이체 프로시저를 짰어요.
그냥 문법 정리가 아닙니다. 트랜잭션, 예외 핸들러, 잔액 검사가 다 들어 있습니다.
그리고 테스트 시나리오를 세 개 돌렸습니다. 정상 송금, 잔액 부족, 없는 계좌로 송금이요.
각 시나리오마다 "롤백 확인" 을 눈으로 보는 쿼리까지 붙여뒀습니다.
박현구 님은 4기 후반 회차를 '찍먹' 시리즈로 채운 분입니다. 6회차부터 10회차까지 계속 만나게 돼요.
이번 글에서 눈에 띄는 건 예제를 고른 감각입니다. 프로시저 문법을 보여주기만 할 거면 훨씬 단순한 예제도 됩니다. 그런데 송금을 골랐어요. 중간에 실패하면 안 되는 일이요.
조금 더 들어가 보면
💸 송금 예제가 가르치는 것
계좌 A에서 B로 50만 원을 보낸다고 해봅시다. 해야 할 일이 셋입니다.
1. A의 잔액을 50만 원 줄인다
2. B의 잔액을 50만 원 늘린다
3. 송금 내역을 한 줄 남긴다
1번만 되고 2번이 안 되면 돈이 사라집니다. 2번만 되고 1번이 안 되면 돈이 생기고요. 그래서 이 셋은 전부 되거나 전부 안 되어야 합니다.
이걸 보장하는 게 트랜잭션이고, 저자의 코드에 START TRANSACTION과 ROLLBACK이 들어 있는 이유입니다.
이 예제가 좋은 이유는 "왜 필요한가"가 설명 없이 이해되기 때문입니다. 잔액이 안 맞으면 안 된다는 걸 누구나 아니까요. 문법을 먼저 배우고 나중에 필요성을 이해하는 순서가 아니라, 필요성이 먼저 보이는 순서입니다.
🧯 예외 핸들러가 하는 일
저자가 넣은 부분 중 실무적인 게 예외 처리입니다.
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SET p_result = 'Error: 시스템 오류로 송금 실패.';
END;
"실행 중 어떤 에러라도 나면 여기로 온다" 는 선언입니다. 그리고 오면 무조건 롤백을 겁니다.
이게 왜 필요하냐면, 예상하지 못한 실패가 반드시 있기 때문입니다. 저자의 테스트 3번이 정확히 그 경우예요. 없는 계좌 번호로 송금을 시도하면 외래 키 제약에 걸려 오류가 납니다. 잔액 검사에서는 안 걸러지는 상황이죠.
핸들러가 없으면 어떻게 될까요. 오류가 나기 전까지 실행된 것들이 애매하게 남습니다. 출금은 됐는데 내역 기록에서 실패한 상태처럼요. 예외 상황에서 데이터가 어그러지는 대부분의 사고가 이 형태입니다.
EXIT이라는 단어도 짚어둘 만합니다. 오류가 나면 거기서 프로시저를 끝낸다는 뜻이에요. 계속 진행하는 방식도 있는데, 돈을 다루는 절차에서는 멈추는 쪽이 맞습니다.
🔍 검사와 예외를 둘 다 넣은 이유
이 코드에는 방어가 두 겹 있습니다. 잔액이 충분한지 미리 확인하는 검사와, 그래도 오류가 나면 잡는 핸들러요.
둘 중 하나만 있어도 될 것 같은데, 둘 다 있는 게 맞습니다. 역할이 다르거든요.
| 잔액 검사 | 예외 핸들러 | |
|---|---|---|
| 다루는 것 | 예상한 실패 | 예상 못 한 실패 |
| 결과 | "잔액 부족" 이라고 알려줌 | "시스템 오류" 라고 알려줌 |
| 사용자에게 | 무엇을 고쳐야 할지 알려줄 수 있음 | 다시 시도하라고밖에 못 함 |
예상한 실패는 이름을 붙여 돌려주고, 예상 못 한 실패는 안전하게 멈추는 것. 이 구분이 있으면 나중에 로그를 볼 때도 편합니다. "잔액 부족"이 많이 찍히는 건 정상이고, "시스템 오류"가 찍히면 봐야 하는 것이니까요.
⚙️ 구분 기호를 바꾸는 이유
문법 쪽에서 하나만 짚겠습니다. 저자가 자세히 설명한 DELIMITER 부분이요.
프로시저 안에는 여러 SQL 문장이 들어가고, 그 문장들은 각각 세미콜론으로 끝납니다. 그런데 프로시저 전체를 만드는 명령도 세미콜론으로 끝나야 합니다. 그러면 클라이언트가 프로시저 본문 안의 첫 세미콜론을 보고 "여기가 끝이구나" 하고 잘라버려요.
그래서 잠깐 문장 구분 기호를 다른 것으로 바꿔두고, 프로시저를 다 만든 다음 되돌립니다.
이건 4회차에서 본 CDATA 문제와 같은 형태입니다. 안에 든 내용이 바깥의 문법으로 읽히는 것이요. 해법도 같은 계열이고요. 구분자를 바꾸거나 감싸서, 어디까지가 내용이고 어디부터가 문법인지 분명히 하는 것입니다.
🧪 테스트 세 개를 돌린 것
이 글에서 가장 값어치 있는 부분이 마지막입니다. 짜고 끝내지 않고 세 가지 상황을 실제로 돌려봤어요.
· 정상 송금 — 잔액이 옮겨졌고 내역이 1건 생겼는지
· 잔액 부족 — 실패 메시지가 나오고 잔액이 그대로인지
· 없는 계좌 — 오류 메시지가 나오고 잔액이 그대로인지
뒤의 두 개에서 계좌를 다시 조회하는 게 핵심입니다. "실패했다"는 메시지가 나온 것과 "아무것도 안 바뀌었다"는 건 다른 이야기거든요. 메시지는 실패인데 잔액은 이미 줄어 있는 상황이 실제로 있을 수 있고, 그게 가장 나쁜 버그입니다.
롤백이 걸렸는지를 눈으로 확인한 것이 이 기록을 실습에서 검증으로 올려놓습니다.
🤔 그래서 프로시저를 쓸 것인가
한 가지를 덧붙여야 이 글이 판단 자료가 됩니다. 이 로직을 데이터베이스 안에 둘 것인가, 애플리케이션 코드에 둘 것인가요.
같은 일을 애플리케이션에서도 할 수 있습니다. 트랜잭션을 열고 세 개의 쿼리를 보내고 커밋하면 되니까요. 그런데도 프로시저를 쓰는 이유가 있습니다.
· 왕복이 줄어듭니다 — 애플리케이션에서 하면 쿼리마다 네트워크를 오갑니다. 프로시저는 한 번 부르고 안에서 다 합니다
· 여러 곳에서 같은 절차를 씁니다 — 웹에서도 배치에서도 송금이 필요하면, 로직이 한 군데 있는 게 낫습니다
· 권한을 좁힐 수 있습니다 — 테이블을 직접 고칠 권한 대신 "이 프로시저만 부를 수 있는" 권한을 줄 수 있습니다
대가도 분명합니다.
· 버전 관리가 어렵습니다 — 코드는 저장소에 남는데 프로시저는 데이터베이스 안에 있습니다. 누가 언제 고쳤는지 추적하려면 따로 관리해야 해요
· 테스트가 번거롭습니다 — 애플리케이션 코드처럼 단위 테스트를 붙이기 어렵습니다
· 옮기기 어렵습니다 — 데이터베이스를 바꾸면 프로시저는 다시 써야 합니다
그래서 요즘은 대체로 애플리케이션 쪽에 두는 편입니다. 다만 대량 처리처럼 왕복 비용이 크게 작용하는 자리, 그리고 권한을 좁혀야 하는 자리에서는 여전히 프로시저가 답이에요.
이 글은 그 판단을 하기 전에 알아야 할 것을 갖춰줍니다. 무엇을 할 수 있는지 알아야 쓸지 말지를 정할 수 있으니까요.
🔐 트랜잭션이 지키는 네 가지
송금 예제가 나온 김에 트랜잭션이 실제로 보장하는 것들을 정리해두겠습니다. 이 글이 그중 셋을 코드로 보여주고 있거든요.
· 전부 되거나 전부 안 되기 — 이 글의 롤백이 그것입니다
· 끝나고 나면 규칙이 지켜져 있기 — 잔액의 합이 안 바뀌는 것 같은 조건이요
· 동시에 돌아도 서로 안 섞이기 — 두 사람이 같은 계좌에서 동시에 뺄 때
· 끝났다고 하면 진짜 남아 있기 — 커밋 뒤에 서버가 죽어도 데이터가 남는 것
세 번째가 이 예제에서 안 드러나는 부분인데, 실무에서는 여기서 사고가 많이 납니다.
잔액 100만 원인 계좌에서 두 요청이 동시에 80만 원씩 빼려 한다고 해봅시다. 둘 다 "잔액이 충분한가"를 확인하는 시점에는 100만 원이 보입니다. 그래서 둘 다 통과하고, 결과는 마이너스 60만 원이 되죠.
검사와 갱신 사이에 다른 요청이 끼어드는 것입니다. 이걸 막으려면 확인하는 순간 그 행을 잠가두거나, 갱신할 때 조건을 함께 걸어 잔액이 부족하면 아예 안 바뀌게 해야 합니다.
저자의 코드는 순서대로 실행되는 상황을 다루고 있고, 그것만으로도 프로시저와 트랜잭션의 뼈대를 다 보여줍니다. 동시성은 그다음 단계인데, 이 예제가 그 다음 단계로 이어지기 좋은 자리에 있어요. 은행 송금은 동시성 문제를 설명하기에도 가장 좋은 예제거든요.
📝 원문에서는 이렇게 확인합니다
실패 시나리오에 확인 쿼리를 붙였습니다.
-- 잔액 부족 (철수 -> 영희 500만원) CALL TransferMoney(1, 2, 5000000, @msg); SELECT @msg; -- 'Fail: 잔액 부족.' SELECT * FROM accounts; -- 잔액이 그대로 - 롤백 확인 SELECT * FROM history; -- 기록도 늘지 않음
주석에 "롤백 확인" 이라고 적어둔 게 좋습니다. 무엇을 보려고 이 쿼리를 돌리는지가 코드 안에 남아 있어요.
큐레이터 노트
문법을 보여주려고 고른 예제가 사실은 개념을 가르치는 예제라 뽑았습니다. 송금은 중간에 멈추면 안 되는 일이라, 트랜잭션이 왜 필요한지가 설명 없이 이해됩니다.
그리고 실패 시나리오에서 롤백을 눈으로 확인한 것이 결정적이었어요. 「실패한 시도가 남아 있다」와 「왜 그런지까지 갔다」가 같이 붙습니다. 잘 되는 경우만 보여주는 실습 글과 갈리는 지점입니다.
이분은 7·8·9·10회차에도 계속 나옵니다.
03
🔢 선형대수 5장 연습문제 풀이
최태형 님
5회차에 이어지는 선형대수 연재의 여섯 번째입니다. 이번 장의 주제는 행렬식이에요.
문제 구성이 이렇습니다. 행렬식 구하기, 행렬식이 0이 되는 값 찾기, 역행렬을 갖지 못하는 값 찾기.
4장에서 소거법으로 판정하던 것을, 이번에는 숫자 하나를 계산해서 판정합니다.
앞 회차에서 소개한 그 연재입니다. 4장이 역행렬이었고, 5장이 행렬식이에요. 순서가 정확합니다.
조금 더 들어가 보면
🎯 행렬 전체를 숫자 하나로
행렬식은 정방행렬 하나를 넣으면 숫자 하나가 나오는 계산입니다. 그리고 그 숫자 하나가 아주 많은 것을 알려줍니다.
가장 중요한 건 이겁니다. 0인가 아닌가.
· 0이 아니면 — 역행렬이 있습니다. 되돌릴 수 있는 변환이에요
· 0이면 — 역행렬이 없습니다. 정보가 뭉개진 변환입니다
4장에서 소거법으로 판정하던 것과 결론이 같습니다. 소거했을 때 0인 행이 나오는 행렬은 행렬식도 0이에요. 같은 사실을 다른 방법으로 보는 것이죠.
그래서 저자가 푼 문제들의 형태가 흥미롭습니다. "행렬식이 0이 되기 위한 실수 x를 구하라" 와 "행렬 A가 역행렬을 갖지 못하는 실수 x를 구하라" 가 나란히 나오는데, 사실 같은 문제입니다. 교재가 두 개념이 같은 것을 가리킨다는 걸 문제로 보여주고 있어요.
📏 이 숫자가 갖는 기하학적 뜻
행렬식에는 눈에 보이는 의미가 있습니다. 넓이 또는 부피의 배율이요.
2차 행렬을 평면의 변환으로 보면, 원래 넓이 1인 정사각형이 변환 뒤에 어떤 평행사변형이 됩니다. 그 평행사변형의 넓이가 행렬식의 절댓값입니다. 3차라면 부피고요.
이렇게 보면 "0이면 역행렬이 없다"가 당연해집니다. 넓이가 0이 됐다는 건 평면이 선으로 납작하게 눌렸다는 뜻이니까요. 눌린 것을 다시 펼 방법은 없습니다. 어느 점에서 왔는지 알 수 없거든요.
부호도 뜻이 있습니다. 음수면 뒤집혔다는 것입니다. 거울에 비친 것처럼 방향이 반대가 된 것이죠.
교재는 계산 절차부터 가르치는데, 이 그림을 같이 들고 있으면 문제를 풀다 막혔을 때 답이 말이 되는지 감으로 확인할 수 있습니다.
⚖️ 왜 계산 방법이 여러 개인가
5장에서 배우는 행렬식 계산법은 보통 두 가지입니다. 하나는 한 행이나 열을 기준으로 잘라 작은 행렬식들의 합으로 푸는 방법, 다른 하나는 소거하듯 위쪽만 남기고 대각선을 곱하는 방법이에요.
이 둘의 관계가 5회차에서 이야기한 것과 정확히 같습니다.
· 잘라서 푸는 방법 — 작은 행렬에서 직관적이고, 0이 많은 행이 있으면 아주 빠릅니다. 그런데 차수가 커지면 계산량이 폭발합니다
· 소거해서 푸는 방법 — 절차가 단조롭지만 차수가 커져도 감당할 만하게 늘어납니다
작을 때 편한 방법과 커져도 버티는 방법이 또 갈립니다. 4장의 역행렬에서 봤던 구도가 5장에서 반복되는 것이죠. 교재가 같은 구조를 다른 소재로 두 번 보여주고 있습니다.
🧩 실무에서 이 개념이 나타나는 자리
행렬식이라는 이름은 실무에서 잘 안 보입니다. 그런데 "행렬식이 0에 가깝다" 는 상황은 자주 만납니다. 이름만 다르게요.
· 데이터 분석 — 변수 두 개가 거의 같은 정보를 담고 있으면 계산이 불안정해집니다. 5회차에서 짚었던 그 문제입니다
· 그래픽스 — 변환 행렬의 행렬식이 음수면 면이 뒤집힙니다. 모델이 안쪽이 보이는 상태로 그려지는 원인 중 하나예요
· 수치 계산 — 행렬식이 0에 가까우면 "이 연립방정식은 답이 아슬아슬하다"는 경고가 됩니다. 입력이 조금만 달라져도 답이 크게 흔들립니다
세 경우 다 "되돌릴 수 있는가"를 묻고 있습니다. 5장이 그 질문에 숫자 하나로 답하는 방법을 가르치는 셈이에요.
✋ 손으로 풀 때 붙는 요령들
이 장은 손으로 풀 때 실수가 잦은 자리이기도 합니다. 부호가 계속 번갈아 붙거든요. 그래서 교재와 강의에서 반복해 알려주는 요령이 몇 가지 있습니다.
· 0이 많은 줄을 기준으로 자릅니다 — 어느 행이나 열을 기준으로 삼아도 답은 같습니다. 그러면 0이 가장 많은 줄을 고르는 게 이득이에요. 0이 곱해지는 항은 통째로 사라지니까요
· 먼저 0을 만들어두고 자릅니다 — 한 행에 다른 행의 배수를 더해도 행렬식은 안 변합니다. 그래서 계산 전에 0을 몇 개 만들어두면 훨씬 짧아집니다
· 한 행이 다른 행의 배수면 계산할 것도 없습니다 — 그 자리에서 0입니다
두 번째가 특히 실전적입니다. 4장에서 익힌 행연산을 그대로 쓰는데, 목적이 다릅니다. 4장에서는 단위행렬을 만들려고 했고, 5장에서는 계산을 줄이려고 하는 것이죠.
같은 도구를 다른 목적으로 쓰는 것. 교재가 장을 나눠 가르치는 것들이 실제로는 이렇게 이어져 있습니다. 저자의 풀이에 4장에서 쓰던 연산 표기가 그대로 나오는 것도 그래서고요.
📌 문제 순서가 곧 설명입니다
이 장의 문제들을 순서대로 보면 교재의 의도가 드러납니다.
행렬식을 직접 구하는 문제로 시작해서, 특정 값에서 0이 되는 조건을 찾게 하고, 마지막에 역행렬이 없는 조건을 찾게 합니다. 계산 → 조건 → 다른 이름의 같은 조건 순서예요.
이런 순서를 그대로 통과한 기록이 남으면, 나중에 다시 볼 때 개념의 연결이 같이 남습니다. 답만 적힌 노트와 풀이 과정이 남은 노트의 차이가 여기서 나옵니다.
⚠️ 컴퓨터는 이 판정을 다르게 합니다
5장의 판정 규칙에 실무적인 단서를 하나 붙여두겠습니다. "행렬식이 0인가"를 컴퓨터에게 물으면 거의 항상 "아니오"가 나옵니다.
이유는 소수 계산의 오차입니다. 정확히 0이어야 할 값이 계산 과정에서 아주 작은 수로 남거든요. 그래서 코드에서 행렬식 == 0으로 판정하면 사실상 절대 참이 안 됩니다.
그래서 실제 라이브러리들은 이 질문을 다르게 던집니다. "0인가"가 아니라 "0에 얼마나 가까운가" 로요. 그리고 그 가까움을 재는 별도의 지표를 씁니다.
이게 왜 중요하냐면, 아슬아슬한 경우가 딱 잘라 0인 경우보다 위험하기 때문입니다. 행렬식이 정확히 0이면 계산이 실패하고 사람이 알아챕니다. 그런데 0에 아주 가까우면 계산은 성공하고 답은 엉뚱하게 나옵니다. 입력이 조금만 달라져도 결과가 크게 흔들리고요.
손으로 풀 때는 "영행이 나왔다 / 안 나왔다"로 깔끔하게 갈립니다. 그런데 그 판정을 기계에 옮기면 회색 지대가 생겨요. 이 차이를 알고 있으면 나중에 수치 계산에서 "왜 답이 이렇게 튀지"를 만났을 때 어디를 볼지 알게 됩니다.
교재가 가르치는 판정과 실제 코드의 판정이 어떻게 다른지 — 손으로 한 번 풀어본 사람이 그 다음에 얻을 수 있는 것입니다.
🧷 그리고 실제로는 행렬식을 잘 안 구합니다
한 가지 더 붙이면, 실무 코드에서 행렬식 자체를 구하는 일은 드뭅니다.
역행렬이 있는지 알고 싶으면 행렬식을 구할 게 아니라 그냥 소거를 해보면 됩니다. 소거하다 막히면 없는 것이고, 끝까지 가면 있는 것이니까요. 계산량도 소거 쪽이 적습니다.
연립방정식을 풀 때도 마찬가지입니다. 역행렬을 구해서 곱하는 것보다 그냥 소거로 푸는 게 빠르고 정확합니다. 역행렬을 만드는 과정에서 오차가 한 번 더 끼거든요.
그래서 수치 계산 라이브러리들은 "역행렬을 구하지 말고 방정식을 풀라"고 안내합니다. 수식에 역행렬이 적혀 있어도 코드에서는 다르게 구현하는 것이죠.
그럼 5장은 왜 배우는가. 계산 방법 자체보다 판정 기준과 그 의미를 얻기 위해서입니다. 행렬식이 0이라는 게 무슨 뜻인지, 부호가 무엇을 말하는지, 값이 작다는 게 왜 위험한지요.
수식은 이해를 위한 것이고 구현은 다른 절차를 씁니다. 이 구분을 아는 것도 교재를 한 번 통과한 사람이 얻는 것 중 하나예요.
이 구분이 있으면 라이브러리 문서를 읽을 때도 달라집니다. "역행렬을 구하는 함수"와 "연립방정식을 푸는 함수"가 따로 있는 이유가 보이거든요. 수식만 보고 있으면 둘이 같은 일로 보이는데, 어느 쪽을 부르느냐에 따라 속도와 정확도가 달라집니다. 그리고 문서에는 대개 "가능하면 이쪽을 쓰라"는 안내가 한 줄 붙어 있고요. 그 한 줄이 왜 있는지 아는 것과 모르는 것의 차이입니다.
📝 원문에서는 이렇게 씁니다
문제 목록 자체가 이 장의 구조를 보여줍니다.
4. 행렬식이 0이 되기 위한 실수 x를 구하라.
5. 행렬 A가 역행렬을 갖지 못하는 실수 x를 구하라.
계산 → 조건 찾기 → 다른 이름으로 같은 조건 찾기 순서입니다. 4번과 5번이 같은 문제라는 걸 눈치채는 순간이 이 장의 핵심이고요.
그리고 풀이는 4장과 같은 방식입니다. 중간 단계를 한 줄도 건너뛰지 않고, 무슨 연산을 했는지 화살표마다 적어둡니다.
큐레이터 노트
진도가 이어지고 있다는 것 자체가 근거가 되는 기록입니다. 4장의 역행렬을 5장의 행렬식으로 이어받았고, 두 장이 사실 같은 것을 다르게 본다는 걸 문제를 통해 통과했어요.
한 편만 놓고 보면 연습문제 풀이인데, 회차를 쌓아 놓으면 한 학기가 그대로 남아 있습니다. 「시리즈로 이어진다」가 이 기록의 전부이자 값어치예요. 8·9·10회차에서 계속 만나게 됩니다.
💡 세 편을 겹쳐 읽으며
여러 단계를 한 덩어리로 묶습니다
세 편이 각자의 자리에서 같은 동작을 합니다.
박현구 님의 프로시저는 세 개의 SQL을 한 덩어리로 묶습니다. 전부 되거나 전부 안 되게요. 노현주 님은 버전 두 단계를 한 번의 이관으로 바꿉니다. 최태형 님이 푼 행렬식은 행렬 전체를 숫자 하나로 압축합니다.
묶으면 뭐가 좋아지느냐면, 중간 상태를 신경 쓰지 않아도 된다는 것입니다. 트랜잭션 안에서는 절반만 된 상태를 아무도 못 봅니다. 이관은 끝났거나 안 끝났거나 둘 중 하나고요. 행렬식은 0인지 아닌지만 보면 됩니다.
중간 상태가 없으면 판단이 쉬워집니다. 그리고 판단이 쉬워지면 실수가 줍니다.
실패했을 때 어디로 돌아갈지 정해뒀습니다
세 편 중 둘이 이 이야기를 직접 합니다.
박현구 님은 롤백을 걸고 잔액이 그대로인지 눈으로 확인했습니다. 노현주 님은 원본을 건드리지 않는 방식을 골라서 실패해도 기존 서버가 그대로 돌아가게 했고요.
세 번째도 결이 같습니다. 행렬식이 0이 아니라는 건 되돌릴 수 있다는 뜻이니까요.
되돌릴 수 있게 만들어두는 일이 4기 후반 회차에서 계속 나옵니다. 5회차의 무상태 서버도 같은 자리였어요.
안에 든 것과 바깥의 문법이 섞이는 문제
작은 것 하나가 또 겹칩니다. 박현구 님이 DELIMITER를 바꾼 이유요.
프로시저 본문 안의 세미콜론이 바깥 명령의 끝으로 읽히는 문제인데, 4회차에서 노현주 님이 다룬 CDATA와 정확히 같은 형태입니다. 데이터에 든 <가 XML 태그로 읽히는 것이요.
같은 분이 다른 회차에서 같은 모양의 문제를 만난 셈입니다. 경계를 분명히 하지 않으면 안에 든 것이 바깥 문법으로 읽힙니다. 이 형태를 한 번 알아두면 SQL이든 XML이든 셸이든 같은 눈으로 보게 됩니다.
이번 회차에서 가져갈 것
1. 여러 번 고치는 작업은 한 덩어리로 묶기.
계좌 두 개를 고치고 기록을 남기는 일은 셋이 아니라 하나여야 합니다. 중간에 멈춘 상태가 존재할 수 있다면 그건 아직 안 묶인 것입니다.
2. 예상한 실패와 예상 못 한 실패를 나눠 다루기.
잔액 부족은 이름을 붙여 돌려주고, 그 밖의 오류는 핸들러로 잡아 안전하게 멈추세요. 로그를 볼 때 둘이 구분돼 있어야 무엇을 봐야 하는지 압니다.
3. 실패 시나리오에서는 "실패했다"가 아니라 "안 바뀌었다"를 확인하기.
메시지는 실패인데 데이터는 이미 바뀐 상태가 가장 나쁩니다. 실패 테스트 뒤에 원래 상태를 다시 조회하세요.
4. 운영 중인 것을 옮길 때는 원본을 건드리지 않는 쪽으로.
제자리에서 고쳐 올리는 방식은 중간에 실패하면 돌아갈 곳이 없습니다. 새 곳에 붓는 방식은 느려도 원본이 남습니다.
5. 옮긴 뒤에는 목록이 아니라 개수로 확인하기.
명령이 오류 없이 끝난 것과 데이터가 다 온 것은 다릅니다. 옮기기 전 개수를 적어두고 비교하세요.
4기 6회차는 2025년 12월이었습니다.
데이터베이스 이관과 프로시저 실습과 전공 교재 풀이라는 서로 다른 자리에서, 세 분이 나란히 여러 단계를 한 덩어리로 다루는 이야기를 남겼습니다. 그리고 셋 다 실패했을 때 어디로 돌아갈지를 함께 적었어요.
성장일지는 멤버들이 2주에 한 번씩 자신의 성장을 기록하는 활동이에요. 지난 기수의 성장일지를 다시 읽으면서, 그때 소개해드리지 못한 글을 하나씩 꺼내고 있습니다.
좋은 글 남겨주신 노현주 님, 박현구 님, 최태형 님께 감사드립니다. 그리고 4기를 함께 채워주신 모든 멤버분들께도요! 😊
다음 큐레이션으로 다시 찾아오겠습니다! 🌱
- 에디터 · 성장일지 큐레이터 -
※ 본 큐레이션은 각 저자가 공개한 글을 소개하는 것이며, 모든 원문의 저작권은 저자에게 있습니다. 저자 본인의 요청이 있을 경우 즉시 수정 또는 삭제합니다.