2011-03-29 81 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