使此SQL查询更有效

Lei*_*igh 1 c# sql foreach

我有以下查询,它根据采购订单检查收货,以查看最初订购的商品以及通过收货预订的商品数量.例如,我下了10个香蕉奶昔的采购订单,然后我生成了一个收据,说明我在所述采购订单上收到了5个这样的奶昔.

SELECT t.PONUM, t.ITMNUM, t.ordered, 
       SUM(t.received) as received, 
       t.ordered - ISNULL(SUM(t.received),0) as remaining, 
       SUM(t.orderedcartons) as orderedcartons, 
       SUM(t.cartonsreceived) as cartonsreceived, 
       SUM(t.remainingcartons) as remainingcartonsFROM(SELECT pod.PONUM, 
       pod.ITMNUM, pod.QTY as ordered, ISNULL(grd.QTYRECEIVED, 0) as received, 
       pod.DELIVERYSIZE as orderedcartons, 
       ISNULL(grd.DELIVERYSIZERECEIVED, 0) as cartonsreceived, 
       (pod.DELIVERYSIZE - ISNULL(grd.DELIVERYSIZERECEIVED, 0)) as remainingcartons
FROM TBLPODETAILS pod 
  LEFT OUTER JOIN TBLGRDETAILS grd 
    ON pod.PONUM = grd.PONUM and pod.ITMNUM = grd.ITMNUM) t
GROUP BY t.ITMNUM, t.PONUM, t.ordered
ORDER BY t.PONUM
Run Code Online (Sandbox Code Playgroud)

返回以下数据:

PONUM   ITMNUM  ordered received remaining orderedcartons cartonsreceived remainingcartons

1       1     5.0000    3.0000      2.0000   5.0000         3.0000          2.0000
Run Code Online (Sandbox Code Playgroud)

接下来我有一个C#循环来根据我从上面的查询中获得的数据生成更新查询:

foreach (DataRow POUpdate in dt.Rows) {...

query += "UPDATE MYTABLE SET REMAININGITEMS=" + remainingQty.ToString() 
       + ", REMAININGDELIVERYSIZE=" + remainingBoxes.ToString() + " WHERE ITMNUM=" 
       + itemNumber + " AND PONUM=" + poNumber + ";";
Run Code Online (Sandbox Code Playgroud)

然后,我对DB执行每个更新查询.哪个在我的本地开发机器上工作正常.

但是,部署到生产服务器会在第一次查询时回收超过150,000条记录.

所以循环这么多行会锁定SQL和我的应用程序.是foreach吗?是原始选择将所有数据加载到内存中吗?都?我可以将此查询转换为单个查询并删除C#循环吗?如果是这样,最有效的方法是什么?

Dav*_*eim 5

在SQL中,目标应该是立即在整个表上编写操作.这样做SQL服务器非常有效,但是在任何交互上都需要很大的开销,因为它需要处理事务的一致性,原子性等等.所以在某种程度上,每个事务的固定成本很高,因为服务器做它的事情,但是事务中额外行的边际成本非常低 - 更新1m行可能比更新10行快1/2.

这意味着foreach将导致SQL服务器不断地与您的应用程序来回,并且每次都会发生锁定/解锁和执行事务的固定成本.

你能编写查询来在SQL中运行,而不是在C#中操作数据吗?看来你想根据你的select语句编写一个相对简单的更新(例如,根据ID匹配,参见从一个表到另一个表的SQL更新.

尝试类似下面的内容(未经过代码测试,因为我无法访问您的数据库结构等):

UPDATE MYTABLE 
  SET REMAININGITEMS = remainingQty, 
  REMAININGDELIVERYSIZE=remainingBoxes
From 
(SELECT t.PONUM, t.ITMNUM, t.ordered, 
       SUM(t.received) as received, 
       t.ordered - ISNULL(SUM(t.received),0) as remaining, 
       SUM(t.orderedcartons) as orderedcartons, 
       SUM(t.cartonsreceived) as cartonsreceived, 
       SUM(t.remainingcartons) as remainingcartonsFROM(SELECT pod.PONUM, 
       pod.ITMNUM, pod.QTY as ordered, ISNULL(grd.QTYRECEIVED, 0) as received, 
       pod.DELIVERYSIZE as orderedcartons, 
       ISNULL(grd.DELIVERYSIZERECEIVED, 0) as cartonsreceived, 
       (pod.DELIVERYSIZE - ISNULL(grd.DELIVERYSIZERECEIVED, 0)) as remainingcartons
FROM TBLPODETAILS pod 
  LEFT OUTER JOIN TBLGRDETAILS grd 
    ON pod.PONUM = grd.PONUM and pod.ITMNUM = grd.ITMNUM) t
GROUP BY t.ITMNUM, t.PONUM, t.ordered
ORDER BY t.PONUM ) as x

join MYTABLE on MYTABLE.ITMNUM=x.itmnum AND MYTABLE.PONUM=i.ponum
Run Code Online (Sandbox Code Playgroud)

  • AS在问题的评论中指出,SQL注入可能是一个问题.如果您没有为更新添加任何输入,则此查询可以避免这种可能性. (2认同)