다음을 통해 공유


PRIMARY KEY 및 FOREIGN KEY 제약 조건

적용 대상: SQL Server 2016(13.x) 이상 Azure SQL 데이터베이스 Azure SQL Managed Instance

SQL Server 테이블에서 데이터 무결성을 강제 적용하는 데 사용할 수 있는 두 가지 유형의 제약 조건으로 기본 키와 외래 키가 있습니다. 이는 중요한 데이터베이스 개체입니다.

기본 키 제약 조건

테이블에는 일반적으로 테이블의 각 행을 고유하게 식별하는 값을 가진 열 또는 열 조합이 포함되어 있습니다. 이러한 열이나 열 조합은 테이블의 PK(기본 키)라고 하며 테이블에 엔터티 무결성을 적용합니다. 기본 키 제약 조건은 데이터의 고유성을 보장하므로 자주 ID 열에 정의됩니다.

테이블에 대해 기본 키 제약 조건을 지정하면 데이터베이스 엔진은 기본 키 열에 대해 고유 인덱스를 자동으로 만들어 데이터 고유성을 적용합니다. 또한 쿼리에서 기본 키가 사용되는 경우 이 인덱스를 사용하여 데이터에 빠르게 액세스할 수 있습니다. 둘 이상의 열에 기본 키 제약 조건이 정의된 경우 값은 한 열 내에서 중복될 수 있지만 기본 키 제약 조건 정의의 모든 열에서 값의 각 조합은 고유해야 합니다.

다음 그림과 같이 Purchasing.ProductVendor 테이블의 ProductIDVendorID 열은 이 테이블의 복합 기본 키 제약 조건을 구성합니다. 그 결과 ProductVendor 테이블의 모든 열에서 ProductIDVendorID의 조합은 고유합니다. 이렇게 하면 중복 행이 삽입되지 않습니다.

복합 PRIMARY KEY 제약 조건에 대한 테이블의 행 다이어그램입니다.

  • 테이블은 하나의 기본 키 제약 조건만 포함할 수 있습니다.
  • 기본 키는 16개의 열과 900바이트의 총 키 길이를 초과할 수 없습니다.
  • 기본 키 제약 조건에 의해 생성된 인덱스 수는 비클러스터형 인덱스 999개, 클러스터형 인덱스 1개인 테이블의 인덱스 수 제한을 초과할 수 없습니다.
  • 기본 키 제약 조건에 대해 클러스터형 또는 비클러스터형을 지정하지 않은 경우 테이블에 클러스터형 인덱스가 없으면 클러스터형이 사용됩니다.
  • 기본 키 제약 조건 내에서 정의된 모든 열은 NOT NULL로 정의되어야 합니다. Null 허용 여부를 지정하지 않은 경우에는 기본 키 제약 조건에 참여하는 모든 열의 Null 허용 여부가 Null이 아닌 것으로 설정됩니다.
  • CLR 사용자 정의 형식 열에 기본 키를 정의하는 경우 형식 구현이 이진 순서를 지원해야 합니다.

외래 키 제약 조건

FK(외래 키)는 외래 키 테이블에 저장될 수 있는 데이터를 제어하기 위해 두 테이블의 데이터 간에 링크를 설정하고 적용하는 데 사용되는 열 또는 열의 조합입니다. 외래 키 참조에서는 한 테이블에 대한 기본 키 값을 포함하는 열이 다른 테이블의 열에서 참조될 때 두 테이블 사이에 링크가 만들어집니다. 이 열은 두 번째 테이블에서 외래 키가 됩니다.

예를 들어 Sales.SalesOrderHeader 테이블에는 Sales.SalesPerson 테이블에 대한 외래 키 링크가 생성되는데 이는 판매 주문과 영업 사원 간에 논리적 관계가 있기 때문입니다. SalesOrderHeader 테이블의 SalesPersonID 열은 SalesPerson 테이블의 기본 키 열과 일치합니다. SalesOrderHeader 테이블의 SalesPersonID 열은 SalesPerson 테이블에 대한 외래 키입니다. 이 외래 키 관계를 만들면 SalesPerson 테이블에 이 값이 없을 경우 SalesOrderHeader 테이블에 SalesPersonID 값을 삽입할 수 없습니다.

