2010-06-16 3 views
1

SQL에 자체 ID (PK) 열을 유지해야하는 몇 가지 코드가 있습니다. 우리는 일괄 적으로 데이터를 삽입하는 테이블을 가지고 있지만 일괄 삽입이 완료되기 전에 관련 테이블에 데이터를 추가하므로 IDENTITY 열을 사용하여 값을 앞쪽으로 찾을 수 없습니다.데이터베이스에서 ID 값을 올바르게 예약하는 방법은 무엇입니까?

현재 코드가 필드의 MAX 값을 선택하고이를 1 씩 증가시킵니다. 응용 프로그램의 두 인스턴스가 동시에 실행될 가능성은 거의 없지만 여전히 스레드 안전성이 없습니다 (즉, 매번 데이터베이스에 연결된다는 것은 말할 것도 없습니다.)

저는 ADO.net 엔티티 모델을 사용하고 있습니다. 내가 사용할 ID의 범위를 '예약'하는 방법은 무엇이며, 그 범위가 다 떨어지면 사용할 새 블록을 가져 와서 동일한 범위가 사용되지 않도록하십시오.

+2

데이터 (자식 행과 부모 행)를 삽입하는 순서는 '외부 키'데이터 무결성을 적용하지 않는다는 것을 의미합니다. 이게 옳은 거니? 왜? – van

+0

동의 - 귀하의 프로세스가 거꾸로 된 것처럼 들립니다. 먼저 PK로 레코드를 작성한 다음 종속 레코드를 추가해야합니다. 아니면 당신은 당신의 일치를 위해 참 (대리가 아닌) PK를 사용해야합니다. – dkretz

+0

그게 옳은 이유는, 결정이 내려 졌을 때 내가 여기 없었기 때문에 나는 말할 수 없었습니다. 내 유일한 추측은 성과입니다. 부모 테이블은 한 번에 수백만 개의 레코드가 삽입되는 반면, 자식 레코드는 거의 없습니다. 사실 부모 테이블에서 항목을 삭제하는 동안 자식 테이블의 행이 삭제되지 않습니다. 다 대일 매핑 (부모 - 자식)이므로 삭제하지 않기로 한 것 같습니다. 나는 그것을 나중에 조사 할 수 있습니다. – esac

답변

3
  • 사용 이상의 범용 고유 식별자 데이터 유형. 이 경우 기본적으로 클라이언트 측에서 생성하여 SQL으로 전달하고 걱정할 필요가 없습니다. 단점은 물론이 필드의 크기입니다.
  • 데이터베이스에 간단한 테이블을 만들고 CREATE TABLE ID_GEN (ID INTEGER IDENTITY)을 입력하고 factory으로 사용하여 식별자를 제공하십시오. 이상적으로는 필요한 식별자 수를 전달할 수있는 저장 프로 시저 (또는 함수)를 만드는 것이 좋습니다. 저장 프로 시저가이 행 수 (비어 있음)를이 ID_GEN 테이블에 삽입하고 코드에서 사용할 수있는 모든 새 ID을 반환합니다. 당연히 원래 테이블에는 IDENTITY이 더 이상 없습니다.
  • 위에 ID_Factory의 변형을 만들 수 있습니다.

달리 제한하지 않으면 단순함 (UUID)을 선택합니다.

+0

팩토리 메서드는 내가 결국 사용하는 것입니다. 키 크기를 guid보다 작게 유지하고 주문하는 이점이 있습니다. – esac

3

