2011-03-29 120 views
1

我有一個更新表(30列和約150 000行)的簡單查詢。SQL:查詢超時已過期

例如:

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

這個查詢將影響約2500行。

的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 

將產生2500^2 = 6250000記錄從INSERTEDDELETED笛卡爾乘積(即的兩個表中的所有記錄所有可能的組合),其將被插入到tbl1

這就是你想要做的?

最可能的是,你想加入的表上的PRIMARY KEY

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 

這將把更新到PK爲刪除記錄和插入另外,一個新的PK

+0

其實什麼記錄看起來我錯了,以及,可能是打算工會都在那裏,而不是加入 – 2011-03-29 12:33:35

+0

@Sam:我相信在日誌表中的每個記錄包含兩個新的和舊版本的記錄。 – Quassnoi 2011-03-29 12:39:03

+0

是的,我看到了,我確實upvote你,因爲這是一個很好的答案。然而,這裏的日誌記錄機制看起來有點臃腫,我猜之前在同一行後可以節省一些時間,因爲它更容易診斷(相對於有2行) – 2011-03-29 12:59:54

0

感謝Quassnoi,這是一個好主意,「完全聯合」。它幫助了我。

此外,我嘗試更新表中的部分(一次1000個項目),使我的代碼更快的工作,因爲對於某些companyId我需要更新超過160 000行。

代替舊代碼:

 
    
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 2011-03-29 17:16:36

+0

在沒有'order by'的情況下,用什麼標準選擇前N行?你如何確保你從表var中刪除了與剛在tblSomeTable中更新的ID相同的ID? – 2011-03-30 09:56:57

+0

此外,你似乎試圖使用SO,就好像它是一個論壇,嚴格來講,它不是。我的意思是,你已經發布了更多的問題作爲答案,這會讓事情變得更糟。通常情況下,你應該簡單地編輯你的原始帖子添加。 – 2011-03-30 10:01:22