제약 조건을 사용하여 데이터 무결성 적용
제약 조건 및 시퀀스 개체는 데이터 문제가 발생하기 전에 방지하는 디자인 선택 사항입니다. 외래키 제약이 없으면 고아 레코드가 데이터베이스에 이미 있을 수 있습니다. 나중에 ID 열을 바꾸기 위해 시퀀스 개체를 추가하려면 모든 애플리케이션에서 변경해야 합니다. 애플리케이션 코드는 데이터의 유효성을 검사할 수 있지만 사용자는 대량 가져오기, 직접 쿼리 또는 유효성 검사를 건너뛰는 새 애플리케이션을 통해 데이터를 바이패스할 수 있습니다.
데이터베이스 제약 조건은 엔진 수준에서 규칙을 적용하므로 항상 적용됩니다. 데이터베이스에 적용할 규칙 및 ID 열 또는 시퀀스를 사용할지 여부와 같이 디자인 중에 내리는 결정은 애플리케이션의 수명 동안 데이터 품질에 영향을 줍니다.
제약 조건을 사용하는 시기 이해
데이터 품질 문제는 비용이 많이 듭니다. 데이터 품질이 저하되면 잘못된 비즈니스 의사 결정, 실패한 통합 및 규정 준수 위반이 발생합니다. 동일한 데이터베이스에 액세스하는 여러 애플리케이션에서 일관성이 없을 수 있는 애플리케이션 수준 유효성 검사와 달리 제약 조건은 애플리케이션 코드, 임시 쿼리, 직접 SQL 스크립트 또는 대량 가져오기를 통해 무시할 수 없는 데이터베이스 엔진 수준에서 규칙을 적용합니다. 모든 INSERT, UPDATE및 DELETE 작업은 데이터베이스 엔진이 변경 내용을 커밋하기 전에 정의된 모든 제약 조건을 충족해야 합니다.
데이터베이스 제약 조건 적용
제약 조건은 데이터베이스가 손상되기 전에 데이터 품질 문제를 방지합니다. 다음 표에서는 각 제약 조건 형식이 특정 데이터 무결성 문제를 해결하는 방법을 보여 줍니다.
| 문제 | 제약 조건 | 예시 |
|---|---|---|
| 고아 상태로 남겨진 레코드 | 외래 키 | 유효한 고객 없이 주문 방지 |
| 중복 데이터 | UNIQUE | 중복 전자 메일 등록 중지 |
| 잘못된 데이터 | CHECK | 부정적인 가격 또는 미래의 생년월일을 거부합니다. |
| 중요한 데이터 누락 | NOT NULL | 불완전한 레코드를 방지하다 |
| 참조 불일치 | 외래 키 | 테이블 간 데이터 무결성 유지 관리 |
고객 전자 메일 열에 고유한 제약 조건을 정의하지 않은 소매 회사를 고려합니다. 시간이 지남에 따라 동일한 고객이 동일한 전자 메일 주소로 여러 번 등록되었습니다. 마케팅에서 홍보 캠페인을 보낼 때 일부 고객은 동일한 전자 메일의 복사본 3개를 받아 비용을 증가시키고 고객 신뢰를 손상시켰습니다. 테이블 정의에 추가 UNIQUE (EmailAddress) 하면 이러한 중복 항목이 삽입되지 않았을 수 있습니다.
제약 조건은 데이터베이스 엔진 수준에서 규칙을 적용하여 데이터가 시스템에 들어오는 방식에 관계없이 데이터 품질을 보장합니다. 애플리케이션 유효성 검사를 무시할 수 있고, 애플리케이션에 따라 다르며, 유지 관리가 더 어렵습니다. 데이터베이스 제약 조건은 항상 적용되고 중앙 집중화되며 하나의 원본을 제공합니다.
제약 조건은 데이터베이스 수준에서 데이터 품질과 일관성을 보장합니다.
기본 키 제약 조건 사용
기본 키 제약 조건은 고유 데이터를 보장하고 엔터티 무결성을 적용합니다. 기본 키 제약 조건을 지정하면 데이터베이스 엔진은 기본 키 열에 대한 고유 인덱스를 자동으로 만듭니다. 테이블에는 하나의 기본 키 제약 조건만 포함될 수 있으며 기본 키 제약 조건 내에 정의된 모든 열은 다음과 같이 NOT NULL정의되어야 합니다.
제약 조건을 사용하여 PRIMARY KEY 기본 키를 만들 수 있습니다. 예제는 다음과 같습니다.
CREATE TABLE Customer (
CustomerID INT PRIMARY KEY IDENTITY(1,1),
EmailAddress NVARCHAR(100) NOT NULL
);
외래 키 제약 조건 사용
외래 키 제약 조건은 외래 키 테이블에 저장할 수 있는 데이터를 제어하여 참조 무결성을 적용합니다. 외래 키 제약 조건은 이러한 변경 내용이 외래 키 테이블의 데이터에 대한 링크를 무효화하는 경우 기본 키 테이블의 데이터를 변경하지 못하게 합니다.
같은 연계 참조 작업을CASCADESET NULL정의하거나 SET DEFAULT 사용자가 기존 외래 키가 가리키는 키를 삭제하거나 업데이트하려고 할 때 발생하는 작업을 지정할 수 있습니다.
외래 키 열에 인덱스를 수동으로 만들 필요는 없지만 조인 조건에 외래 키 열이 자주 사용되기 때문에 유용합니다.
FOREIGN KEY 제약 조건을 REFERENCES 절과 함께 사용하여 외래 키를 만들 수 있습니다. 예제는 다음과 같습니다.
CREATE TABLE Order (
OrderID INT PRIMARY KEY IDENTITY,
CustomerID INT NOT NULL,
OrderDate DATETIME2,
FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID)
);
고유 제약 조건 사용
고유 제약 조건은 기본 키에 참여하지 않는 특정 열에 중복 값이 입력되지 않도록 합니다.
PRIMARY KEY 제약 조건과 달리 UNIQUE 제약 조건은 NULL 값을 허용합니다. 그러나 UNIQUE 제약 조건에 참여하는 모든 값과 마찬가지로 열당 하나의 null 값만 허용됩니다. 데이터베이스 엔진은 고유성 요구 사항을 적용하기 위해 고유한 비클러스터형 인덱스가 자동으로 만들어집니다.
키워드를 사용하여 UNIQUE 고유한 제약 조건을 만들 수 있습니다. 예제는 다음과 같습니다.
CREATE TABLE Product (
ProductID INT PRIMARY KEY,
SKU NVARCHAR(50) UNIQUE,
ProductName NVARCHAR(100)
);
CHECK 제약 조건 사용
CHECK 제약 조건은 하나 이상의 열에서 허용하는 값을 제한하여 도메인 무결성을 적용합니다. 논리 연산자를 기반으로 하여 TRUE 또는 FALSE를 반환하는 논리 표현식을 사용하여 CHECK 제약 조건을 만들 수 있습니다. 단일 열에 여러 CHECK 제약 조건을 적용하거나 여러 열에 단일 CHECK 제약 조건을 적용할 수 있습니다.
null 값은 UNKNOWN로 평가되어, 식에서 이들의 존재가 제약 조건을 무효화할 수 있습니다. 예를 들어 MyColumn = 10 제약 조건이 INT 열에 있는 경우, NULL는 NULL이 FALSE로 평가되지 않기 때문에 여전히 삽입할 수 있습니다.
논리 식과 함께 키워드를 CHECK 사용하여 CHECK 제약 조건을 만들 수 있습니다. 예제는 다음과 같습니다.
CREATE TABLE Employee (
EmployeeID INT PRIMARY KEY,
HireDate DATE,
Salary DECIMAL(10,2),
CHECK (Salary >= 20000),
CHECK (HireDate <= GETDATE())
);
기본 제약 조건 사용
기본 제약 조건은 작업 중에 INSERT 값이 지정되지 않은 경우 기본값을 제공합니다. 데이터베이스 프로젝트를 사용할 때는 환경마다 다른 시스템 생성 이름을 허용하는 대신 명시적 이름으로 제약 조건을 만드는 것이 좋습니다.
키워드를 사용하여 DEFAULT 제약 조건을 DEFAULT 만들 수 있습니다. 예제는 다음과 같습니다.
CREATE TABLE Activity (
ActivityID INT PRIMARY KEY IDENTITY,
Description NVARCHAR(200),
CreatedDate DATETIME2 CONSTRAINT DF_Activity_CreatedDate DEFAULT GETUTCDATE(),
IsActive BIT CONSTRAINT DF_Activity_IsActive DEFAULT 1
);
시퀀스 개체 사용
시퀀스 개체는 시퀀스가 만들어진 사양에 따라 숫자 값의 시퀀스를 생성하는 사용자 정의 스키마 바인딩된 개체입니다. ID 열과 달리 시퀀스는 특정 테이블과 연결되지 않습니다. 애플리케이션은 시퀀스 개체를 참조하여 다음 값을 검색하고 시퀀스와 테이블 간의 관계는 애플리케이션에 의해 제어됩니다.
ID 열은 단일 테이블에 대해 자동 번호 매기기를 필요로 할 때 잘 작동합니다. 그러나 하나의 테이블로 제한됩니다. 여러 테이블에서 숫자를 공유하거나, 행을 삽입하기 전에 다음 값을 얻거나, 카운터를 쉽게 다시 설정할 수 없습니다. 시퀀스 개체는 테이블과 독립적으로 숫자를 생성하여 이러한 문제를 해결합니다.
시퀀스를 사용하는 시기 이해
다음 시나리오에서는 ID 열 대신 시퀀스를 사용합니다.
- 공유 번호 계열 - 애플리케이션에서는 여러 테이블 또는 테이블 내의 여러 열 간에 단일 일련의 숫자를 공유해야 합니다.
- 순환 번호 계열 - 지정된 숫자에 도달하면 애플리케이션에서 숫자 계열을 다시 시작해야 합니다. 예를 들어 1에서 10까지 값을 할당하면 애플리케이션에서 1부터 10까지 값을 다시 할당합니다.
-
정렬된 시퀀스 값 - 애플리케이션에서 시퀀스 값을 다른 필드별로 정렬해야 합니다. 함수는
OVER절을 적용하여 반환된 값이ORDER BY절이 지정한 순서대로 생성되도록 할 수 있습니다. -
여러 숫자 예약 - 애플리케이션에서 여러 개의 순차적인 번호를 한 번에 예약해야 합니다. ID 값을 요청할 때 다른 프로세스가 동시에 숫자를 발급하면 간격이 생길 수 있습니다. 호출
sp_sequence_get_range은 시퀀스에서 여러 숫자를 한 번에 검색합니다. - 변경 가능한 사양 - 생성 후 증분 값과 같은 시퀀스의 사양을 변경해야 합니다.
시퀀스 개체는 ID 열보다 더 많은 유연성을 제공할 수 있습니다.
| 특징 | 순서 | 아이덴티티 |
|---|---|---|
| 테이블에 고정 | 아니오 | 네 |
| 여러 테이블 또는 열에 걸쳐 공유됩니다. | 네 | 아니오 |
| 삽입 작업 전에 다음 값 가져오기 | 네 | 아니오 |
| 사용자 지정 최소/최대값 | 네 | 한정 |
| 한 번에 여러 숫자 검색 | 네 | 아니오 |
| 지정된 횟수에서 순환/재시작 | 네 | 아니오 |
| 다른 필드를 기준으로 값 정렬 | 네 | 아니오 |
| 만든 후 증분 변경 | 네 | 아니오 |
단일 테이블에 대해 간단한 자동 증가 기본 키가 필요하고 여러 테이블에서 동일한 숫자 계열을 공유하거나 행을 삽입하기 전에 다음 값을 검색할 필요가 없는 경우 ID 열을 사용합니다.
삽입하기 전에 애플리케이션에 숫자가 필요하거나, 여러 테이블 간에 단일 계열을 공유해야 하거나, 지정된 숫자에 도달할 때 숫자 계열을 다시 시작해야 하거나, 한 번에 여러 순차 숫자를 예약해야 하는 경우 시퀀스를 사용합니다.
시퀀스 제한 사항 이해
ID 열과 달리 시퀀스 값은 테이블에 삽입한 후 자동으로 보호되지 않습니다 . 또한 고유성은 시퀀스 값에 자동으로 적용되지 않습니다. 테이블의 시퀀스 값이 고유해야 하는 경우 열에 고유한 제약 조건을 만듭니다.
시퀀스 번호는 현재 트랜잭션 범위 외부에서 생성되며, 시퀀스 번호를 사용하는 트랜잭션이 커밋되거나 롤백되는지 여부에 관계없이 소비됩니다.
시작, 증가 및 범위에 대한 선택적 매개 변수가 있는 문을 사용하여 CREATE SEQUENCE 시퀀스 개체를 만들 수 있습니다. 예제는 다음과 같습니다.
-- Create sequence
CREATE SEQUENCE OrderNumber
START WITH 1000
INCREMENT BY 1
MINVALUE 1000
MAXVALUE 999999
NO CYCLE;
-- Use sequence in INSERT with NEXT VALUE FOR function
INSERT INTO Order (OrderID, CustomerID, OrderNumber, OrderDate)
VALUES (1, 100, NEXT VALUE FOR OrderNumber, GETDATE());
-- Get next value before INSERT
DECLARE @NextOrderNum INT = NEXT VALUE FOR OrderNumber;
SELECT @NextOrderNum;
-- Get multiple sequence numbers at once for batch processing
DECLARE @FirstSeq INT, @LastSeq INT;
EXEC sp_sequence_get_range
@sequence_name = N'OrderNumber',
@range_size = 100,
@range_first_value = @FirstSeq OUTPUT,
@range_last_value = @LastSeq OUTPUT;
-- Reset sequence
ALTER SEQUENCE OrderNumber RESTART WITH 1000;
이 예제에서는 1000에서 시작하여 1씩 증가하고 999999에서 중지하는 재순환하지 않는 시퀀스 OrderNumber를 만듭니다. 함수는 INSERT 문 중에 인라인으로 다음 사용 가능한 숫자를 검색하거나, 애플리케이션이 값을 먼저 참조해야 할 경우 삽입 전에 해당 숫자를 변수에 할당합니다. 한 번에 sp_sequence_get_range 여러 순차 숫자가 필요한 일괄 처리 작업의 경우 100개 숫자 블록을 예약하여 범위의 첫 번째 값과 마지막 값을 반환합니다. 필요한 경우 ALTER SEQUENCE 문장은 시퀀스를 1000으로 재설정합니다.
제약 조건은 문제가 발생하기 전에 방지하는 아키텍처 결정입니다. 제약 조건 CHECK 이 없으면 잘못된 데이터가 데이터베이스를 눈에 띄지 않게 손상시킬 수 있습니다. 테이블 간 번호 매기기 필요 시 ID 열을 선택하면 애플리케이션 수준 해결 방법이 강제로 적용됩니다. 데이터베이스 수준에서 정의된 제약 조건은 데이터베이스에 액세스하는 애플리케이션, 도구 또는 스크립트에 관계없이 데이터 품질을 보호합니다. 이러한 결정은 애플리케이션의 수명 동안 데이터 무결성 보장을 형성합니다.