테이블 구조를 변경하려면 행 생성 코드에 newid() [SQL] 또는 Guid.NewGuid() [C#]과 함께 uniqueidentifier을 사용하는 것이 좋습니다. 새의 GUID의 값이 모두 0 또는 임의의 다른 GUID와 동일하도록 매우 낮은 확률이

이다 Guid.NewGuid() DOCO 가입일

.

+0

나는 DBA가 아니지만 이것이 PK이기 때문에 클러스터 된 인덱스를 갖게 될 것입니다. 페이지 분할을 보장하기 때문에 ID를 유지하는 끔찍한 방법 일 것입니다. – esac

+0

아마도 결론을보십시오 : http://www.sql-server-performance.com/articles/per/guid_performance_p2.aspx 페이지 분할에 대한 귀하의 진술은 단지 귀하의 키가 더 큰 사실에 의해 증가된다는 것입니다. 그러나 삽입 된 행의 자연 순서가 더 이상 보존되지 않는다는 점에 유의해야합니다. 반드시 나쁜 것은 아닙니다. 또한 위의 주석을 참고하십시오. 외래 키 무결성이 항상 유지되도록 종속 행이 두 번째로 삽입되도록 삽입을 수정해야합니다. – Reddog

+0

이것은이 문제를 해결할 수있는 유일한 방법 인 IMHO입니다. 벌크 삽입을 위해 서버에 데이터를 보내기 전에 코드에 키를 할당 할 수 있다는 추가적인 이점이 있습니다. – NotMe

0

두 명의 클라이언트가 동일한 ID 블록을 예약 할 수 있습니다.

잠김으로써 삽입물을 직렬화 할 해결책이 없습니다.

MSDN의 Locking Hints을 참조하십시오. UNIQUEIDENTIFIER (UUID) 대신 INTEGER

0

당신은 PK를 변경하고 싶지 않은 많은 자식 테이블이 있습니다. 조인을 더 잘 수행하려면 정수 filedsa를 사용하십시오. 그러나 여전히 GUID 필드를 추가하고 미리 생성 된 값이있는 대량 삽입에 채울 수 있습니다. 그런 다음 신원 삽입물을 혼자 둘 수 있습니다 (거의 사용하지 않는 것이 좋습니다). 그리고 생성 한 GUID 값을 사용하여 방금 삽입 한 ID 값을 하위 테이블에 다시 가져올 수 있습니다.

대량 삽입 대신 일반 세트 기반 삽입 (values ​​절 대신 select 절에 하나씩 사용)을 사용하는 경우 SQL을 사용하는 경우 출력 절을 사용하여 행의 ID를 가져올 수 있습니다 Server 2008의

0

가장 일반적인 솔루션은 결코 데이터베이스 식별자를 통해 클라이언트 식별자를 생성이다 - 보통은 음의 값입니다 다음 삽입시 데이터베이스에 의해 생성 된 식별자로 식별자를 업데이트합니다.

이 방법은 많은 사용자와 응용 프로그램에서 사용하는 것이 안전 동시에 데이터를 삽입합니다. GUID를 제외한 다른 방법은 다중 사용자 안전이 아닙니다.

엔티티가 데이터베이스에 저장되기 전에 엔티티의 기본 키를 알아야하지만 GUID를 사용할 수없는 드문 경우 엔 식별자 중복을 방지하는 식별자 생성 알고리즘을 사용할 수 있습니다. 가장 간단한 방법은 연결된 각 클라이언트에 고유 한 식별자 접두어를 할당하고이 클라이언트가 생성 한 각 식별자 앞에 앞에 붙입니다.

ADO.NET Entity Framework를 사용하는 경우 식별자 생성에 대해 걱정할 필요가 없습니다. EF는 식별자를 자체적으로 생성하므로 엔티티의 기본 키를 IsDbGenerated = true로 표시하십시오.

엄밀히 객체가 아직 데이터베이스에 저장되지 않습니다에 대한 다른 ORM 같은 엔티티 프레임 워크는 식별자를 필요로하지 않는, 말, 올바르게 새 개체를 사용하여 작업하는 한 정도로 객체 참조입니다. 실제 기본 키 값은 업데이트/삭제 엔티티 및 새 엔티티, e.i.를 참조하는 엔티티의 업데이트/삭제/삽입시에만 필요합니다. 실제 기본 키 값이 데이터베이스에 기록 될 예정인 경우 엔티티가 새로운 경우 새로운 엔티티가 데이터베이스에 저장되지 않고 ORM이 엔티티 저장에 대한 참조 순서를 고려한 특정 순서를 유지할 때까지 새로운 엔티티를 참조하는 다른 엔티티를 저장할 수 없습니다.

2

왜 ETL 작업처럼 들리는 것을 할 ADO.net 엔티티 프레임 워크를 사용하고 있습니까? (아래의 일반적으로 ADO.NET Entity Framework 및 ORM에 대한 비평을 참조하십시오.

int를 사용하는 이유는 무엇입니까? uniqueidentifier를 사용하면 "실행중인 응용 프로그램의 여러 인스턴스"문제가 해결됩니다. 있는 int IDENTITY를 사용하는 것보다 느립니다 열 기본값으로 고유 식별자를 사용

... 그것은 INT보다 GUID를 생성하는 데 더 많은 시간이 걸립니다. guid는 int (4 바이트)보다 큽니다 (16 바이트). 먼저 시도해보고 만족스런 결과가 나오면 실행하십시오.

경우 일괄 GUID를 생성 (또는 다른 서버) 및 표에서 캐시 용인 삽입 각 행에 대한 GUID를 생성함으로써 도입 된 지연.

샘플 TSQL 코드 :

CREATE TABLE testinsert 
(
    date_generated datetime NOT NULL DEFAULT GETDATE(), 
    guid uniqueidentifier NOT NULL, 
    TheValue nvarchar(255) NULL 
) 
GO 

CREATE TABLE guids 
(
    guid uniqueidentifier NOT NULL DEFAULT newid(), 
    used bit  NOT NULL DEFAULT 0, 
    date_generated datetime NOT NULL DEFAULT GETDATE(), 
    date_used datetime NULL 
) 
GO 

CREATE PROCEDURE GetGuid 
@guid uniqueidentifier OUTPUT 
AS 
BEGIN 
SET NOCOUNT ON 
DECLARE @return int = 0 

BEGIN TRY 
    BEGIN TRANSACTION 
    SELECT TOP 1 @guid = guid FROM guids WHERE used = 0 

    IF @guid IS NOT NULL 
    UPDATE guids 
    SET 
    used = 1, 
    date_used = GETDATE() 
    WHERE guid = @guid 
    ELSE 
    BEGIN 
    SET @return = -1 
    PRINT 'GetGuid Error: No Unused guids are available' 
    END 
    COMMIT TRANSACTION 
END TRY 

BEGIN CATCH 
    SET @return = ERROR_NUMBER() -- some error occurred 
    SET @guid = NULL 
    PRINT 'GetGuid Error: ' + CAST(ERROR_NUMBER() as varchar) + CHAR(13) + CHAR(10) + ERROR_MESSAGE() 
    ROLLBACK 
END CATCH 

RETURN @return 
END 
GO 

CREATE PROCEDURE InsertIntoTestInsert 
@TheValue nvarchar(255) 
AS 
BEGIN 
    SET NOCOUNT ON 
    DECLARE @return int = 0 

    DECLARE @guid uniqueidentifier 
    DECLARE @getguid_return int 

    EXEC @getguid_return = GetGuid @guid OUTPUT 

    IF @getguid_return = 0 
    BEGIN 
    INSERT INTO testinsert(guid, TheValue) VALUES (@guid, @TheValue) 
    END 
    ELSE 
    SET @return = -1 

    RETURN @return 
END 
GO 

-- generate the guids 
INSERT INTO guids(used) VALUES (0) 
INSERT INTO guids(used) VALUES (0) 

--Insert data through the stored proc 
EXEC InsertIntoTestInsert N'Foo 1' 
EXEC InsertIntoTestInsert N'Foo 2' 
EXEC InsertIntoTestInsert N'Foo 3' -- will fail, only two guids were created 

-- look at the inserted data 
SELECT * FROM testinsert 

-- look at the guids table 
SELECT * FROM guids 

재미있는 질문은 어떻게 ADO.Net의 엔티티 프레임 워크이지도 않아 ...인가?

이 ORM의 초기에 시작 고전적인 문제는 (객체 관계형 대응)입니다.

관계형 데이터베이스 모범 사례 (기본 테이블에 대한 직접 액세스를 허용하지 않고 뷰와 저장 프로 시저를 통한 데이터 조작 만 허용)를 사용하면 헤드 카운트 (데이터베이스 스키마뿐만 아니라 쓸 수있는 사람도 있지만 또한 모든 뷰와 API를 구성하는 저장 프로 시저)를 생성하고 지연 (실제로이 내용을 쓰는 시간)을 프로젝트에 도입합니다.

모든 사람들이 이것을 자르고 사람들은 이해하지 못하는 정규화 된 데이터베이스에 대해 직접 쿼리를 작성하므로 ORM,이 경우 ADO.NET Entity Framework가 필요합니다.

ORM은 나에게서 두려움을 두려워합니다. 나는 ORM 도구가 무의미하게 비효율적 인 쿼리를 생성하여 성능이 뛰어난 데이터베이스 서버를 무릎 꿇게 만듭니다. 프로그래머 생산성에서 얻은 결과는 최종 사용자 대기 및 DBA ​​좌절에서 사라졌습니다.

+0

ORM의 희소성에 동의합니다. 현존하는 코드 중 일부는 ADO.Net EM을 사용하고 방금 말한 것을 수행하여 시스템이 느려지 게했습니다. 그러나 EM을 사용하여 더 큰 규모의 응용 프로그램을 작성하고 프로파일 링 (Visual Studio + SQL 프로파일 러)에주의를 기울여 생성 된 쿼리를보고 효율적으로 수정했습니다. – esac