외래 키 참조가 있는 테이블은 여전히 253개의 외래 키 참조로 제한됩니다. SQL Server 2016(13.x)에서는 단일 테이블의 열을 참조할 수 있는 다른 테이블 및 열의 수 제한이 253에서 10,000으로 증가합니다. 단, 호환성 수준이 130 이상이어야 합니다. 이러한 참조 가능 테이블 및 열 수의 증가에는 다음과 같은 제한이 적용됩니다.

  • 253개 이상의 외래 키 참조는 DELETE DML 작업에만 지원됩니다. UPDATEMERGE 작업은 지원되지 않습니다.

  • 외래 키 참조가 있는 테이블은 여전히 253개의 외래 키 참조로 제한됩니다.

  • columnstore 인덱스, 메모리 최적화 테이블, 스트레치 데이터베이스 또는 분할된 외래 키 테이블에 대해서는 현재 253개보다 많은 외래 키 참조를 포함할 수 없습니다.

    Important

    Stretch Database는 SQL Server 2022(16.x) 및 Azure SQL 데이터베이스에서 사용되지 않습니다. 데이터베이스 엔진의 이후 버전에서는 이 기능이 제거됩니다. 새 개발 작업에서는 이 기능을 사용하지 않도록 하고, 현재 이 기능을 사용하는 애플리케이션은 수정하세요.

외래 키 제약 조건에 대한 인덱스

기본 키 제약 조건과 달리 외래 키 제약 조건을 만들면 해당 인덱스가 자동으로 만들어지지 않습니다. 그러나 외래 키에 인덱스를 수동으로 만드는 것은 다음과 같은 이유로 유용한 경우가 많습니다.

  • 외래 키 열은 쿼리에서 한 테이블의 외래 키 제약 조건 열을 다른 테이블의 기본 또는 고유 키 열과 연결하여 테이블의 데이터를 병합하는 조인에서 자주 사용됩니다. 인덱스를 사용하면 데이터베이스 엔진은 외래 키 테이블에서 관련 데이터를 빠르게 찾을 수 있습니다. 그러나 이 인덱스 만들기는 필요하지 않습니다. 테이블 간에 기본 키 또는 외래 키 제약 조건이 정의되지 않더라도 관련된 두 테이블의 데이터를 결합할 수 있습니다. 그러나 두 테이블 간 외래 키 관계가 설정되면 키를 기준으로 하는 쿼리에서 결합할 때 최적화될 수 있습니다.

  • 기본 키 제약 조건의 변경 내용은 관련 테이블의 외래 키 제약 조건을 통해 확인됩니다.

참조 무결성

외래 키 제약 조건의 기본 목적은 외래 키 테이블에 저장할 수 있는 데이터를 제어하는 것이지만 기본 키 테이블의 데이터 변경 내용도 제어합니다. 예를 들어, 한 영업 사원에 대한 행이 Sales.SalesPerson 테이블에서 삭제되었는데 이 영업 사원의 ID가 Sales.SalesOrderHeader 테이블의 판매 주문에 사용된 경우 두 테이블 간의 관계 무결성이 손상됩니다. SalesPerson 테이블의 데이터에 대한 연결이 끊어졌으므로 삭제된 영업 사원의 판매 주문은 SalesOrderHeader 테이블에서 고아 항목이 됩니다.

외래 키 제약 조건은 이런 상황이 발생되지 않도록 합니다. 제약 조건은 이러한 변경 내용이 외래 키 테이블의 데이터에 대한 링크를 무효화하는 경우 기본 키 테이블의 데이터를 변경할 수 없도록 보장하여 참조 무결성을 적용합니다. 기본 키 테이블의 행을 삭제하거나 기본 키 값을 변경하려고 하면 삭제되거나 변경된 기본 키 값이 다른 테이블의 외래 키 제약 조건 값에 해당하는 경우 작업이 실패합니다. 외래 키 제약 조건의 행을 성공적으로 변경하거나 삭제하려면 먼저 외래 키 테이블에서 외래 키 데이터를 삭제하거나 외래 키를 다른 기본 키 데이터에 연결하는 외래 키 테이블의 외래 키 데이터를 변경해야 합니다.

연계 참조 무결성

