2011-03-29 6 views
1

나는 업데이트 테이블 (30 열과 약 150 000 행)에 대한 간단한 쿼리가 있습니다. 예를 들어SQL : 쿼리 시간 초과가 만료되었습니다.

:이 쿼리는 약 2500 행이 영향을받는 것

UPDATE tblSomeTable set F3 = @F3 where F1 = @F1 

.

tblSomeTable 트리거가 있습니다

ALTER TRIGGER [dbo].[trg_tblSomeTable] 
    ON [dbo].[tblSomeTable] 
    AFTER INSERT,DELETE,UPDATE 
AS 
BEGIN 
    declare @operationType nvarchar(1) 
    declare @createDate datetime 
    declare @UpdatedColumnsMask varbinary(500) = COLUMNS_UPDATED() 


-- detect operation type 
if not exists(select top 1 * from inserted) 
    begin 
     -- delete 
     SET @operationType = 'D' 
     SELECT @createDate = dbo.uf_DateWithCompTimeZone(CompanyId) FROM deleted 
    end 
else if not exists(select top 1 * from deleted) 
    begin 
     -- insert 
     SET @operationType = 'I' 
     SELECT @createDate = dbo..uf_DateWithCompTimeZone(CompanyId) FROM inserted 
    end 
else 
    begin 
     -- update 
     SET @operationType = 'U' 
     SELECT @createDate = dbo..uf_DateWithCompTimeZone(CompanyId) FROM inserted 
    end 


-- log data to tmp table 

INSERT INTO tbl1 
SELECT 
    @createDate, 
    @operationType, 
    @status, 
    @updatedColumnsMask, 
    d.F1, 
    i.F1, 
    d.F2, 
    i.F2, 
    d.F3, 
    i.F3, 
    d.F4, 
    i.F4, 
    d.F5, 
    i.F5, 
    ... 

FROM (Select 1 as temp) t 
LEFT JOIN inserted i on 1=1 
LEFT JOIN deleted d on 1=1 

END 

을 그리고 업데이트 쿼리를 실행하면 나는 시간 제한이있다.

타임 아웃을 방지하기 위해 논리를 어떻게 최적화 할 수 있습니까?

감사합니다.

답변

4

이 쿼리

SELECT * 
FROM (
     SELECT 1 AS temp 
     ) t 
LEFT JOIN 
     INSERTED i 
ON  1 = 1 
LEFT JOIN 
     DELETED d 
ON  1 = 1 

tbl1가 삽입된다 (즉, 두 테이블의 모든 레코드의 모든 가능한 조합이다) 및 INSERTEDDELETED의 카티 생성물로부터 2500^2 = 6250000 레코드를 생성한다.

그게 당신이 원하는 것입니까?

대부분의 아마, 당신은 그들의 PRIMARY KEY에 테이블을 조인 할 :이 새로운 PK으로, 기록을 삭제하고 다른 삽입으로 PK에 업데이 트를 처리합니다

INSERT 
INTO tbl1 
SELECT @createDate, 
     @operationType, 
     @status, 
     @updatedColumnsMask, 
     d.F1, 
     i.F1, 
     d.F2, 
     i.F2, 
     d.F3, 
     i.F3, 
     d.F4, 
     i.F4, 
     d.F5, 
     i.F5, 
     ... 
FROM INSERTED i 
FULL JOIN 
     DELETED d 
ON  i.id = d.id 

.

+0

사실뿐만 아니라, 아마도이 –

+0

@Sam을 조인 대신 모두가 노동 조합을 의도 기록됩니다 나에게 잘못 보인다 : 나는 로그 테이블의 각 레코드는 신규 및 이전 버전을 모두 포함 믿는다 기록들. – Quassnoi

+0

그래, 나는 그것을보고 좋은 반응이 원인 upvote 않았다. 그러나 여기 로깅 메커니즘은 다소 부풀어 오른 것 같습니다. 이전에 같은 행에서 두 번째 행을 사용하는 것과는 대조적으로 더 쉽게 진단 할 수있는 시간을 절약 할 수 있다고 생각합니다. –

0

감사의 말 Quassnoi, "FULL JOIN"과 함께하는 것이 좋습니다. 그것은 나를 도왔다.

또한 일부 회사의 경우 160,000 개가 넘는 행을 업데이트해야하기 때문에 일부분 (1000 개 항목을 한 번에)으로 테이블을 업데이트하려고합니다. 대신 이전 코드의

:

 
    
UPDATE tblSomeTable set someVal = @someVal where companyId = @companyId 
 

내가 하나 아래 사용

 
    
declare @rc integer = 0 
declare @parts integer = 0 
declare @index integer = 0 
declare @portionSize int = 1000 

-- select Ids for update 
declare @tempIds table (id int) 
insert into @tempIds 
select id from tblSomeTable where companyId = @companyId 

-- calculate amount of iterations 
set @[email protected]@rowcount 
set @parts = @rc/@portionSize + 1 

-- update table in portions 
WHILE (@parts > @index) 
begin 

    UPDATE TOP (@portionSize) t  
    SET someVal = @someVal  
    FROM tblSomeTable t  
    JOIN @tempIds t1 on t1.id = t.id   
    WHERE companyId = @companyId   

    delete top (@portionSize) from @tempIds  
    set @index += 1   

end 
 

당신이 이것에 대해 어떻게 생각하십니까? 그것은 의미가 있습니까? 그렇다면 올바른 부분 크기를 선택하는 방법은 무엇입니까?

또는 간단한 업데이트도 좋은 해결책이 있습니까? 나는 지금 막 자물쇠를 피고 싶다.

감사

+0

해당 부분의 정수 수학을주의하십시오. – HLGEM

+0

'order by'가없는 경우 상위 N 개의 행을 선택하기 위해 어떤 기준이 사용됩니까?tblSomeTable에서 방금 업데이트 된 테이블과 동일한 ID를 테이블에서 삭제하는 방법은 무엇입니까? –

+0

또한 엄밀히 말하자면 포럼 인 것처럼 SO를 사용하려고하는 것 같습니다. 내 말은, 당신은 대답으로 추가 질문을 올렸습니다. 일반적으로 추가를 위해 원래 게시물을 편집하기 만하면됩니다. –

관련 문제