如何加快SQL Server 2008中的更新查询?

时间:2014-01-07 19:30:29

标签: sql sql-server sql-server-2008

update orders
set tname = (select top 1 t.task
                from task t
                where prod_typ='2' and sorder_nbr = t.ORDER_NBR
                order by t.strt_dt desc) 
where Prod_type='2'

update orders
set tname=  (select top 1 t.task
                from task t
                where  prod_typ='1' and sorder_nbr=t.ORDER_NBR
                order by t.strt_dt desc)
where Prod_type='1'

我正在尝试通过tname表中的最新任务更新orders表的task

prod_typ表的orders条件为1,sorder_nbr表的orderstask表的order_nbr相等

我的第一个更新语句适用于行为900k的行,第二个更新行为400k表示第二个更新语句需要一个多小时才能运行,最后我取消了查询

4 个答案:

答案 0 :(得分:3)

1)您查询和我的查询:

update orders
set tname = (select top 1 t.task
                from task t
                where prod_type='2' and order_nbr = t.ORDER_NBR
                order by t.strt_dt desc) 
where Prod_type='2';
go

update o
set tname = (select top 1 t.task
                from task t
                where prod_type='2' and o.order_nbr = t.ORDER_NBR
                order by t.strt_dt desc) 
from dbo.orders o
where Prod_type='2';
go

实际执行计划: enter image description here

如您所见,如果当前数据库的默认排序规则为CI(不区分大小写),则跟随谓词order_nbr=t.ORDER_NBR强制SQL Server将t.ORDER_NBR的值与值order_nbr列进行比较来自同一张表task t。查看与第一个查询对应的第一个执行计划。

要解决 这个问题,我已经使用了另一个别名 dbo.orders o我已经重新确定谓词o.order_nbr = t.ORDER_NBR。您也可以在第二个执行计划中看到这一点。

取决于每个order_num和&的任务数量。 prod_type你可以测试S#1,如果有很多任务,或S#2,如果每个order_num& prod_type。同样,您需要使用您的数据进行测试,以确定哪种解决方案更好。

2)解决方案#1:

UPDATE  o
SET     tname = 
        COALESCE(
            (SELECT  TOP(1) t.task
            FROM    dbo.task t
            WHERE   t.prod_type=o.Prod_type 
            AND     o.order_nbr = t.ORDER_NBR
            ORDER BY t.strt_dt DESC), tname
        ) 
FROM    dbo.orders o
WHERE   o.Prod_type IN ('1', '2');

3)解决方案#2:

UPDATE  o
SET     tname = lt.task
FROM    dbo.orders o 
INNER JOIN 
(
    SELECT  src.order_nbr, src.prod_type, src.task
    FROM (
        SELECT  t.ORDER_NBR, t.prod_type, t.task,
                ROW_NUMBER() OVER(PARTITION BY t.ORDER_NBR, t.prod_type ORDER BY t.strt_dt DESC) RowNum
        FROM    dbo.task t
    ) src 
    WHERE src.RowNum = 1
) lt -- last task
ON o.order_nbr = lt.ORDER_NBR AND o.prod_type = lt.prod_type
WHERE   o.Prod_type IN ('1', '2');

如果您有疑问,请随时提出。

4)dbo.task(order_nbr, prod_type, strt_dt) include (task)上的索引应该有助于两种解决方案。

5)你也应该公布实际的执行计划。

答案 1 :(得分:1)

尝试这样的事情。这将同时更新prod_type为1和2。

UPDATE orders
SET tname = t1.task
FROM orders o
CROSS APPLY (
    SELECT order_nbr, prod_type, t.task, row_number() OVER (PARTITION BY order_nbr, prod_type ORDER BY strt_dt DESC) rownumber
    FROM task t
    WHERE o.prod_type = t.prod_type
        AND o.order_nbr = t.order_nbr) t1
WHERE t1.rownumber = 1
    AND o.prod_type in (1,2)

答案 2 :(得分:1)

如果数据大小比我建议您使用变量更新表,或使用CTE更新

Update a table using CTE and NEWID()

Updating record using CTE?

我希望这会有所帮助

用tname(t.task)作为 (选择前1个t.task                 来自任务t                 其中prod_typ ='2',order_nbr = t.ORDER_NBR                 按t.strt_dt desc排序 插入订单(t.task)

答案 3 :(得分:-1)

使用CTE查询会加快这一点,因为不需要为每一行创建子查询,而是预先准备好。这是sqlfiddle

   ;with cteTaskNames as
   (
     select top 1 t.task
     from task t
     where  prod_type='2' and order_nbr=t.ORDER_NBR
     order by t.strt_dt desc
   )
   update orders
   set tname = (select task from cteTaskNames)
   where Prod_type='2'
   go

另外,     1)“prod_type”是整数字段还是字符串字段?     2)如果在cte中添加group by,则可以对订单执行内部联接,并使用cte查询立即运行所有更新,而不是执行每个查询。