2009-05-20 2 views
5

SQL Server 2005 데이터베이스에 많이 사용되는 테이블이 있습니다. 그것은 우리의 제품을 가지고 있습니다. 우리는 창고에서 매 시간마다 업데이트를 받고 지난 몇 년 동안 우리는 테이블을 절단하고 정보를 업데이트하는 루틴을 운영해 왔습니다. 이것은 몇 초 밖에 걸리지 않으며 지금까지 문제가되지 않았습니다. 현재이 정보를 쿼리하는 우리 시스템을 사용하는 사람들이 더 많아 졌기 때문에 결과적으로 차단 프로세스로 인해 많은 시간 초과가 발생합니다. 테이블을 잠그지 않고 사용중인 테이블에서 데이터를 업데이트하는 가장 좋은 방법은 무엇입니까?

는 ... 그래서 ...

우리는 우리의 옵션을 연구하고 문제를 완화하기 위해 아이디어와 함께 올라와있다.

  1. 두 개의 테이블이 있습니다. 표 A (활성) 및 표 B (비활성).
  2. 활성 표 (표 A)를 가리키는보기를 작성합니다.
  3. 이 테이블 정보 (4 개 개체)를 필요로하는 모든 것들이 이제보기를 거쳐야합니다.
  4. 시간별 루틴은 비활성 테이블을 자르고 최신 정보로 업데이트 한 다음 비활성 테이블을 가리 키도록보기를 업데이트하여 활성 테이블로 만듭니다.
  5. 이 루틴은 어떤 테이블이 활성 상태인지 결정하고 기본적으로 뷰간에 전환합니다.

무엇이 문제입니까? 뷰 중간 쿼리를 전환하면 문제가 발생합니까? 이게 효과가 있니?

감사합니다.

추가 정보

  • 루틴이 많은 단계를 peforms SSIS 패키지 결국 /가 문제의 테이블을 업데이트 잘라

  • 블로킹 프로세스는이 쿼리를 다른 두 개의 저장 프로 시저입니다 표.

+0

는 두 개의 별도의 부하 분산 서버는 완벽한 대안을 제공 할 수있다. 라이브 하나를 유지하고 다른 하나를 업데이트 한 다음 전환합니다. –

답변

6

snapshot isolation을 사용 해본 적이 있습니까? 그것은 당신이 SSIS 물건에 대한 큰 뚱뚱한 거래를 시작하고 여전히 테이블에서 읽을 수 있습니다.

이 솔루션은 테이블을 전환하는 것보다 훨씬 깨끗해 보입니다.

+0

+1. 그것은 정확히 당신이해야만합니다. 이상적으로는 모든 것을 덤프 할 필요가없는 업데이트를 얻지 만 그렇지 않기 때문에 트릭은 트랜잭션을 시작하고 모든 것을 삭제하지 않고 모든 것을로드하는 것입니다. 당신이 커밋을 실행하는 순간, 데이터베이스는 갭이없이 모든 것을 바꿀 것입니다. –

+0

자르지 않는 이유는 무엇입니까? 모든 삭제가 기록되기 때문에 삭제하는 것이 더 느리지 않습니까? –

+0

그게 중요한 부분이라고 생각합니다. 스냅 샷 격리를 사용하면 사용자가 새 데이터를 볼 수있게됩니다. truncate는 기록되지 않고 transacton에 어떤 영향을 미칠지 모르겠지만 원하는 방식이 아닐 수도 있습니다. 사실 테이블에 보류중인 트랜잭션이있는 경우 잘라내기를 실패 할 것입니다. – Zack

2

나는 이것이 잘못된 방식으로 진행되고 있다고 생각합니다. 페이지를 업데이트하거나 테이블을 잠금으로 제한 할 수 있지만 테이블을 업데이트해야합니다.

테이블을 자르고 다시 채우지 않을 것입니다. 그것은 항상 그것을 읽으려는 사용자를 방해 할 것입니다.

테이블을 바꾸지 않고 업데이트 한 경우 다른 방법으로이를 제어 할 수 있습니다. 읽기 사용자는 테이블을 차단해서는 안되며 낙천적 인 읽기가 가능할 수도 있습니다.

읽기 SQL 뷰 문에 with (nolock) 힌트를 추가하십시오. 테이블이 정기적으로 업데이트되는 경우에도 매우 많은 양의 사용자가 읽을 수 있어야합니다.

+0

SQl 힌트, 특히 NOLOCK은 여러 가지 이유로 나쁘다는 것을 이해합니다. http://tinyurl.com/qwloxh –

+1

