【问题标题】:Can I optimize this SQL remote update?我可以优化这个 SQL 远程更新吗?
【发布时间】:2011-07-12 16:09:24
【问题描述】:

我有这个更新远程表的 sql 更新语句。有什么办法可以优化/加速这段代码?它作为存储过程的一部分运行。

DECLARE @WIP Table(Item varchar(25), WIP int)

--Get Work In Progress Numbers
INSERT INTO @WIP
select (UPC.ItemPrefix + '-' + UPC.ItemCode) As Item, SUM(PO.Quantity) As WIP
--into #WIP
from [NCLGS].[dbo].[AL_ItemUPCs] UPC
INNER JOIN al_PO PO ON PO.UPCID = UPC.UPCID
where PO.status in ('Assigned', 'New', 'UnAssigned', 'WaitingForFile')
Group by  (UPC.ItemPrefix + '-' + UPC.ItemCode)

--SLOW PART, takes over 17 minutes
UPDATE [Server].[Database].[dbo].[Item]  
SET     QtyOnHand = IH.QtyOnHand,
        QtyWorkInProgress = W.WIP   
FROM Avanti_InventoryHeader IH
INNER JOIN [Server].[Database].[dbo].[Item] I ON I.ItemNumber = IH.ItemNumber
LEFT JOIN @WIP W ON IH.ItemNumber = W.Item
WHERE isnumeric(left(IH.ItemNumber, 2)) = 0

【问题讨论】:

  • 您估计@wip 表中通常会有多少条记录?
  • @Jose Chama - 531 我上次运行它。会长得很慢。

标签: sql sql-server tsql sql-server-2000


【解决方案1】:

我过去也遇到过类似的问题,我不得不使用动态 SQL 来提高性能。

我发现当我加入本地临时表和远程表时,SQL 会将所有数据带到本地服务器,然后过滤 where 语句中的内容。

在这种情况下,我会尝试在动态查询中使用 SELECT UNION ALL 将整个变量表 @WIP 作为嵌套表传递。

我说的是这样的:

 DECLARE @WIP Table(Item varchar(25), WIP int)

    --Get Work In Progress Numbers
    INSERT INTO @WIP
    select (UPC.ItemPrefix + '-' + UPC.ItemCode) As Item, SUM(PO.Quantity) As WIP
    --into #WIP
    from [NCLGS].[dbo].[AL_ItemUPCs] UPC
    INNER JOIN al_PO PO ON PO.UPCID = UPC.UPCID
    where PO.status in ('Assigned', 'New', 'UnAssigned', 'WaitingForFile')
    Group by  (UPC.ItemPrefix + '-' + UPC.ItemCode)

declare @SQL VARCHAR(MAX)

set @SQL = '
UPDATE [Server].[Database].[dbo].[Item]  
SET     QtyOnHand = IH.QtyOnHand,
        QtyWorkInProgress = W.WIP   
FROM Avanti_InventoryHeader IH
INNER JOIN [Server].[Database].[dbo].[Item] I 
    ON I.ItemNumber = IH.ItemNumber
