본문 바로가기

web/Django

Django migrate model 칼럼 추가시 null=True는 가급적 쓰지 말자

 

1
2
3
4
You are trying to add the field 'created' with 'auto_now_add=True' to greentariffs without a default; the database needs something to populate existing rows.
 
 1) Provide a one-off default now (will be set on all existing rows)
 2) Quit, and let me add a default in models.py
cs

django 마이그레이션시 칼럼을 추가할때 종종 위와 같이 경고 메시지를 볼수 있다.

구글에서 검색해 보면 한글 블로그 대부분이 칼럼에 null=True를 추가하면 해결된다고 하는데,

이는 정말 null이 들어가도 되는 칼럼에만 사용해야 한다.

 

먼저 해결 방법은 1번을 누른 후 디폴트로 들어갈 값을 넣어주면 끝난다. (현재 날짜로 넣을 경우는 아래와 같이)

위와 같이 경고 메시지가 나오는 경우는 이미 테이블에 데이터가 있으며, 칼럼 추가시 디폴트 값을 django에서는 알지 못하기 때문에 테이블에 칼럼을 추가하지 못하는 상황인것이다.

편하게 null=True하면 끝나는데 그러면 왜 안되는냐? (null=True가 무조건 잘못 되었다는것은 아니다. 상황에 맞게 써야 한다)

 

 

1. NULL

RDB에서 null은 피하라고 한다. “릴레이션에서 null이란 개념이 존재하지 않기 때문이다” null은 관계형 모델에는 존재하지 않고, 테이블에만 존재한다. 또한 null을 가진 테이블은 1NF의 조건을 만족하지 않는다.

NULL은 값이 없는것이 아닌 값이 없는 존재이기 때문이다.

따라서 null=True로 했을 경우 쿼리 작성시 매번 null 체크를 하는 수 밖에 없다

select * from user where age <> 20 and age is null

null을 사용하면 안되는 가장 큰 이유는 관계형 모델을 해치는 존재이기 때문이다.

null은 현시점에서는 알수 없는 값이다. 어떤 행에 일치할지도 모르고, 일치하지 않을지도 모른다. NULL을 사용한 연산 결과는 NULL이 되어 버리기 때문이다.

NULL이 포함되어 있다면 모든 질의를 릴레이션의 연산만으로 해결할수 있다는 전제가 무너지게 된다.

 

2. 옵티마이저의 폐해

null의 영향은 쿼리의 실행계획인 옵티마이저에게도 영향을 끼친다.

null이 있는 인덱스 항목은 인덱스 상에서도 제일 앞 또는 뒤쪽에 몰아서 배치된다. 실행계획에서는 is null을 해결하기 위해서 인덱스의 제일 앞 부분이나 제일 뒷부분을 스캔해야 한다. 어느 정도 null이 아닌 값이 분산되어 있어도(카디날리티가 높아도) 인덱스 상의 칼럼이 null인 모든 행은 스캔하게 된다. 결국 null 값이 늘어갈 수록 스캔 시간이 늘어난다.

물론 옵티마이저의 실행 비용이 완벽한 것은 아니지만 null로 인해서 최적의 비용은 도출 할수 없게 된다.

 

3. NULL 을 사용해도 좋을때

현실 세계를 관계형 모델링으로 표현이 불가능 하므로 NULL은 관계형 모델을 해치지만 관계형 모델이 아닐 경우엔 사용해도 상관 없다.

 

결론 : 관계형 모델 빡시게 할려면 값을 잘 넣고 정규화를 잘하면 된다.

참고 : 관계형 데이터베이스 실전 입문 (http://www.yes24.com/Product/Goods/29343536)