데이터베이스는 어떤 시점에서 트랜잭션의 인덱스를 업데이트합니까?


11

인덱스와 트랜잭션이 모두 포함 된 삽입의 이벤트 시퀀스를 이해하려고합니다.

예를 들어, Oracle 설명서에는 다음이 명시되어 있습니다.

데이터를로드하기 전에 하나 이상의 인덱스를 작성하거나 갖는 경우 데이터베이스는 각 행이 삽입 될 때마다 모든 인덱스를 업데이트해야합니다.

그러나 트랜잭션을 만들고 5 개의 행을 삽입 한 다음 커밋하면 어떻게됩니까? 삽입 할 때마다 또는 커밋 지점에서 색인이 업데이트됩니까?

Logic은 레코드가 커밋 될 때까지 업데이트 된 인덱스를 사용할 수 없기 때문에 커밋 시점에서만 업데이트한다고 알려줍니다. 그러나 이것이 사실입니까?

그렇다면 1m 행을 삽입 할 때 최상의 성능을 얻으려면 100k 레코드의 10 트랜잭션이 아닌 모든 행에 대해 하나의 큰 커밋을 수행해야합니까? 물론 행 999,999가 실패하면 이것이 더 큰 롤백 위험이 있음을 알고 있습니다.

내 용어가 약간 밖에 없다면 사과드립니다. 나는 무역에 의한 DBA가 아닙니다. Oracle과 Postgres가 가장 많이 사용하지만 일반적으로 데이터베이스와 같이 특정 데이터베이스에별로 관심이 없습니다. 이 주제를 검색했지만 실제로 확실한 답을 찾을 수 없습니다.

답변:


8

SQL Server 및 Oracle과 협력합니다. 일부 예외가있을 수 있지만 해당 플랫폼의 경우 일반적으로 데이터와 인덱스가 동시에 업데이트됩니다.

트랜잭션을 소유하는 세션과 다른 세션에 대해 인덱스가 업데이트되는 시점을 구분하는 것이 도움이 될 것이라고 생각합니다. 기본적으로 다른 세션에는 트랜잭션이 커밋 될 때까지 업데이트 된 인덱스가 표시되지 않습니다. 그러나 트랜잭션을 소유 한 세션은 즉시 업데이트 된 인덱스를 보게됩니다.

그것에 대해 생각하는 한 가지 방법은 기본 키가있는 테이블을 고려하십시오. SQL Server 및 Oracle에서는 인덱스로 구현됩니다. 대부분의 경우 INSERT기본 키를 위반하는 작업이 수행 되면 즉시 오류가 발생하기 를 원합니다. 이를 위해서는 데이터와 동시에 인덱스를 업데이트해야합니다. Postgres와 같은 다른 플랫폼에서는 트랜잭션이 커밋 될 때만 검사되는 지연 제약 조건을 허용합니다.

다음은 일반적인 사례를 보여주는 빠른 Oracle 데모입니다.

CREATE TABLE X_TABLE (PK INT NULL, PRIMARY KEY (PK));

INSERT INTO X_TABLE VALUES (1);
INSERT INTO X_TABLE VALUES (1); -- no commit

두 번째 INSERT문은 오류를 발생시킵니다.

SQL 오류 : ORA-00001 : 고유 제약 조건 (XXXXXX.SYS_C00384850) 위반

00001. 00000- "고유 제한 조건 (% s. % s)을 위반했습니다"

* 원인 : UPDATE 또는 INSERT 문이 중복 키를 삽입하려고했습니다. DBMS MAC 모드로 구성된 Trusted Oracle의 경우 중복 항목이 다른 레벨에 존재하면이 메시지가 표시 될 수 있습니다.

* 조치 : 고유 제한을 제거하거나 키를 삽입하지 마십시오.

아래의 인덱스 업데이트 작업을 보려면 SQL Server의 간단한 데모입니다. 먼저 행에 백만 개의 행과 비 클러스터형 인덱스가있는 두 개의 열 테이블을 만듭니다 VAL.

DROP TABLE IF EXISTS X_TABLE_IX;

CREATE TABLE X_TABLE_IX (
ID INT NOT NULL,
VAL VARCHAR(10) NOT NULL
PRIMARY KEY (ID)
);

CREATE INDEX X_INDEX ON X_TABLE_IX (VAL);