LEFT JOIN ('

select @SQL = @SQL + 'select '''+w.Item+''' as Item, 
    '''+cast( w.WIP as varchar(50))+''' as WIP union all '
from @WIP W

set @SQL = @SQL + ' select NULL,0 ) W   
    ON IH.ItemNumber = W.Item
WHERE isnumeric(left(IH.ItemNumber, 2)) = 0 '

PRINT @SQL 

它看起来不是很整洁,但它可能对你有用,就像对我一样。

【讨论】:

  • -我不确定这有什么帮助?动态 SQL 不解析查询然后做完全相同的事情吗?
  • 在我的情况下,我需要从远程服务器检索几千行,然后我加入了一个包含我需要的临时表。然后我发现它带来了整个表(这就是我认为您的更新现在正在做的事情),所以我创建了一个动态 SQL,其中包含我需要检索的所有 ID。我知道这不是很好,但它将时间减少到毫秒。
  • 我刚刚添加了一些代码来向您展示我在说什么。基本上,您会将整个变量表 @wip 作为“全选联合”嵌套表传递给远程服务器。
  • 它就像一个 UNION 但它的性能更好,因为它不运行不同的。查看这篇文章:bit.ly/oD6gtL
【解决方案2】:

我会先尝试将项目加载到本地表变量中,然后再进行连接。

DECLARE @WIP Table ( Item varchar(25), WIP int )
  --Get Work In Progress Numbers 
INSERT  INTO @WIP
        select  ( UPC.ItemPrefix + '-' + UPC.ItemCode ) As Item,
                SUM(PO.Quantity) As WIP 
        --into #WIP 
        from    [NCLGS].[dbo].[AL_ItemUPCs] UPC
                INNER JOIN al_PO PO ON PO.UPCID = UPC.UPCID
        where   PO.status in ( 'Assigned', 'New', 'UnAssigned',
                               'WaitingForFile' )
        Group by ( UPC.ItemPrefix + '-' + UPC.ItemCode )  

DECLARE @Item TABLE (ItemNumber  INT PRIMARY KEY, QtyOnHand INT)
SELECT ItemNumber, QtyOnHand
FROM   [Server].[Database].[dbo].[Item]    

--SLOW PART, takes over 17 minutes 
UPDATE  [Server].[Database].[dbo].[Item]
SET     QtyOnHand = IH.QtyOnHand,
        QtyWorkInProgress = W.WIP
FROM    Avanti_InventoryHeader IH
        INNER JOIN @item I ON I.ItemNumber = IH.ItemNumber
        LEFT JOIN @WIP W ON IH.ItemNumber = W.Item
WHERE   isnumeric(left(IH.ItemNumber, 2)) = 0 

此外,您可以考虑通过从表变量中删除未更新的记录并仅将更新的记录加入链接服务器来进一步限制更新。

DECLARE @Item TABLE
    (
      ItemNumber INT PRIMARY KEY,
      QtyOnHand INT,
      updated BIT DEFAULT ( 0 ),
      WIP int
    )
SELECT  ItemNumber,
        QtyOnHand
FROM    [Server].[Database].[dbo].[Item] 

UPDATE  i
SET     i.QtyOnHand = ih.QtyOnHand,
        updated = 1
FROM    @item i
        INNER JOIN Avanti_InventoryHeader IH ON I.ItemNumber = IH.ItemNumber
        LEFT JOIN @WIP W ON IH.ItemNumber = W.Item
WHERE   isnumeric(left(IH.ItemNumber, 2)) = 0  

DELETE FROM @item WHERE updated = 0

UPDATE  I
SET     QtyOnHand = IH.QtyOnHand,
        QtyWorkInProgress = IH.WIP
FROM    [Server].[Database].[dbo].[Item] I
        INNER JOIN @item IH ON I.ItemNumber = IH.ItemNumber

【讨论】:

  • -但是如果我不加入,SQL 将如何知道 Item 中的哪些行要更新?
  • -我确定我只是错过了它,但是您的第一个示例更新了远程表而不加入它,而您的第二个示例通过加入它来更新远程表。其中一个是错误的吗?
  • 首先我将整个表从远程服务器拉到一个表变量中。然后对表变量做所有的工作。完成后,我通过加入预处理且可能更小的数据集写回远程表。也许它会有所帮助..不确定。
【解决方案3】:

尝试在此存储过程调用的远程服务器上创建一个存储过程。

在远程存储过程中,将需要的数据拉到远程服务器上到临时表中。然后在远程服务器上执行 UPDATE / JOIN。

根据我的经验,尝试跨链接服务器进行联接可能会非常慢...而且在进行任何联接之前在一台或另一台服务器上获取所有必需的数据通常更快。

【讨论】:

  • -我不确定他们是否会让我在远程服务器(它不是我们的)上放置一个存储过程,但我可能必须尝试。
【解决方案4】:

我发现了查询的真正问题,它更新了数千条记录,即使这些记录没有改变。所以我查询了更改的记录,将其保存在表变量中,并且只更新了更改的记录。整个过程(不仅仅是这部分)从 16 分 44 秒缩短到 1 分 26 秒。

--BEGIN EXPERIMENTAL ITEM UPDATE SECTION
    DECLARE @WIP Table(Item varchar(25), WIP int)

    --Get Work In Progress Numbers
    INSERT INTO @WIP
    select (UPC.ItemPrefix + '-' + UPC.ItemCode) As Item, SUM(PO.Quantity) As WIP
    --into #WIP
    from [NCLGS].[dbo].[AL_ItemUPCs] UPC
    INNER JOIN al_PO PO ON PO.UPCID = UPC.UPCID
    where PO.status in ('Assigned', 'New', 'UnAssigned', 'WaitingForFile')
    Group by  (UPC.ItemPrefix + '-' + UPC.ItemCode)

    Declare @Remote Table(Item varchar(25), QtyOnHand int, WIP int)

    INSERT INTO @REMOTE
    Select ItemNumber, QtyOnHand, QtyWorkInProgress
    from [BMPR.COM].[NCL-CustomerPortal].[dbo].[Item]

    DECLARE @ItemsToUpdate Table (Item varchar(50))

    INSERT INTO @ItemsToUpdate
    Select R.Item
    From @Remote R
    Inner join Avanti_InventoryHeader IH ON R.Item = IH.ItemNumber
    LEFT JOIN @WIP W ON R.Item = W.Item
    Where R.QtyOnHand <> IH.QtyOnHand 
    OR R.WIP <> W.WIP

    --Select * from @ItemsToUpdate

    UPDATE [BMPR.COM].[NCL-CustomerPortal].[dbo].[Item]  
    SET     QtyOnHand = IH.QtyOnHand,
            QtyWorkInProgress = W.WIP   
    FROM Avanti_InventoryHeader IH
    INNER JOIN [BMPR.COM].[NCL-CustomerPortal].[dbo].[Item] I ON I.ItemNumber = IH.ItemNumber
    LEFT JOIN @WIP W ON IH.ItemNumber = W.Item
    WHERE I.ItemNumber in ( Select * from @ItemsToUpdate )
--END EXPERIMENTAL ITEM UPDATE SECTION

有关于这个方法的cmet吗?

【讨论】:

    【解决方案5】:

    PostgreSQL 的 UPDATE 中有一个 ONLY 子句,它只会更新提到的表。否则,它会尝试更新您要加入的所有表,这可能是瓶颈所在。您使用的是什么类型的 SQL?如果是 Postgres,可能是其他一些,尝试将更新行更改为

    UPDATE ONLY [Server].[Database].[dbo].[Item]
    

    【讨论】:

      猜你喜欢
      • 2011-04-25
      • 2018-01-11
      • 1970-01-01
      • 2022-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-15
      • 1970-01-01
      相关资源
      最近更新 更多