어떤 기능을 변경하다 보면, 테이블에 컬럼 추가가 필요한 경우가 있다.
보통은 운영DB 변경을 먼저하고 소스 배포가 나가고 소스 배포가 밀리는 경우, 운영 DB가 변경되고 소스는 AS-IS인 채로 며칠이 지나가기도 한다.
그럴 때 주의해야겠다고 느낀 점에 대해서 적어보려고 한다.
not null 옵션을 주어야하는지 고려
not null이 꼭 필요한지 고려해보자.
JPA 같은 ORM을 쓰고 있는 상태에서 AS-IS 소스가 동작하면 save() 메서드가 호출되면서 insert 쿼리가 나갈 때 새로 추가된 컬럼에 값이 지정돼 있지 않은 쿼리가 나가게 된다.
이때 새롭게 추가된 컬럼이 not null이라면? 값이 지정돼 있지 않기 때문에 에러가 발생한다.
(정확히는 해당 컬럼에 default 옵션이 걸려있지 않을 때, default 값이 없다는 에러를 내뱉는다.)
not null이 걸려있지 않은 컬럼의 경우, NPE 가능성도 고려
'그러면 not null을 안걸면 되는거 아냐?' 라고 생각할 수 있지만
null이 들어갈 수 있는 컬럼의 경우 NPE 가능성이 있으므로 조심해야한다.
not null, default를 걸지 않은 컬럼을 추가하는 경우, 기존 row들의 해당 컬럼은 모두 NULL로 채워지기 때문이다.
(Int든, bigint든, varchar든 마찬가지이다.)
⭐️ 컬럼 추가시에는 default 옵션을 주자
not null이라면 반드시 default 옵션을 주어야, insert 쿼리에 해당 컬럼이 빠져있어도 에러가 나지 않는다.
nullable한 컬럼이더라도, default 옵션이 있어야 기존 데이터들의 해당 컬럼이 null로 채워지지 않기 때문에 NPE를 방지할 수 있다.
컬럼 정의기존 row에 들어가는 값
| CASE | 채워지는 값 |
| INT (NULL 허용, DEFAULT 없음) | NULL |
| BIGINT (NULL 허용, DEFAULT 없음) | NULL |
| INT DEFAULT 0 | 0 |
| BIGINT DEFAULT 0 | 0 |
| INT NOT NULL DEFAULT 0 | 0 |
| INT NOT NULL (DEFAULT 없음) | 모드에 따라 에러가 날수도, 안날수도 있음 |
결론: 기존 데이터가 있는 테이블에 새로운 컬럼 추가를 해야하는 경우, default 0, default ""과 같은 설정을 반드시 주자.
(물론 적절한 default 값은 상황에 맞게 지정을 해야함)
왜 ALTER 문 적용시에는 몰랐을까?(=에러가 안났을까?)
alter table user add column password3 int after password;
대충 이런식의 alter문을 날렸었는데, 아무런 문제없이 컬럼이 추가됐고, 기존 데이터에는 다 0이 들어가 있었다.
Mysql 8점대의 implicit default(묵시적 기본값) 또는 8점대에서 기본으로 적용되는 ALGORITHM=INSTNAT 모드 때문이 아닐까 추측해본다.
gpt한테 물어보니 이런 말을 했음

정리하자면, ALGORITHM=INSTANT는 실제 row에 값을 쓰는 방식이 아님.
이 INSTANT 방식은 컬럼의 추가 위치가 맨 뒤일때 적용된다고 알려져있지만, 8.0.29 이후 버전에서는 중간에 추가되는 컬럼이어도 최적화가 가능하다고 함.
따라서 INSTANT로 인해 실제 row가 변경된 것이 아니므로 ALTER문을 날릴 때 에러가 나지 않았고, '0'이라는 값으로 채워진 이유는 암묵적 기본값(implicit default) 때문이다.
8.0.29 버전 릴리즈 노트. ALGORITHM=INSTANT에 대한 내용에서, 컬럼이 추가되는 위치와 상관없이 ALGORITHM=INSTANT 적용될 수 있다는 내용 써있음
https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-29.html?utm_source=chatgpt.com
MySQL :: MySQL 8.0 Release Notes :: Changes in MySQL 8.0.29 (2022-04-26, General Availability)
MySQL 8.0 Release Notes / Changes in MySQL 8.0.29 (2022-04-26, General Availability) Changes in MySQL 8.0.29 (2022-04-26, General Availability) Important This release is no longer available for download. It was removed due to a critical issue that coul
dev.mysql.com
https://dev.mysql.com/doc/refman/9.1/en/data-type-defaults.html?utm_source=chatgpt.com
MySQL :: MySQL 9.1 Reference Manual :: 13.6 Data Type Default Values
13.6 Data Type Default Values Data type specifications can have explicit or implicit default values. A DEFAULT value clause in a data type specification explicitly indicates a default value for a column. Examples: CREATE TABLE t1 ( i INT DEFAULT -1, c VAR
dev.mysql.com
그러면 왜 DML(insert문)을 날릴 때는 에러가 났을까?
그건 STRICT_TRANS_TABLES 모드 때문으로 추정한다.
이 모드는 default 없는 not null 컬럼에 값이 지정돼있지 않으면 에러를 내는데, 이는 DDL에는 적용되지 않는다고 함
공식문서는 아니지만 아래 스택 오버플로우에서 따봉 많이 받은 글에 그렇게 쓰여있다..

https://stackoverflow.com/questions/22868345/mysql-add-a-not-null-column?utm_source=chatgpt.com
MySQL add a NOT NULL column
I am adding a column to a table: ALTER TABLE t ADD c varchar(10) NOT NULL; The column gets added, and each record has the empty string. Is this expected to work this way under all conditions (str...
stackoverflow.com
GPT의 말이 뭔가 시원하진 않지만... 그래도 저런 상황이라서 DDL 적용시에는 에러가 발생하지 않고, DML이 나갈때 에러가 났다고 보는게 가장 맞을 것 같다.
⭐️ AS-IS 소스를 dev 환경에 올려서 확인해보기
AS-IS 소스(변경전 소스)를 dev환경(또는 stg환경)에 올려서 DB 변경만 되고 소스 변경이 되지 않은 상황에 에러없이 제대로 동작하는지도 꼭 확인해봐야겠다.
정리하자면,
- 컬럼 추가 시에는 NPE, not null 컬럼을 주의
- 웬만하면 default 값 주자.
- DB 변경된 상태에서 이전 버전 dev/stg에 올려서 확인해보자.
지금까지 멍청이의 회고였습니다.