테이블에 마지막 ID를 삽입하는 가장 좋은 방법


35

삽입을 통해 생성 한 ID 값을 얻는 가장 좋은 방법은 무엇입니까? 이 진술이 성능 측면에서 어떤 영향을 미칩니 까?

  1. SCOPE_IDENTITY()
  2. 집계 함수 MAX()
  3. TOP 1TableName에서 IdentityColumn 선택ORDER BY IdentityColumn DESC

1
사용 PostgreSQL을 당신은 선반에서있을 것이다 postgresql.org/docs/9.1/static/sql-insert.html
예브게니 Afanasyev에게

왼쪽 필드 옵션-테이블에 Guid 열이 있고 새 Guid를 생성하여 삽입하는 동안 새 열에 삽입 할 수있는 경우 해당 Guid가있는 행을 선택하여 생성 된 int ID를 가져올 수 있습니다.
niico

답변:


56

SCOPE_IDENTITY()단일 행을 삽입하고 생성 된 ID를 검색하려는 경우 사용하십시오 .

CREATE TABLE #a(identity_column INT IDENTITY(1,1), x CHAR(1));

INSERT #a(x) VALUES('a');

SELECT SCOPE_IDENTITY();

결과:

----
1

OUTPUT여러 행을 삽입하고 생성 된 ID 세트 를 검색해야하는 경우이 절을 사용하십시오 .

INSERT #a(x) 
  OUTPUT inserted.identity_column 
  VALUES('b'),('c');

결과:

----
2
3

왜 이것이 가장 빠른 옵션입니까?

기본적으로, 격리 수준 및 / 또는 여러 사용자가 올바른 것으로 보장되는 것은 성능뿐입니다. 정확성 측면을 무시하더라도 SQL Server는 삽입 된 값을 SCOPE_IDENTITY()메모리 에 보유 하므로 당연히 테이블이나 시스템 테이블에 대해 자체 격리 쿼리를 실행하는 것보다 빠릅니다.

정확성 측면을 무시하는 것은 우체부에게 오늘의 우편물을 잘 전달했다고 말하는 것과 같습니다. 그는 자신의 평균 시간보다 10 분 더 빨리 경로를 완료했습니다.

다음을 사용 하지 마십시오 :

  • @@IDENTITY -예를 들어 ID 열이있는 테이블에 자체 ID 열이있는 다른 테이블에 삽입하는 트리거가있는 경우와 같이 모든 시나리오에서 사용할 수 없으므로 잘못된 값을 다시 얻게됩니다.
  • IDENT_CURRENT()- 나는 이것에 대해 자세히 다루지 여기 및 코멘트뿐만 아니라 유용한 독서를하지만, 본질적으로, 동시성에 따라, 당신은 종종 잘못된 답변을 얻을 것입니다.
  • MAX()또는 TOP 1- MAX()다른 사람이 아닌 사람이 되도록하기 위해 직렬화 가능한 격리로 두 명령문을 보호해야합니다 . 이것은을 사용하는 것보다 훨씬 비쌉니다 SCOPE_IDENTITY().

이 함수는 또한 두 개 이상의 행을 삽입 할 때마다 실패하며 생성 된 모든 ID 값이 필요합니다 OUTPUT. 절의 유일한 옵션 입니다.


내 기억에 또 하나의 질문이 촉발되었습니다. 어떤 세션이나 사용자가 특정 테이블에서 마지막으로 생성 된 ID를 가져와야 할 때마다 해당 열의 MAX ()가 정확하고 가장 좋은 방법은 무엇입니까?
AA.SC

테이블에 여러 행을 삽입하면 SCOPE_IDENTITY ()가 항상 마지막으로 생성 된 ID를 반환합니까? 열이 기본 키이지만 ID 열이 아닌 경우 어떻게합니까?
AA.SC

@ AA.SC 예, 마지막을 반환합니다. ID 열이 아닌 경우 아니요, 이러한 기능 중 어느 것도 작동하지 않습니다. 이 경우 PK 가치는 어디에서 발생합니까?
Aaron Bertrand

어플리케이션에서 컬럼이 INT 타입 인 컬럼에서 이것을 보았습니다. 개발자들은 새로운 레코드를 삽입해야 할 때 MAX (columnname) +1을 사용합니다
AA.SC

그런 다음 방금 삽입 한 값을 알고 있습니다. SQL Server는 당신에게 말할 방법이 없습니다 (성능이나 동시성에 좋지 않은 전체 트랜잭션을 완전히 격리하지 않으면 사실 후에 MAX를 다시 가져올 수 없습니다).
Aaron Bertrand

