널이 될 수없는 필드에 대해 PostgreSQL에서 NOT NULL을 지정하지 않은 결과는 무엇입니까?


10

테이블의 필드 대부분이 항상 null이 아니지만이 테이블의 스키마가 이것을 강제하지 않는 응용 프로그램 (데이터가 PostgreSQL에 저장 됨)이 있습니다. 예를 들어이 가짜 테이블을보십시오.

CREATE TABLE "tbl" (
    "id" serial,
    "name" varchar(40),
    "num" int,
    "time" timestamp
    PRIMARY KEY ("id"),
    UNIQUE ("id")
);

또한 name, num, time명시 적으로 언급되지 않은 NOT NULL그들이 실제로 시행 응용 프로그램 측에서 발생하기 때문에.


내 느낌은 그것이 변경되어야한다는 것입니다. 그러나 반격 점은 응용 프로그램 수준이 null 값을 여기에 표시 할 수 없으며 다른 사람은 테이블을 수동으로 수정하지 않는다는 것입니다.

내 질문은 : 성능, 스토리지, 일관성, 그 밖의 다른 이점과 단점 (현재 Null이 없음을 이미 확인했으며 비즈니스 논리에서 Null이 없어야한다고 가정 함) 명시 적 NOT NULL제약?

우리는 좋은 코드 검토 프로세스와 합리적으로 좋은 문서를 가지고 있기 때문에 일부 새로운 사람이이 제약 조건을 어기는 무언가를 저지를 가능성은 실제로 변경을 정당화하기에 충분하지 않습니다.

이것은 내 결정이 아니므로 다른 정당화를 찾는 이유입니다. 내 의견으로는, 무언가가 null이 될 수없고 데이터베이스가 무언가가 null이 아닌 것을 지정할 수 있다면-그냥하십시오. 특히 변경이 매우 간단한 경우.


1
Null 및 디스크 공간 고려 사항에 대해서는이 답변을 참조하십시오. stackoverflow.com/questions/5008753/… 간단히 말해, 테이블에 8 개 이상의 열과 1 개 이상의 nullable 열이 있으면 모든 열이 1보다 많은 경우보다 테이블에 행당 더 많은 바이트가 필요합니다. 널이 아님을 정의했습니다.
ypercubeᵀᴹ

1
@ ypercubeᵀᴹ : 정확하게, 널 비트 맵은 에 실제 널값이있는 경우 에만 행당 추가 됩니다 : stackoverflow.com/a/7654497/939860 . 따라서 NOT NULL제한 조건은 스토리지 크기에 직접적인 영향을 미치지 않습니다. 물론 모든 열이 정의 된 상태 NOT NULL에서 시작하기 위해 null 비트 맵이있을 수 없습니다. 반면에 , 널 비트 맵이 비교적 더 작기 때문에 (값이 희소 한 경우는 제외) 실제 값이없는 열에 대해 "빈"또는 더미 값 대신 NULL을 사용하는 경우 스토리지 크기는 일반적으로 훨씬 작습니다 .
Erwin Brandstetter 2016 년

@ ErwinBrandstetter 그때 내 나쁜 부분을 이해하지 못했습니다. 따라서 null 값이없는 열의 경우 NULL 또는 NOT NULL로 정의하든 저장 공간에 차이가 없습니다. 맞습니까? 인덱스 스토리지 공간도 마찬가지입니까?
ypercubeᵀᴹ

5
"응용 프로그램 수준에서는 null 값이 여기에 표시 되지 않도록합니다. " 아니요, 그렇지 않습니다. 그것은 수있는 하나의 응용 프로그램이 null을 삽입하지 않습니다 있는지 확인하십시오. 그러나 psql (예 :)이 있으며 응용 프로그램에 대해 알지 않고도 의도적으로 실수로 null을 삽입 할 수 있습니다.
Mike Sherrill 'Cat

5
아무도 테이블을 수동으로 수정하지 않도록 할 수있는 유일한 응용 프로그램은 dbms 자체입니다.
Mike Sherrill 'Cat Recall'9

답변:


9

새로운 프로그래머가 도착하여 해당 DB에 대해 앱을 작성해야 할 경우 어떻게됩니까? 그들은 x 필드 이어야 한다는 것을 모른다 NOT NULL.

다른 프로그램은 모든 필드 x가 NOT NULL카운트를 수행하기위한 것이라고 가정 할 수 있지만 현재 일부 NULL는 새로운 프로그램으로 인해 일관성이없고 오류를 추적하기가 어렵습니다.

