문제

나는 단일 테이블에 레코드를 삽입하는 가장 좋은 방법을 찾으려고 노력하고 있지만 항목이 아직 존재하지 않는 경우에만 가능합니다. 이 경우 핵심은 Nvarchar (400) 필드입니다. 이 예에서는 그것이 이름 인 척하자 단어 Oxford English Dictionary / Fav 사전을 여기에 삽입하십시오. 또한 단어 필드를 주요 키로 만들어야한다고 생각합니다. (테이블에는 고유 식별자 PK도 있습니다).

그래서 .. 테이블에 추가해야 할이 단어를 얻을 수 있습니다 ...

예를 들어.

  • 고양이
  • foo
  • 술집
  • 퓨 퓨
  • 등...

그래서 전통적으로 나는 다음을 시도 할 것입니다 (의사 코드)

SELECT WordID FROM Words WHERE Word = @Word
IF WordID IS NULL OR WordID <= 0
    INSERT INTO Words VALUES (@Word)

즉. 단어가 존재하지 않으면 삽입하십시오.

지금 .. 내가 걱정하는 문제는 우리가 많은 타격을 받고 있다는 것입니다. 그래서 선택과 삽입 사이에 다른 프로세스에서 단어를 삽입 할 수 있습니다. 그러면 제약 조건 오류가 발생합니다. ? (즉, a 경쟁 조건).

그런 다음 다음을 수행 할 수 있다고 생각했습니다 ...

INSERT INTO Words (Word)
SELECT @Word
WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word)

원래, 단어가 존재하지 않을 때 단어를 삽입하십시오.

구문은 제쳐두고, 테이블을 잠그는 방법 때문에 이것이 나쁘거나 좋은지 확실하지 않으며 (그렇다면) 테이블에 거대한 읽기와 많은 글을 얻는 테이블의 성능이 아닙니다.

그래서 - 당신은 SQL Gurus가 어떻게 생각하고 행동합니까?

나는 간단한 삽입과 '잡는'오류가 발생하기를 바랐다.

도움이 되었습니까?

해결책

솔루션 :

INSERT INTO Words (Word)
    SELECT @Word
WHERE NOT EXISTS (SELECT WordID FROM Words WHERE Word = @Word)

... 얻는 것만 큼 좋습니다. 이것으로 단순화 할 수 있습니다.

INSERT INTO Words (Word)
    SELECT @Word
WHERE NOT EXISTS (SELECT * FROM Words WHERE Word = @Word)

... 존재하기 때문에 실제로 레코드를 반환 할 필요는 없으므로 쿼리 최적화기는 요청한 필드를 보는 것을 귀찮게하지 않습니다.

그러나 언급 한 바와 같이, 이것은 삽입 중에 전체 테이블을 잠그기 때문에 특히 성능이 없습니다. 그 점을 제외하고, 고유 인덱스 (기본 키가 될 필요가 없음)를 Word에 추가하면 관련 페이지 만 잠겨 있으면됩니다.

최선의 선택은 예상 부하를 시뮬레이션하고 SQL Server 프로파일 러로 성능을 보는 것입니다. 다른 분야와 마찬가지로 조기 최적화는 나쁜 것입니다. 허용 가능한 성능 메트릭을 정의한 다음 다른 작업을 수행하기 전에 측정하십시오.

그것이 여전히 당신에게 충분한 성능을 제공하지 않는다면, 데이터웨어 하우징 분야의 많은 기술이 도움이 될 수 있습니다.

다른 팁

나는 이것에 대한 더 나은 (또는 적어도 더 빠른) 대답을 발견했다고 생각합니다. 다음과 같은 인덱스를 만듭니다.

CREATE UNIQUE NONCLUSTERED INDEX [IndexTableUniqueRows] ON [dbo].[table] 
(
    [Col1] ASC,
    [Col2] ASC,

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = ON, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

고유성을 정의하는 모든 열을 포함하십시오. 중요한 부분은 ingore_dup_key = on입니다. 그것은 독특한 삽입물을 경고로 바꿉니다. SSI는 이러한 경고를 무시하며 여전히 FastLoad를 사용할 수 있습니다.

MS SQL Server를 사용하는 경우 테이블 열에서 고유 해야하는 고유 인덱스를 만들 수 있습니다 (문서화 여기):

CREATE UNIQUE [ CLUSTERED | NONCLUSTERED ] INDEX <index_name>
    ON Words ( word [ ASC | DESC ])

지정하십시오 Clustered 또는 NonClustered, 귀하의 경우에 따라. 또한 (더 빠른 추구를 가능하게하기 위해) 정렬하려면 ASC 또는 DESC 정렬 순서를 위해.

보다 여기, 인덱스 아키텍처에 대해 더 많이 배우려면

그렇지 않으면 사용할 수 있습니다 UNIQUE CONSTRAINTS 문서화 된 것처럼 여기:

ALTER TABLE Words
ADD CONSTRAINT UniqueWord
UNIQUE (Word); 

나는 비슷한 문제가 있었고 이것이 내가 그것을 해결 한 방법입니다

insert into Words
( selectWord , Fixword)
SELECT word,'theFixword'
FROM   OldWordsTable
WHERE 
(
    (word LIKE 'junk%') OR
     (word LIKE 'orSomthing') 

)
and word not in 
    (
        SELECT selectWord FROM words WHERE selectWord = word
    ) 

고유 한 제약 조건은 명성이지만 한 가지 방법은 삽입 로직에 사용할 수도 있습니다.http://www.sqlteam.com/article/application-locks-or-mutexes-in-sql-server-2005

기본적으로 아래 표에 잠금 장치를 넣지 않으므로 존재 점검이 정상적으로 수행되는 동안 읽기에 대해 걱정하지 않습니다.

SQL 코드의 뮤트입니다.

MS SQL의 세부 사항에 대해서는 말할 수 없지만 SQL의 기본 키의 한 점은 고유성을 보장하는 것입니다. 따라서 일반적인 SQL 항의 정의에 따라 기본 키는 테이블에 고유 한 하나 이상의 필드입니다. 이 동작을 시행하는 다른 방법이 있지만 (이전 항목을 새로운 항목으로 바꾸는대로 대체) SQL MS 가이 동작을 시행하는 메커니즘이없고 그렇지 않은 경우 놀랄 것입니다. 새 항목을 거부하십시오. 기본 키를 Word 필드에 설정했는지 확인하십시오. ~해야 한다 일하다.

그러나 다시 한 번, 나는 이것이 MySQL 프로그래밍과 데이터베이스 클래스의 지식에서 비롯된 것이 아니므로 MS SQL의 복잡성을 벗어난 경우 사과드립니다.

declare @Error int

begin transaction
  INSERT INTO Words (Word) values(@word)
  set @Error = @@ERROR
  if @Error <> 0 --if error is raised
  begin
      goto LogError
  end
commit transaction
goto ProcEnd

LogError:
rollback transaction
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top