7

성능과는 별도로, 그들은 모두 다른 의미를 가지고 있습니다.

SCOPE_IDENTITY()현재 범위 내에서 직접 모든 테이블에 삽입 된 마지막 ID 값을 제공합니다 (범위 = 배치, 저장 프로 시저 등. 그러나 현재 범위에서 시작된 트리거 내에는 포함되지 않음).

IDENT_CURRENT()당신에서 특정 테이블에 삽입 된 마지막 ID 값을 줄 것이다 어떤 에 의해 범위, 어떤 사용자.

@@IDENTITY테이블이나 범위에 관계없이 현재 연결에 대한 가장 최근의 INSERT 문에 의해 생성 된 마지막 ID 값을 제공합니다. (참고 : Access는이 기능을 사용하므로 ID 열이있는 테이블에 값을 삽입하는 트리거에 문제가 있습니다.)

사용 MAX()하거나하는 것은 TOP 1테이블이 음의 신원 단계를 가지고, 또는 삽입 행했다 경우 당신에게 완전히 잘못된 결과를 줄 수있는 SET IDENTITY_INSERT플레이를. 다음은이 모든 것을 보여주는 스크립트입니다.

CREATE TABLE ReverseIdent (
    id int IDENTITY(9000,-1) NOT NULL PRIMARY KEY CLUSTERED,
    data char(4)
)

INSERT INTO ReverseIdent (data)
VALUES ('a'), ('b'), ('c')

SELECT * FROM ReverseIdent

SELECT IDENT_CURRENT('ReverseIdent') --8998
SELECT MAX(id) FROM ReverseIdent --9000

SET IDENTITY_INSERT ReverseIdent ON

INSERT INTO ReverseIdent (id, data)
VALUES (9005, 'd')

SET IDENTITY_INSERT ReverseIdent OFF

SELECT IDENT_CURRENT('ReverseIdent') --8998
SELECT MAX(id) FROM ReverseIdent --9005

요약 :와 스틱 SCOPE_IDENTITY(), IDENT_CURRENT()또는 @@IDENTITY하고 있는지 확인 당신이 하나의 반환 당신이 실제로 필요로하는을 사용하고 있습니다.


1
왜의 사용을 장려 할 IDENT_CURRENT()하고 @@IDENTITY때 자신의 스크립트는 출력 잘못된 결과가 있음을 보여줍니다?
Aaron Bertrand

1
@AaronBertrand 나는 확실하지 않다. 마지막으로 생성 된 ID 값은 8998 (단계는 -1임을 알 수 있음)이며 이것이 IDENT_CURRENT()반환되는 것입니다. MAX ()는 id가 뒤로 계산되므로 IDENTITY_INSERT9005는 생성 된 ID 값이 아니므로에 반영되지 않으므로 첫 번째 행 이후의 올바른 값을 반환 하지 않습니다 IDENT_CURRENT(). 그러나 당신이 실제로 무엇을 반환 하는 경우에 "잘못된"결과를 반환 할 수 있습니다SCOPE_IDENTITY() . 작업에 적합한 도구를 선택하십시오.
db2

OP가 삽입 한 ID 값 뒤에있는 것 같습니다.이 경우 8998이 올바르지 않습니다. 내가 언급 한 엣지 케이스 (뒤로 증가 및 IDENTITY_INSERT 켜짐)는 IDENT_CURRENT를 사용하는 것에 대해 더 나아가 내 의견으로는 논쟁 을 일으키며 트리거의 위험 때문에 (지금 또는 나중에 추가됨) @@ IDENTITY를 사용해서는 안됩니다. 나는 왜 IDENT_CURRENT가 OP가 사용하기를 원하는지 (특히 동시성에서) 왜 더 안정적인 방법이 존재할 때 누군가가 @@ IDENTITY를 사용하는지 이해하기 위해 고심하고 있습니다.
Aaron Bertrand

@AaronBertrand 원하는 결과가 현재 범위의 마지막 삽입물이라는 점에서 100 % 명확하지 않습니다 (옵션 1과 관련하여 옵션 1이 2와 3이 다름). 다르다. 그러나 나는 그것이 @@IDENTITY결코 신원 가치를 창출하는 이상적인 방법이 아니라는 데 동의 합니다. 요점은 MAX()또는의 TOP 1신뢰성이 떨어지는 버전과 같다는 IDENT_CURRENT()것입니다. 유지 보수 작업이나 무언가에 유용 할 수 있습니다.
db2
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.