Могу ли я оптимизировать это удаленное обновление SQL? - PullRequest
4 голосов
/ 12 июля 2011

У меня есть 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

Ответы [ 5 ]

1 голос
/ 12 июля 2011

Я бы сначала попытался загрузить элементы в локальную переменную таблицы перед выполнением объединения.

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
1 голос
/ 12 июля 2011

В прошлом у меня была похожая проблема, и мне пришлось использовать динамический SQL для повышения производительности.

Я обнаружил, что когда я соединял локальную временную таблицу с удаленной таблицей, SQL переносил все данные на локальный сервер и затем фильтровал то, что у меня было в операторе where.

В этом случае я бы попытался передать всю таблицу переменных @WIP как вложенную таблицу, используя SELECT UNION ALL в динамическом запросе.

Я говорю о чем-то вроде этого:

 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 

Это выглядит не очень аккуратно, но может работать для вас так же, как и для меня.

0 голосов
/ 19 июля 2011

Я выяснил реальную проблему с запросом, он обновлял тысячи записей, даже если эти записи не изменились.Поэтому я запросил измененные записи, сохранил их в табличной переменной и обновил только измененные записи.Вся процедура (не только эта часть) прошла от 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

Есть ли какие-либо комментарии к этому методу?

0 голосов
/ 12 июля 2011

Попробуйте создать хранимую процедуру на удаленном сервере, которая вызывается этой хранимой процедурой.

В удаленной хранимой процедуре перетащите нужные данные на удаленный сервер во временные таблицы.Затем выполните ОБНОВЛЕНИЕ / ОБЪЕДИНЕНИЕ на удаленном сервере.

По моему опыту, попытка выполнить соединение через связанный сервер может быть очень медленной ... и зачастую быстрее получить все необходимые данные на одном сервере.сервер или другой, прежде чем делать какие-либо присоединения.

0 голосов
/ 12 июля 2011

В обновлении PostgreSQL есть предложение ONLY, которое будет обновлять только упомянутую таблицу.В противном случае он пытается обновить все таблицы, к которым вы присоединяетесь, и это может быть узким местом.Какой тип SQL вы используете?Если это Postgres, возможно, некоторые другие, попробуйте изменить строку обновления на

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