SQL INSERT, SELECT 제대로 이해하기
들어가는 말
최근 데이터베이스를 다뤄오면서 느끼는 것이 있다. SQL을 처음 배우는 사람들이 가장 많이 틀리는 지점은 문법이 아니라는 것이다.
INSERT, SELECT 문법은 구글 검색 한 번이면 바로 찾을 수 있다. 진짜 문제는 “이 명령어가 데이터에 어떤 영향을 미치는지”를 제대로 이해하지 못한 채 쿼리를 실행하는 것이다. SELECT 하나 잘못 짜면 불필요한 데이터를 수백만 건 끌어오고, INSERT 하나 잘못 짜면 운영 데이터에 쓰레기 값이 쌓인다. 이 글은 MySQL의 가장 기본 명령어인 SELECT와 INSERT를 단순히 문법 차원이 아니라, 실무에서 어떻게 사용해야 하는지의 관점으로 정리한다.
SELECT: 데이터를 “읽어오는 작업”의 기본
SELECT는 테이블에 저장된 데이터를 조회하는 명령어다. 처음 배울 때 가장 먼저 접하는 형태는 다음과 같다.
SELECT * FROM users;
이 쿼리는 users 테이블의 모든 데이터를 가져온다. 문법적으로는 완벽하게 맞다. 하지만 실무에서 이 형태를 그대로 사용하는 개발자는 없다고 봐도 무방하다. 이유는 단순하다. 테이블에 컬럼이 수십 개 있고 레코드가 수백만 건이라면, 지금 당장 필요하지 않은 데이터까지 전부 끌어오게 된다. 이는 네트워크 비용과 메모리 낭비로 직결된다.
실무에서는 반드시 필요한 컬럼만 명시적으로 지정해서 조회하는 것이 기본 원칙이다.
SELECT name, email FROM users;
이처럼 컬럼을 지정하면 조회 범위가 명확해지고, 나중에 이 쿼리를 다시 읽는 사람도 “이 쿼리가 무엇을 위한 것인지”를 즉시 파악할 수 있다. 유지보수성 측면에서도 매우 중요한 습관이다.
여기에 WHERE 조건절을 더하면 진짜 실무에서 통용되는 쿼리에 가까워진다.
SELECT name, email FROM users WHERE age >= 20;
WHERE 조건은 단순히 데이터를 걸러내는 기능이 아니다. 인덱스가 걸려 있는 컬럼에 조건을 걸면 풀 스캔 없이 빠르게 결과를 가져올 수 있다. 반면 인덱스가 없는 컬럼에 복잡한 조건을 걸면 테이블 전체를 읽어야 하기 때문에 성능이 급격히 떨어진다. SELECT를 제대로 이해한다는 것은 단순히 어떤 데이터를 가져올지가 아니라, 어떻게 가져오는지까지 고민하는 것을 의미한다.
한 가지 더 강조하고 싶은 것은, SELECT는 “데이터 필터링 도구”라는 관점으로 이해해야 한다는 점이다. 테이블에 있는 데이터를 그냥 가져오는 것이 아니라, 내가 원하는 데이터만 정확하게 정의해서 끌어오는 것이 SELECT의 본질이다. 이 관점으로 접근하면 이후에 배우게 되는 JOIN이나 GROUP BY, 서브쿼리도 자연스럽게 연결된다.
INSERT: 데이터를 “남기는 작업”의 기본
INSERT는 테이블에 새로운 데이터를 추가하는 명령어다. 기본적인 형태는 다음과 같다.
INSERT INTO users (name, email) VALUES ('홍길동', 'test@test.com');
간단해 보이지만, 여기에도 반드시 지켜야 할 원칙이 있다. 첫째, 컬럼 목록과 VALUES의 순서는 반드시 일치해야 한다. 순서가 어긋나면 값이 엉뚱한 컬럼에 들어가거나, 데이터 타입 오류로 쿼리가 실패한다. 둘째, NOT NULL 제약이 걸려 있는 컬럼은 반드시 값을 넣어야 한다. 이를 누락하면 INSERT 자체가 실패한다.
실무에서는 단건 INSERT보다 다중 INSERT가 훨씬 많이 사용된다.
INSERT INTO users (name, email) VALUES
('홍길동', 'a@test.com'),
('김철수', 'b@test.com'),
('이영희', 'c@test.com');
이 방식은 데이터를 한 건씩 여러 번 INSERT하는 것보다 훨씬 효율적이다. 데이터베이스 커넥션을 반복적으로 맺고 끊는 오버헤드가 없고, 트랜잭션 처리 비용도 줄어든다. 대량의 초기 데이터를 넣거나 배치 작업을 처리할 때 이 방식은 거의 필수적으로 사용된다.
초보 단계에서 자주 발생하는 실수 중 하나는 INSERT 후에 커밋(COMMIT) 여부를 확인하지 않는 것이다. MySQL의 기본 설정은 AutoCommit이 켜져 있어서 별도 처리 없이도 반영되지만, 트랜잭션을 명시적으로 시작한 경우에는 커밋을 하지 않으면 데이터가 실제로 저장되지 않는다. 데이터를 넣었는데 조회가 안 된다면 가장 먼저 커밋 여부를 확인해야 한다.
INSERT SELECT: 읽으면서 동시에 저장하는 방식
SELECT와 INSERT를 따로 배웠다면, 이 둘이 결합된 형태를 이해하는 것이 다음 단계다. 바로 INSERT SELECT 구문이다.
INSERT INTO backup_users (name, email)
SELECT name, email FROM users WHERE age >= 20;
이 쿼리는 users 테이블에서 조건에 맞는 데이터를 조회한 뒤, 그 결과를 backup_users 테이블에 바로 삽입한다. 별도의 중간 작업 없이 SELECT의 결과가 곧 INSERT의 입력이 된다. 대량 데이터 이관, 특정 조건을 만족하는 데이터만 별도 테이블에 분리하는 작업, 혹은 로그 테이블에서 요약 데이터를 뽑아 집계 테이블에 저장하는 경우 등에서 이 구문이 매우 자주 활용된다.
실무에서 이 구문을 사용할 때 반드시 점검해야 할 사항이 두 가지 있다.
첫째는 컬럼 구조의 일치 여부다. SELECT로 가져오는 컬럼과 INSERT 대상 테이블의 컬럼이 데이터 타입과 순서 모두 일치해야 한다. VARCHAR(50) 컬럼에서 끌어온 값을 INT 컬럼에 넣으려 하면 오류가 발생하거나 데이터가 잘려서 저장된다. 특히 날짜, 숫자, 문자열 타입이 혼재할 경우 반드시 DESCRIBE 명령으로 양쪽 테이블의 구조를 미리 확인하는 것이 좋다.
둘째는 WHERE 조건의 정확성이다. SELECT에서 조건을 잘못 설정하거나 아예 누락하면, 의도하지 않은 데이터가 대량으로 삽입될 수 있다. 운영 환경에서 이런 실수가 발생하면 데이터 정합성이 깨지고, 원상복구에 많은 시간이 소요된다. 이 구문을 처음 실행할 때는 반드시 SELECT 부분만 먼저 단독으로 실행해서 결과를 확인한 뒤, 문제가 없다고 판단될 때 INSERT SELECT 전체를 실행하는 습관을 들여야 한다.
실무에서 이 두 가지를 바라보는 관점
경험상 SELECT와 INSERT를 별개의 명령어로 외우는 사람은 일정 수준 이상에서 성장이 멈추는 경우가 많다. 이 두 가지는 데이터 흐름의 양 끝단이다. SELECT는 데이터를 읽어오는 행위이고, INSERT는 데이터를 기록으로 남기는 행위다. 그리고 INSERT SELECT는 읽으면서 동시에 새로운 기록을 만들어내는 행위다. 이 흐름을 이해하면 이후에 나오는 UPDATE, DELETE, MERGE, 심지어 복잡한 ETL 파이프라인 설계도 같은 맥락에서 이해할 수 있다.
또한 SELECT와 INSERT를 익힐 때 성능에 대한 감각도 함께 길러야 한다. 아무리 정확한 쿼리라도 느리면 실무에서 쓸 수 없다. WHERE 조건에 인덱스가 걸려 있는지, 한 번에 처리하는 데이터 양이 적절한지, 트랜잭션 범위가 너무 넓지 않은지를 항상 염두에 두고 쿼리를 작성하는 것이 장기적으로 훨씬 중요하다.
마무리하며
SELECT와 INSERT는 SQL의 시작점이지만, 이 두 가지를 제대로 이해하고 실무 수준으로 다룰 수 있다면 데이터베이스 작업의 절반은 완성된 것이나 다름없다. 문법을 외우는 것보다 데이터가 어디서 오고, 어디로 가고, 그 과정에서 어떤 조건과 구조가 작동하는지를 이해하는 것이 핵심이다. 이 기반이 탄탄하게 잡혀야 이후에 배우게 되는 JOIN, GROUP BY, 인덱스 설계, 쿼리 최적화가 자연스럽게 이어진다. 기본을 얕보지 말고, 지금 당장 사용하고 있는 SELECT와 INSERT 하나하나를 다시 점검해보길 권한다.
Add your first comment to this post