열에서 고유 한 데이터에 대한 올바른 패턴은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/463421

  •  19-08-2019
  •  | 
  •  

문제

다음 스키마가있는 테이블 [파일

CREATE TABLE [dbo].[File]
(
    [FileID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](256) NOT NULL,
 CONSTRAINT [PK_File] PRIMARY KEY CLUSTERED 
(
    [FileID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

아이디어는 FileID가 테이블의 키로 사용되며 이름은 파일을 나타내는 완전한 자격을 갖춘 경로라는 것입니다.

내가하려고했던 것은 이름이 이미 사용 중인지 확인하기 위해 저장된 절차를 만드는 것입니다. 그렇다면 해당 레코드를 사용하여 새 레코드를 만듭니다.

그러나 스트레스를 받으면 많은 스레드가 저장 프로 시저를 한 번에 실행하여 코드를 테스트하면 다른 오류가 발생합니다.

이 버전의 코드는 교착 상태를 만들고 클라이언트에 교착 상태 예외를 던집니다.

CREATE PROCEDURE [dbo].[File_Create]
    @Name varchar(256)
AS
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    BEGIN TRANSACTION xact_File_Create
    SET XACT_ABORT ON

    SET NOCOUNT ON 
    DECLARE @FileID int
    SELECT @FileID = [FileID] FROM [dbo].[File] WHERE [Name] = @Name
    IF @@ROWCOUNT=0
    BEGIN
        INSERT INTO [dbo].[File]([Name])
        VALUES (@Name)
        SELECT @FileID = [FileID] FROM [dbo].[File] WHERE [Name] = @Name
    END

    SELECT * FROM [dbo].[File]
    WHERE [FileID] = @FileID

    COMMIT TRANSACTION xact_File_Create
GO

이 버전의 코드는 이름 열에서 동일한 데이터로 행을 얻습니다.

CREATE PROCEDURE [dbo].[File_Create]
    @Name varchar(256)
AS
    BEGIN TRANSACTION xact_File_Create

    SET NOCOUNT ON 
    DECLARE @FileID int
    SELECT @FileID = [FileID] FROM [dbo].[File] WHERE [Name] = @Name
    IF @@ROWCOUNT=0
    BEGIN
        INSERT INTO [dbo].[File]([Name])
        VALUES (@Name)
        SELECT @FileID = [FileID] FROM [dbo].[File] WHERE [Name] = @Name
    END

    SELECT * FROM [dbo].[File]
    WHERE [FileID] = @FileID

    COMMIT TRANSACTION xact_File_Create
GO

이런 유형의 행동을 수행하는 올바른 방법이 무엇인지 궁금합니다. 일반적으로 이것은 열 데이터가 단일 열 또는 여러 열에서 고유 한 곳에서 사용하고 다른 열이 키로 사용되는 곳에서 사용하고 싶은 패턴입니다.

감사

도움이 되었습니까?

해결책

당신이 이름 필드에서 크게 검색하는 경우, 당신은 아마도 그것을 고유 한 것으로 인덱싱하고 아마도 이것이 클러스터링 될 것입니다. 일 순위 검색 필드). 첫 번째 선택에서 @FileID를 사용하지 않으므로 Name = @Name이있는 파일에서 카운트 (*)를 선택하고 0보다 큰지 확인합니다 (이는 SQL이 테이블의 잠금 장치를 유지하지 못하게합니다. 열이 선택되지 않으므로 검색 단계).

귀하의 행동은 이름이 존재하는 후속 쿼리 성공 또는 실패에 영향을 미치기 때문에 직렬화 가능한 레벨을 사용하는 올바른 과정에 있습니다. 해당 세트가없는 버전이 복제를 일으키는 이유는 두 개의 선택이 동시에 실행되어 레코드가 없다는 것을 발견했기 때문에 둘 다 삽입물 (중복을 생성)으로 진행했기 때문입니다.

이전 버전의 교착 상태는 검색 프로세스를 오랜 시간이 걸리는 인덱스가 없기 때문일 가능성이 높습니다. 직렬화 가능한 트랜잭션에 서버를 다운로드하면 다른 모든 것은 작업이 완료 될 때까지 기다려야합니다. 색인 ~해야 한다 작업을 빠르게 만들지 만 테스트만으로는 충분히 빠른지 나타냅니다. 다시 제출함으로써 실패한 거래에 응답 할 수 있습니다. 실제 상황에서는 부하가 일시적이기를 바랍니다.

편집 : 테이블을 색인화하지만 직렬화가 가능하지 않으면 세 가지 사례가 있습니다.

  • 이름이 발견되고 ID가 캡처되어 사용됩니다. 흔한
  • 이름은 찾을 수 없으며 예상대로 삽입합니다. 흔한
  • 이름을 찾을 수없고, 다른 정확한 일치가 첫 번째 밀리 초 이내에 게시되었으므로 삽입 실패가 실패합니다. 매우 드 rare

나는이 마지막 사례가 진정으로 예외적 일 것으로 예상되므로,이 매우 드문 경우를 포착하기 위해 예외를 사용하는 것이 일련 화 할 수있는 관여하는 것이 바람직하며, 이는 심각한 성능 결과를 초래할 것입니다.

만약 당신이 실제로 동일하게 밀리 초 이내에 게시물을 갖는 것이 일반적이라는 기대가 있다면 새로운 이름, 인덱스와 함께 직렬화 가능한 트랜잭션을 사용하십시오. 일반적인 경우에는 느려지지만 이러한 게시물이 발견되면 더 빠릅니다.

다른 팁

먼저 이름 열에서 고유 인덱스를 만듭니다. 그런 다음 클라이언트 코드에서 FileID를 선택하고 Where 절에 이름을 넣어 이름이 존재하는지 확인하십시오. 그렇다면 FileID를 사용하십시오. 그렇지 않은 경우 새 제품을 삽입하십시오.

존재하는 기능을 사용하면 물건을 조금 정리할 수 있습니다.

if (Exists(select * from table_name where column_name = @param)
begin
  //use existing file name
end
else
  //use new file name
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top