그들은 데이터의 사본을 만들고 잠금을 피하기 위해 뷰를 재구성하는 것만 큼 '나쁘다'. 가장 좋은 방법은 실제로 트랜잭션 등록 정보에 잠금을 설정하는 것이지만자를 사용하기 때문에 잠금을 설정할 수 없습니다. 또한이 기사에서 지적한 점에 동의하지 않습니다. 때로는 SQL 힌트가 교착 상태를 처리하는 가장 좋은 방법이지만 때로는 SQL 힌트를 사용하여 수행하는 작업을 이해해야합니다. – Keith

+0

아, 그리고 그렇게 하는군요 : http://www.codinghorror.com/blog/archives/001166.html – Keith

1

트랜잭션을 사용하여 자르기 작업보다는 정보를 업데이트하는 것이 좋습니다.

잘라 내기는 기록되지 않으므로 트랜잭션에서 수행 할 수 없습니다.

작업이 트랜잭션에서 수행되면 기존 사용자는 영향을받지 않습니다.

어떻게 수행 할 것인가는 테이블의 크기와 데이터가 근본적으로 바뀌는 방식에 따라 달라집니다. 좀 더 자세한 정보를 주시면 아마도 제가 더 조언 해 줄 수 있습니다.

+0

루틴은 SSIS 패키지이며 모든 것이 트랜잭션에서 실행되고있는 것으로 나타나며 이로 인해 차단이 발생합니다. –

2

개인적으로 테이블에 대해 일괄 처리 프로세스를 실행하기 위해 항상 시간을 들여야하는 경우 비즈니스/데이터 액세스 계층에서 사용자 환경을 관리해야한다고 개인적으로 생각합니다. 해당 테이블에 대한 연결을 모니터링하고 일괄 처리를 제어하는 ​​테이블 관리 개체를 도입하십시오.

새 배치 데이터가 준비되면 관리 개체는 모든 새 쿼리 요청을 중지하고 (대기열에 넣을 수도 있습니다) 기존 쿼리를 완료하고 일괄 처리를 실행 한 다음 쿼리에 대해 테이블을 다시 엽니 다. 관리 객체는 UI 레이어가 해석 할 수있는 이벤트 (BatchProcessingEvent)를 발생시켜 사람들이 해당 테이블을 현재 사용할 수 없음을 알릴 수 있습니다. 내 $ 0.02

,

네이트

+0

우리는 이것을 고려했으며이 옵션을 정말 좋아하지만, 더 많은 작업이 필요하며, 시간은 우리가 불행히도 호화로운 것이 아닙니다. 그러나 나는 서버 배치 프로세스와 상관없이 이것을 처리하는 것이 최적이라고 동의한다. –

0

우리는 우리의 높은 사용 시스템에서이 작업을 수행하고 문제가 없었어요. 그러나 모든 것 데이터베이스와 마찬가지로, dev에 변경을 가한 다음로드 테스트를하는 것이 도움이 될 수있는 유일한 방법입니다. SSIS 패키지가 아니라면 블럭이 계속 발생할 수 있습니다.

1

하나의 가능한 솔루션은 테이블을 업데이트하는 데 필요한 시간을 최소화하는 것입니다.

먼저웨어 하우스에서 데이터를 다운로드 할 준비 테이블을 만듭니다. 당신이해야 할 "삽입, 업데이트 및 삭제"하는 경우

최종 테이블

에서 피날레 표는 다음과 같습니다 가정 수 있습니다 :

Table Products: 
    ProductId  int 
    QuantityOnHand Int 

을 그리고 당신은 창고에서 QuantityOnHand를 업데이트해야합니다. 이 같은 "작업"테이블 만들기 다음

Table Prodcuts_WareHouse 
    ProductId  int 
    QuantityOnHand Int 

그리고 :

:

Table Prodcuts_Actions 
    ProductId  int 
    QuantityOnHand Int 
    Action   Char(1) 

업데이트 프로세스 사항은 다음과 같이해야한다

먼저 같은 준비 테이블을 만듭니다 1. 테이블 자르기 Prodcuts_WareHouse

2.Truncate table Prodcuts_Actions 0 3.Fill 창고

(4)로부터의 데이터와 Prodcuts_WareHouse 테이블.이와 함께 Prodcuts_Actions 테이블 채우기 :

인서트 :

INSERT INTO Prodcuts_Actions (ProductId, QuantityOnHand,Action) 
SELECT  SRC.ProductId, SRC.QuantityOnHand, 'I' AS ACTION 
FROM   Prodcuts_WareHouse AS SRC LEFT OUTER JOIN 
         Products AS DEST ON SRC.ProductId = DEST.ProductId 
WHERE  (DEST.ProductId IS NULL) 

이제 잠겨 있지 않은 최종 테이블까지

INSERT INTO Prodcuts_Actions (ProductId, QuantityOnHand,Action) 
SELECT  DEST.ProductId, DEST.QuantityOnHand, 'D' AS Action 
FROM   Prodcuts_WareHouse AS SRC RIGHT OUTER JOIN 
         Products AS DEST ON SRC.ProductId = DEST.ProductId 
