2015-06-30 50 views
0

我正在執行我的應用程序中的SQL腳本。使用這個腳本,我從Product表中取數據並將其放入Table1。如果我直接從SSMS執行這個腳本,它將花費00:01:27分鐘。但使用應用程序,它給了我一個錯誤:超時過期。操作完成之前超時的時間或服務器沒有響應。SQL腳本花費太多時間並拋出超時錯誤

這裏是我的腳本:

-- Deleting [Table1] table if exists before creating because we don't need to keep track of records 
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'Table1')) 
BEGIN 
    DROP TABLE [dbo].[Table1] 
END 

-- Creating [Table1] table 
CREATE TABLE [dbo].[Table1] 
(
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [ProductId] [int] NOT NULL, 
    [MyStatus] [bit] NOT NULL, 
    [IsDeleted] [bit] NOT NULL, 
    [InTime] [datetime] NULL, 
    [StoreId] [int] NOT NULL, 
    [LanguageId] [int] NOT NULL, 

    PRIMARY KEY([Id]) 
); 

DECLARE @pId int 
DECLARE @sId int 

Truncate Table [dbo].[Table1] 

Insert Into [dbo].[Table1] (ProductId, MyStatus, IsDeleted, InTime, StoreId, LanguageId) 
    select distinct 
     p.Id, 1, 1, GETDATE(), s.Id, l.Id 
    from 
     [dbo].[Store] s, [dbo].[Product] p, [dbo].[Language] as l 
    left join 
     [dbo].[StoreMapping] sm on sm.EntityId = l.Id 
    where 
     (l.LimitedToStores = 1 and s.Id in (sm.StoreId) 
     and sm.EntityName = 'Language') or l.LimitedToStores = 0 

DECLARE tempCursor CURSOR SCROLL FOR 
    select 
     p.Id, sm.StoreId 
    from 
     [dbo].[Product] as p 
    join 
     [dbo].[StoreMapping] as sm on p.Id = sm.EntityId 
    join 
     [dbo].[Store] as s on sm.StoreId=s.Id 
    where 
     p.LimitedToStores = 1 and sm.EntityName = 'Product' 

OPEN tempCursor 
FETCH FIRST FROM tempCursor INTO @pId, @sId 

WHILE @@fetch_status = 0 
BEGIN  
    UPDATE [dbo].[Table1] 
    SET IsDeleted = 0 
    WHERE ProductId = @pId AND StoreId = @sId 

    FETCH NEXT FROM tempCursor INTO @pId, @sId; 
END 

CLOSE tempCursor 

UPDATE [dbo].[Table1] 
SET IsDeleted = 0 
where ProductId in (Select p.Id 
        from [dbo].[Product] as p 
        where p.LimitedToStores = 0) 

UPDATE [dbo].[Table1] 
SET IsDeleted = 1 
where ProductId in (Select p.Id 
        from [dbo].[Product] as p 
        where p.Published = 0 OR p.Deleted = 1 
         OR p.VisibleIndividually = 0) 

DEALLOCATE tempCursor 

誰能幫助我提高這個腳本?

+1

[不良習慣踢:使用舊式JOIN](http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/08/bad-habits-to-kick-using-old-style-joins.aspx) - 在ANSI-** 92 ** SQL St中,舊式*逗號分隔的表*樣式列表已替換爲* proper * ANSI'JOIN'語法andard(**超過20年前**),其使用是不鼓勵的。你應該**最肯定**不開始**混合**這些風格!採用適當的ANSI JOIN語法並在任何地方使用它 - 從現在開始。 –

+1

@marc_s非常不好的習慣踢:在SQL中使用循環而不是編寫單個語句...... –

+0

@SQLPolice:不能同意更多! –

回答

3

與光標的部分和循環通過它來設置IsDeleted=0在表1可以用下面的更新語句來代替:

UPDATE 
    [dbo].[Table1] 
SET 
    IsDeleted=0 
FROM 
    [dbo].[Product] AS p 
    JOIN [dbo].[StoreMapping] AS sm ON p.Id=sm.EntityId 
    JOIN [dbo].[Store] AS s ON sm.StoreId=s.Id 
    JOIN [dbo].[Table1] AS t1 ON t1.ProductId=p.Id AND t1.StoreId=s.Id 
WHERE 
    p.LimitedToStores=1 AND 
    sm.EntityName ='Product' 

最後兩個查詢好書面的JOIN

UPDATE 
    [dbo].[Table1] 
SET 
    IsDeleted=0 
FROM 
    [dbo].[Table1] AS t1 
    JOIN [dbo].[Product] AS p ON 
    p.Id=t1.ProductId 
WHERE 
    p.LimitedToStores=0 

UPDATE 
    [dbo].[Table1] 
SET 
    IsDeleted=1 
FROM 
    [dbo].[Table1] AS t1 
    JOIN [dbo].[Product] AS p ON 
    p.Id=t1.ProductId 
WHERE 
    p.Published=0 OR 
    p.Deleted=1 OR 
    p.VisibleIndividually=0 
+1

好的解決方案。一般說明@Ankita:在SQL Server中,您經常可以避免循環並將它們編寫爲一條語句。循環來自「程序思維」;但是,SQL是「面向集合」的。始終嘗試將您的解決方案看作您想用一條語句處理的一組數據。 –

+0

@SQLPolice是什麼非常真實,也許我應該明確地說過。 –

+0

@TT:我在產品表中有數百萬的數據,使用您的查詢我仍然收到相同的錯誤。請建議。 – Ankita