IMHO 데이터 무결성 규칙은 가능한 한 데이터에 가까운, 즉 데이터베이스와 같은 방식으로 시행하는 것이 가장 좋습니다. 이렇게하면 새로운 앱 및 / 또는 프로그래머가 데이터를 엉망으로 만들 수 없습니다.

프로그래머, 응용 프로그램, 언어 및 프레임 워크가왔다 갔다합니다. 데이터와 데이터베이스는 지속되는 경향이 있습니다. 데이터베이스는 일관성이없고 오류가있는 데이터에 대한 마지막 방어선입니다.

확인 최대 심지어 성능의 비용으로, 데이터베이스의 무결성 제약 집행 메커니즘을 사용. 올바른 결과를 생성하는 느린 시스템은 문제가 발생 하는 빠른 시스템 보다 무한히 우수합니다!


1
IMHO it is always best to enforce data integrity rules as near to the data as possible이것은 실제로 내가 쓴 직감과 동일합니다. 그리고 이것이 바로 제가 타당한 이유를 찾고있는 이유입니다. 우리는 코드 검토와 적절한 문서를 가지고 있으므로, 새로운 개발자에 대한 우려는 무언가를 모르는 것만으로는 변경을 정당화하기에 충분하지 않습니다.
살바도르 달리

4
코드 검토 및 좋은 문서는 (프로그래밍 또는 기타) 오류에 대해 보장하지 않습니다.
ypercubeᵀᴹ

2
그리고 마감일이 촉박 한 프로젝트에 갇히기 전에 문서의 전체 또는 일부를REAL PROGRAMMERS 읽는 사람은 몇 명 입니까?
Vérace

3
데이터웨어 하우스에 대해 같은 태도를 가진 은행에서 한 번 검토를했습니다. 그들의 경우-참조 무결성이 없습니다. 글쎄, 누군가가 문서를 읽지 않고 조회 테이블에서 데이터를 삭제했기 때문에 오래된 데이터의 40 %가 쓰레기였습니다. 데이터 무결성을 갖춘 코드 검토 및 문서를 신뢰하지 않으므로 데이터베이스에서 명시 적으로 작성해야합니다.
TomTom

5

주석에서 다른 사람들이 이미 언급했듯이 NOT NULL테이블 사양 을 추가하면 쿼리의 성능을 크게 향상시킬 수 있습니다 (다른 답변에 명시된 매우 좋은 방법 론적 이유 외에도).

그 이유는 열이 NULL값을 가질 수 없다는 것을 알고있는 쿼리 최적화 프로그램 이 NOT INvs 와 같이 이러한 값에 대한 특수 테스트를 제외 할 수 있기 때문 NOT EXISTS입니다. 예를 들어이 블로그를 볼 수 있습니다 . 여기서 NOT NULL특정 쿼리 로 필드를 선언하지 않으면 (테이블이 항상 null이 아닌 값을 포함하는 경우) 실행 시간이 500 % 증가합니다. 결과는 SQL Server에 대해 표시되지만 사용자와 같은 다른 관계형 DBMS에서도 유사한 동작이 나타날 수 있습니다 (데이터베이스를 다른 시스템으로 이식 할 수 있다는 사실은 말할 것도 없습니다). 쿼리 옵티마이 저가 더 많은 정보를 사용할 수 있으면보다 효율적인 액세스 플랜이 생성 될 수 있다고 가정 할 수 있습니다.


감사합니다. 이것이 내가 찾던 대답의 유형입니다.
살바도르 달리

5
NULL을 포함하지 않는 열 NOT NULL은 여러 가지 이유로 정의되어야하며 그에 대한 인수는 없습니다. 그러나 SQL Server에 대한 블로그 링크는 Postgres에 적용 할 수 없으며 언급 한 성능 영향을 증명하지 않습니다. 아무 말도 없지만 실제 증거 를보고 싶습니다 .
Erwin Brandstetter 2016 년