-- insert one million rows with N from 1 to 1000000
INSERT INTO X_TABLE_IX
SELECT N, N FROM dbo.Getnums(1000000);

인덱스는 해당 쿼리에 대한 포함 인덱스이므로 다음 쿼리는 비 클러스터형 인덱스를 사용할 수 있습니다. 여기에는 실행에 필요한 모든 데이터가 포함됩니다. 예상대로 리턴 값이 리턴되지 않습니다.

SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';

쿼리 1

이제 트랜잭션을 시작 VAL하고 테이블의 거의 모든 행에 대해 업데이트하겠습니다 .

BEGIN TRANSACTION

UPDATE X_TABLE_IX
SET VAL = 'A'
WHERE ID <> 1;

이에 대한 쿼리 계획의 일부는 다음과 같습니다.

쿼리 2

빨간색 원은 비 클러스터형 인덱스에 대한 업데이트입니다. 파란색 원은 클러스터 된 인덱스에 대한 업데이트이며 기본적으로 테이블의 데이터입니다. 트랜잭션이 커밋되지 않았더라도 쿼리 실행의 일부로 데이터와 인덱스가 업데이트되는 것을 볼 수 있습니다. 다른 요인과 함께 관련된 데이터의 크기에 따라 계획에서 항상 이것을 볼 수는 없습니다.

트랜잭션이 여전히 커밋되지 않은 상태 SELECT에서 위 의 쿼리를 다시 살펴 보겠습니다 .

SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';

여기에 이미지 설명을 입력하십시오

쿼리 최적화 프로그램은 여전히 ​​인덱스를 사용할 수 있으며 이번에는 999999 개의 행이 반환 될 것으로 예상합니다. 쿼리를 실행하면 예상 결과가 반환됩니다.

그것은 간단한 데모 였지만 희망적으로 조금 정리했습니다.

제쳐두고, 나는 인덱스가 즉시 업데이트되지 않는다고 주장 할 수있는 몇 가지 경우를 알고 있습니다. 이는 성능상의 이유로 수행되며 최종 사용자는 일관되지 않은 데이터를 볼 수 없습니다. 예를 들어, 삭제가 SQL Server의 인덱스에 완전히 적용되지 않는 경우가 있습니다. 백그라운드 프로세스가 실행되어 결국 데이터를 정리합니다. 궁금하다면 고스트 레코드 에 대해 읽을 수 있습니다 .


그것은 훌륭한 답변이며, 내가 궁금했던 또 다른 답변 : 기본 키 (또는 유사한) 위반이 Insert 또는 Commit에서 발생하는지 여부에 대한 답변입니다. 완전한 답변을 주셔서 감사합니다.
마크 아일랜드

관련 질문 (제약 위반이 발생하는시기)은 지연된 거래의 사용 여부와 관련이 있습니다. 예를 들어 SQL Server는 지연된 트랜잭션을 구현하지 않았으므로 모든 위반은 명령문 끝에서 발생합니다. 다른 DBMS에는 (예를 들어, 모든 유형의 제약 조건이 아닌 Postgres가 있음) 제약 조건이 지연되면 트랜잭션의 커밋 단계에서 위반이 확인됩니다.
ypercubeᵀᴹ

오라클은 또한 지연된 제약 조건을 지원합니다
BobC

1

내 경험에 따르면 1,000,000 행 삽입에는 실제로 배치 삽입을 사용하는 것보다 더 많은 리소스가 필요하고 완료하는 데 시간이 더 걸립니다. 이것은 예를 들어 10,000 개의 행을 100 개의 삽입으로 구현할 수 있습니다.

이렇게하면 삽입되는 배치의 오버 헤드가 줄어들고 배치에 실패하면 더 작은 롤백입니다.

어쨌든 SQL Server의 경우 일괄 삽입을 수행하는 데 사용할 수 있는 bcp 유틸리티 또는 BULK INSERT 명령이 있습니다.

물론이 방법을 처리하기위한 자체 코드를 구현할 수도 있습니다.


1
일반적으로 인덱스가 필요한 테이블에 많은 수의 행을 삽입해야하는 경우 인덱스를 삭제하고 데이터를로드 한 다음 인덱스를 다시 작성하는 것이 더 빠를 수 있습니다. 또한 Oracle은 / * + APPEND * / 힌트를 사용하여 직접 경로 벌크로드 옵션을 지원합니다.
BobC
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.