WHERE  (SRC.ProductId IS NULL) 

업데이트

INSERT INTO Prodcuts_Actions (ProductId, QuantityOnHand,Action) 
SELECT  SRC.ProductId, SRC.QuantityOnHand, 'U' AS Action 
FROM   Prodcuts_WareHouse AS SRC INNER JOIN 
         Products AS DEST ON SRC.ProductId = DEST.ProductId AND SRC.QuantityOnHand <> DEST.QuantityOnHand 

을 삭제합니다.

5.In 거래는 최종 테이블 업데이트 :

위의 모든 과정을
BEGIN TRANS 

DELETE Products FROM Products INNER JOIN 
Prodcuts_Actions ON Products.ProductId = Prodcuts_Actions.ProductId 
WHERE  (Prodcuts_Actions.Action = 'D') 

INSERT INTO Prodcuts (ProductId, QuantityOnHand) 
SELECT ProductId, QuantityOnHand FROM Prodcuts_Actions WHERE Action ='I'; 

UPDATE Products SET QuantityOnHand = SRC.QuantityOnHand 
FROM   Products INNER JOIN 
Prodcuts_Actions AS SRC ON Products.ProductId = SRC.ProductId 
WHERE  (SRC.Action = 'U') 

COMMIT TRAN 

, 당신은 필요 최소한으로 업데이트 할 레코드의 양을 최소화하고, 그래서 시간이 최종 테이블이됩니다 업데이트하는 동안 잠겨 있습니다.

마지막 단계에서 트랜잭션을 사용하지 않아도되므로 명령 실행시 테이블이 해제됩니다.

1

SQL Server Enterprise Edition을 마음껏 사용할 수 있으면 SQL Server Partitioning 기술을 사용하는 것이 좋습니다.

현재 필요한 데이터는 '라이브'파티션에 있고 업데이트 된 버전의 데이터는 '보조'파티션 (쿼리를 위해 사용할 수는 없지만 데이터를 관리하는 데 사용할 수 있음)에있을 수 있습니다.

'보조'파티션으로 데이터를 가져 오면 'LIVE'파티션 OUT 및 'Secondary'파티션 IN을 즉시 전환 할 수 있으므로 가동 중지 시간이없고 차단되지 않습니다.

전환을 완료하면 더 이상 필요없는 데이터를 잘림없이 이전의 보조 데이터 (이전의 보조 파티션)의 사용자에게 영향을 줄 수 있습니다.

가져 오기 작업을 수행해야 할 때마다 프로세스를 반복/반전하기 만하면됩니다.

볼 SQL 서버 파티션에 대한 자세한 내용은 :

http://msdn.microsoft.com/en-us/library/ms345146(SQL.90).aspx

을 또는 당신은 단지

편집 :-) 저를 요청할 수 있습니다 : 보조 노트에

, 순서 모든 차단 문제를 해결하기 위해 SQL Server 행 버전 관리 기술을 사용할 수 있습니다.

http://msdn.microsoft.com/en-us/library/ms345124(SQL.90).aspx

+0

이것은 우리가보기로 달성하고자하는 아이디어이지만 SQL Server의 표준 버전 만 있습니다. 이것에 대해서 –

2

그냥 당신이 SSIS

을 사용하는 읽기

당신은에서 TableDiference 구성 요소를 사용할 수 있습니다 : 당신이에 의해, 테이블에 한 변경 사항을 적용 할 수 있습니다 http://www.sqlbi.eu/Home/tabid/36/ctl/Details/mid/374/ItemID/0/Default.aspx

alt text http://www.sqlbi.eu/Portals/0/Articles/Table%20Difference%20Images/DataFlowSimple.png

이 방법 단 하나지만 물론, 이것은 훨씬 더 느리게되며 테이블 크기에 따라 서버에서 더 많은 RAM이 필요하지만 잠금 문제는 완전히 수정됩니다.

0

테이블 크기가 크지 않으면 짧은 시간 동안 응용 프로그램의 데이터를 캐시 할 수 있습니다. 블로킹을 완전히 제거하지는 못하지만 업데이트가 발생할 때 테이블이 쿼리 될 가능성이 줄어 듭니다.

0

변경된 조경의 일부인 것처럼 보이기 때문에 차단중인 프로세스에 대한 분석을하는 것이 좋습니다. 자신이보고있는 블록을 만들기 위해 잘못 작성된 쿼리 하나만 걸립니다. 잘못 작성된 쿼리를 제외하면 테이블에 하나 이상의 커버 인덱스가 있어야 해당 쿼리의 속도가 빨라지고 이미 작동중인 코드를 다시 작성하지 않고도 다시 돌아올 수 있습니다. 당신은 라이센스가있는 경우이 도움이

희망,

관련 문제