연계 참조 무결성 제약 조건을 사용하면 사용자가 기존 외래 키가 가리키는 키를 삭제하거나 업데이트하려고 할 때 데이터베이스 엔진이 수행하는 작업을 정의할 수 있습니다. 다음과 같은 연계 동작을 정의할 수 있습니다.

  • NO ACTION

    데이터베이스 엔진에서는 오류가 발생하며 부모 테이블의 행에 대한 삭제 또는 업데이트 동작이 롤백됩니다.

  • CASCADE

    부모 테이블에서 행이 업데이트 또는 삭제될 때 참조 테이블에서도 해당 행이 업데이트 또는 삭제됩니다. CASCADEtimestamp 유형의 열이 외래 키 또는 참조 키의 일부인 경우에는 지정할 수 없습니다. ON DELETE CASCADEINSTEAD OF DELETE 트리거가 있는 테이블에 지정할 수 없습니다. ON UPDATE CASCADEINSTEAD OF UPDATE 트리거가 있는 테이블에는 지정할 수 없습니다.

  • SET NULL

    부모 테이블에서 해당 행을 업데이트 또는 삭제하면 해당 외래 키를 구성하는 모든 값이 NULL로 설정됩니다. 이 제약 조건을 실행하려면 외래 키 열이 Null을 허용해야 합니다. INSTEAD OF UPDATE 트리거가 있는 테이블에는 지정할 수 없습니다.

  • SET DEFAULT

    부모 테이블에서 해당 행을 업데이트 또는 삭제하면 외래 키를 구성하는 모든 값이 기본값으로 설정됩니다. 이 제약 조건을 실행하려면 모든 외래 키 열에 기본 정의가 있어야 합니다. 열이 NULL을 허용하고 명시적 기본값이 설정되어 있지 않은 경우 NULL은 해당 열의 암시적 기본값이 됩니다. INSTEAD OF UPDATE 트리거가 있는 테이블에는 지정할 수 없습니다.

CASCADE, SET NULL, SET DEFAULTNO ACTION은 서로 참조 관계를 가진 테이블에서 결합될 수 있습니다. 데이터베이스 엔진 이 NO ACTION을 발견하면 관련된 CASCADE, SET NULLSET DEFAULT 동작을 멈추고 롤백합니다. DELETE 문에서 CASCADE, SET NULL, SET DEFAULT 또는 NO ACTION 작업의 조합을 발생시키는 경우, 데이터베이스 엔진이 NO ACTION을 확인하기 전에 모든 CASCADE, SET NULLSET DEFAULT 작업이 적용됩니다.

트리거 및 연계 참조 작업

연계 참조 동작은 다음과 같은 방식으로 AFTER UPDATE 또는 AFTER DELETE 트리거를 시작합니다.

  • 원래 DELETE 또는 UPDATE로 인해 직접 발생하는 모든 연계 참조 작업이 먼저 수행됩니다.

  • 영향을 받는 테이블에 AFTER 트리거가 정의되어 있는 경우 이러한 트리거는 모든 연계 작업이 수행된 후에 발생합니다. 이러한 트리거는 연계 작업의 반대 순서로 실행됩니다. 단일 테이블에 여러 트리거가 있는 경우 테이블에 대한 전용 첫 번째 또는 마지막 트리거가 없으면 임의 순서로 실행됩니다. 이 순서는 sp_settriggerorder를 사용하여 지정됩니다.

  • UPDATE 또는 DELETE 작업의 직접 대상인 테이블에서 여러 개의 연계 체인이 발생하는 경우 이러한 체인이 해당 트리거를 발생시키는 순서는 지정되지 않습니다. 그러나 한 체인은 다른 체인이 실행되기 전에 항상 모든 트리거를 실행합니다.

  • UPDATE 또는 DELETE 동작의 직접적인 대상인 테이블에 대한 AFTER 트리거는 영향을 받는 행이 있는지 여부에 관계 없이 항상 시작됩니다. 이 경우 다른 테이블은 연계 작업에 영향을 받지 않습니다.

  • 이전 트리거 중 하나가 다른 테이블에 대해 UPDATE 또는 DELETE 작업을 수행하는 경우 이 동작에 의해 보조 연계 체인이 시작될 수 있습니다. 이러한 보조 체인은 모든 기본 체인의 모든 트리거가 실행된 후 한 번에 각 UPDATE 또는 DELETE 작업에 대해 처리됩니다. 이 프로세스는 후속 UPDATE 또는 DELETE 작업에 대해 재귀적으로 반복될 수 있습니다.

  • 트리거 내에서 CREATE, ALTER, DELETE 또는 기타 DDL(데이터 정의 언어) 작업을 수행하면 DDL 트리거가 실행될 수 있습니다. 그리고 추가 연계 체인과 트리거를 시작하는 DELETE 또는 UPDATE 작업이 뒤이어 수행될 수도 있습니다.

  • 특정 연계 참조 동작 체인 내에서 오류가 생성되면 오류가 발생하고 해당 체인에서 AFTER 트리거가 시작되지 않으며 체인을 만든 DELETE 또는 UPDATE 작업이 롤백됩니다.

  • INSTEAD OF 트리거가 있는 테이블에는 연계 작업을 지정하는 REFERENCES 절도 있을 수 없습니다. 그러나 연계 동작의 대상이 되는 테이블의 AFTER 트리거는 다른 테이블 또는 그 개체에 정의된 INSTEAD OF 트리거를 시작하는 뷰에서 INSERT, UPDATE 또는 DELETE 문을 실행할 수 있습니다.