데이터베이스 작업은 마치 개발자 인생 같아: 예상치 못한 일 투성이야. 아무리 경험 많은 개발자라도 실수할 수 있어. 예를 들면, 데이터를 실수로 다 지운다든지, 중복을 넣으려고 한다든지, 무결성 제약을 어긴다든지. 중요한 건 이런 실수를 피하는 것뿐만 아니라, 만약에 실수했을 때 어떻게 복구할지 아는 거야. 자, 대표적인 실수 몇 가지를 같이 보자.
실수 1: WHERE 조건문 빠뜨리기
이건 진짜 고전적인 실수야. 초보자들이 자주 하고, 솔직히 말해서 가끔은 경험자도 해. 바로 WHERE를 업데이트나 삭제 쿼리에 안 넣는 거지. WHERE 없는 쿼리는 테이블의 모든 행을 업데이트하거나 삭제해버려.
-- 이렇게 하면 안 돼:
UPDATE students SET status = '졸업함';
-- 또는 이렇게:
DELETE FROM students;
결과: 이런 쿼리 날리고 나서 students 테이블이 텅 비었다는 걸 알게 되면 진짜 멘붕이야. 백업이나 트랜잭션 안 썼으면 복구도 못 해. (트랜잭션 썼어도 이미 스트레스지...)
예방 방법: UPDATE나 DELETE 쿼리에는 항상 조건을 넣어서, 어떤 행을 바꾸거나 지울지 명확하게 지정해.
-- 이렇게 해야 해:
UPDATE students
SET status = '졸업함'
WHERE year_of_study = 4;
DELETE FROM students
WHERE status = '퇴학당함';
또 하나 팁 — 삭제하기 전에 항상 SELECT로 조건이 맞는지 먼저 확인해봐:
-- 먼저 확인:
SELECT * FROM students WHERE status = '퇴학당함';
-- 그 다음 삭제:
DELETE FROM students WHERE status = '퇴학당함';
실수 2: 데이터 유니크 제약(UNIQUE) 위반
테이블에 UNIQUE 제약이 걸려 있으면, 중복된 값을 넣으려고 하면 에러가 나.
-- email 중복 때문에 에러:
INSERT INTO students (name, email) VALUES ('Otto Lin', 'otto.lin@email.com');
INSERT INTO students (name, email) VALUES ('Peter Pen', 'otto.lin@email.com');
에러:
ERROR: duplicate key value violates unique constraint "students_email_key"
예방 방법: 데이터를 넣기 전에 이미 같은 값이 있는지 먼저 체크해봐.
-- 이런 식으로:
SELECT * FROM students WHERE email = 'otto.lin@email.com';
-- 아니면 UPSERT 써도 돼:
INSERT INTO students (name, email)
VALUES ('Peter Pen', 'otto.lin@email.com')
ON CONFLICT (email) DO NOTHING;
실수 3: 무결성 제약(FOREIGN KEY) 위반
예를 들어, students랑 enrollments 두 테이블이 있다고 해보자. enrollments의 student_id는 students의 id랑 외래키로 연결돼 있어. 만약 students에 없는 student_id로 enrollments에 값을 넣으려고 하면 에러가 나.
INSERT INTO enrollments (student_id, course_id)
VALUES (999, 101); -- 에러, student_id 999는 없음
예방 방법?
- 연관된 테이블에 값 넣기 전에 부모 테이블에 해당 값이 있는지 항상 체크해:
SELECT * FROM students WHERE id = 999;
ON DELETE CASCADE제약을 써서, 부모 테이블에서 삭제하면 연관된 테이블에서도 자동으로 삭제되게 할 수 있어 (근데 이건 조심해서 써야 해).
CREATE TABLE enrollments (
id SERIAL PRIMARY KEY,
student_id INT REFERENCES students(id) ON DELETE CASCADE,
course_id INT
);
실수 4: 잘못된 데이터 타입
데이터를 넣거나 업데이트할 때 PostgreSQL은 타입을 엄격하게 체크해. 숫자 필드에 문자열을 넣으려고 하면 에러가 나.
-- 타입 안 맞아서 에러:
INSERT INTO students (id, name) VALUES ('abc', 'Alex Go');
에러:
ERROR: invalid input syntax for type integer
예방 방법? 넣는 값의 타입을 항상 신경 써. 특히 사용자 폼에서 데이터가 들어올 때는, 앱 쪽에서 꼭 검증해줘야 해.
실수 5: 동시 접근 문제(데이터 유출)
두 명의 사용자가 동시에 같은 테이블의 같은 행을 업데이트하려고 한다고 상상해봐. 트랜잭션 격리 수준이 제대로 안 되어 있으면 충돌이 날 수 있어.
-- 사용자 A:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 사용자 B:
BEGIN;
UPDATE accounts SET balance = balance - 50 WHERE id = 1;
예방 방법? 트랜잭션이랑 격리 수준을 잘 써서, 동시에 데이터가 바뀌는 걸 막아야 해.
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;
실수 6: TRUNCATE로 데이터 날림
TRUNCATE는 테이블의 모든 행을 복구 불가하게 싹 지워버려. 이 명령은 ROLLBACK도 안 되고, 트리거도 안 타고, 바로 실행돼.
-- 진짜 다 지워짐:
TRUNCATE TABLE students;
예방 방법: TRUNCATE 대신 조건을 붙인 DELETE를 써서, 필요하면 롤백할 수 있게 해.
BEGIN;
DELETE FROM students WHERE year_of_study = 1;
-- 마음이 바뀌면:
ROLLBACK;
실수 7: 중요한 작업에 트랜잭션 안 쓰기
여러 단계로 이루어진 복잡한 작업을 할 때, 중간에 에러가 나면 데이터가 일관성 없는 상태로 남을 수 있어.
-- 1단계: 학생 추가
INSERT INTO students (name, email) VALUES ('Otto Lin', 'otto.lin@email.com');
-- 2단계: 수강신청
INSERT INTO enrollments (student_id, course_id) VALUES (LASTVAL(), 101); -- 에러
예방 방법? 이런 작업은 꼭 트랜잭션으로 묶어줘:
BEGIN;
INSERT INTO students (name, email) VALUES ('이반 이바노프', 'ivan.ivanov@email.com');
INSERT INTO enrollments (student_id, course_id) VALUES (LASTVAL(), 101);
COMMIT;
어느 단계에서든 에러가 나면, 이렇게 롤백할 수 있어:
ROLLBACK;
실수 8: NULL을 대충 다루기
NULL은 진짜 함정이야. 0도 아니고, 빈 문자열도 아니고, 비교 연산하면 예상 못한 결과가 나올 수 있어.
-- 이건 안 됨:
SELECT * FROM students WHERE email = NULL;
예방 방법? IS NULL이나 IS NOT NULL을 써야 해:
SELECT * FROM students WHERE email IS NULL;
이런 실수들은 피할 수 없어. 하지만 어떻게 알아채고, 어떻게 피할지 알면 데이터 작업을 더 안전하고 효율적으로 할 수 있어. PostgreSQL은 엄격하지만 공정하게 네 데이터를 지켜주는 수호자야. 뭔가 잘못되면 바로 에러를 던져주지. 기억해, 실수는 적이 아니라 선생님이야.
GO TO FULL VERSION