@ErwinBrandstetter, PostgreSQL 옵티 마이저에 대한 기대가 많았습니다. (여러 테스트 후 PostgreSQL의 블로그에 표시된 NOT IN 쿼리에서 NOT NULL 제약 조건을 사용하거나 사용하지 않고 유의미한 차이를 찾지 못했습니다. 내가 삭제해야한다고 생각하는지 묻습니다
Renzo

아니요, 삭제해야한다고 생각하지 않습니다. 그것은 5 + 투표를하고 downvote가 없습니다.
ypercubeᵀᴹ

not inNull을 허용하는 열의 의미 는 다르지만 둘 사이의 계획에 약간의 차이 가 있어야 합니까?
Martin Smith

2

공간 영향

공간의 의미는 @Erwin Brandstetter에 의해이 게시물에 대해 이야기하고 있습니다

즉, 데이터베이스에 다음과 같은 경우 1 totalColumns - 8비트를 가장 가까운 바이트 (또는 MAXALIGN)로 반올림하여 저장 합니다

  1. 8 개 이상의 열
  2. 테이블의 모든 열은NOT NULL

성능 관련

그러나 @Erwin Brandstetter의 SE에 대한이 게시물에서 그는 말합니다.

  1. "NOT NULL을 설정해도 성능에는 영향을 미치지 않습니다. 확인주기는 몇주기입니다."
  2. "... 실제로 더미 값 대신 NULL을 사용함으로써. 데이터 유형에 따라 많은 디스크 공간과 RAM을 절약하여 모든 속도를 높일 수 있습니다."

@Renzo는 성능에 미치는 영향에 대한 답변가지고 있습니다. PostgreSQL에는 해당되는 것이 없다고 생각합니다 . 난 아무것도 찾을 수 입증 할 어떤 PostgreSQL의 관련 인 것으로 그의를. 어떤 사이클이 저장 되더라도 가장 기본적인 쿼리에서도 정량화 할 수 없습니다.

CREATE TABLE foo (
  a int,
  b int NOT NULL,
  x float,
  y float NOT NULL
);

INSERT INTO foo ( a, b, x, y )
SELECT x, x, x, x
FROM generate_series(1,1E7) AS X(x);

EXPLAIN ANALYZE SELECT 1/a FROM foo;
EXPLAIN ANALYZE SELECT 1/b FROM foo;
EXPLAIN ANALYZE SELECT 1/x FROM foo;
EXPLAIN ANALYZE SELECT 1/y FROM foo;

또한 NULL 인덱스가 더 빠른지 확인하기 위해 몇 가지 테스트를 실행했으며이를 확인할 수 없었습니다. Scott Marlowe 의 메일 링리스트에서 9.1의 쿼리 플래너에 대해 이야기하는 이 놀랍도록 유용한 스레드 를 9.1의 다른 WHERE 절에서 부분 인덱스를 사용할 수 있습니다. 나는 다음을 실행하여 이것을 테스트했다.

CREATE TABLE foo ( a int );
CREATE TABLE bar ( a int NOT NULL );
INSERT INTO foo
  SELECT null FROM generate_series(1,1e5) AS x
  UNION ALL
  SELECT 10
  UNION ALL
  SELECT null FROM generate_series(1,1e5) AS x
;
INSERT INTO bar
  SELECT 0 FROM generate_series(1,1e5) AS x
  UNION ALL
  SELECT 10
  UNION ALL
  SELECT 0 FROM generate_series(1,1e5) AS x
;

이제 색인을 만들었습니다.

CREATE INDEX foobar ON foo(a) WHERE a IS NOT NULL;
CREATE INDEX barbar ON bar(a) WHERE a <> 0;

이 두 경우 모두 플래너는 = 10NULL 또는 0을 각각 검색 할 때 인덱스를 사용할 수 있고 seq 스캔 을 사용할 수있었습니다 . 두 부분 인덱스의 크기는 동일했습니다. 전체 인덱스 (표시되지 않음)는 크기가 동일했습니다. 동일한 방법론에 따라 하나의 시퀀스 1..1e5와 하나의 null / 0 값 및 다른 시퀀스를 가진 테이블을로드했습니다 1..1e5. 두 방법 모두 전체 테이블을 포함하는 인덱스로 null / 0을 찾을 수있었습니다.

TLDR; 요약

플래너 부족을 포함하여 테스트 할 가치가 있다고 생각한 대부분의 성능 문제에 대해 어떤 식 으로든 입증 할 수 없습니다. 램을 절약하기 위해 널 (null)을 사용하는 것의 이점은 실제입니다. null을 사용하지 않고 저장 한 디스크 공간은 무시해도되며 NULLABLE열 이 1 개이거나 열이 8 개 미만인 테이블에 대해서는 과장되어 있습니다. 이러한 경우에는 디스크 공간이 저장되지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.