为什么更新操作比查询操作花费更长的时间?

9

我有以下的 select 语句,它几乎瞬间完成。

declare @weekending varchar(6)  
set @weekending = 100103

select InvoicesCharges.orderaccnumber, Accountnumbersorders.accountnumber  
from Accountnumbersorders, storeinformation, routeselecttable,InvoicesCharges, invoice   
where InvoicesCharges.pubid = Accountnumbersorders.publication  
and Accountnumbersorders.actype = 0  
and Accountnumbersorders.valuezone = 'none'  
and storeinformation.storeroutename = routeselecttable.istoreroutenumber   
and storeinformation.storenumber = invoice.store_number  
and InvoicesCharges.invoice_number = invoice.invoice_number  
and convert(varchar(6),Invoice.bill_to,12) = @weekending  

然而,等效的更新语句需要1分40秒。
declare @weekending varchar(6)
set @weekending = 100103
update InvoicesCharges  
set InvoicesCharges.orderaccnumber = Accountnumbersorders.accountnumber  
from Accountnumbersorders, storeinformation, routeselecttable,InvoicesCharges, invoice   
where InvoicesCharges.pubid = Accountnumbersorders.publication  
and Accountnumbersorders.actype = 0  
and dbo.Accountnumbersorders.valuezone = 'none'  
and storeinformation.storeroutename = routeselecttable.istoreroutenumber 
and storeinformation.storenumber = invoice.store_number 
and InvoicesCharges.invoice_number = invoice.invoice_number
and convert(varchar(6),Invoice.bill_to,12) = @weekending

即使我添加了:
and InvoicesCharges.orderaccnumber <> Accountnumbersorders.accountnumber

在更新语句的末尾将写入数量减少到零后,所需时间相同。
我这里有什么做错了吗?为什么会有如此巨大的差异?

额外的AND子句仍然是一个好主意,为什么要更新50,000行数据,当你只需要更新2行呢? - HLGEM
4个回答

24
  • 事务日志文件写入
  • 索引更新
  • 外键查找
  • 外键级联
  • 索引视图
  • 计算列
  • 检查约束
  • 锁定
  • 闩锁
  • 锁升级
  • 快照隔离
  • 数据库镜像
  • 文件增长
  • 其他进程读/写
  • 页面分裂/不适合的聚集索引
  • 向前指针/行溢出事件
  • 较差的索引
  • 统计信息过时
  • 较差的磁盘布局(例如为所有内容使用一个大型RAID)
  • 具有表访问的UDF的检查约束
  • ...

虽然,常见的问题是触发器...

另外,您的条件extra没有意义:SQL Server如何知道忽略它?在生成大部分负担的更新时甚至触发器仍将触发。例如,在搜索其他条件的行时必须保持锁定。

已于2011年9月和2012年2月进行了编辑以提供更多选项。


2
是的,触发器是原因。我对此很陌生,这个“代码”不是我的。感谢您提醒我。我添加了额外的条件,因为我认为写入磁盘可能需要太长时间,所以没有必要写入磁盘。再次感谢。 - Nodja
特别是那些被“设计”为通过所有行进行游标操作而不是以集合方式运行的触发器! - HLGEM

6

此更新需锁定并修改表中的数据,并记录更改到事务日志中。查询不需要执行这些操作。


吹毛求疵:你可以在SELECT语句中使用DML,只是不会被写回...除非它是INSERT INTO ... SELECT... - OMG Ponies
1
并且还要修改表上的任何索引。索引越多,写入时间就越长。 - womp
那么为什么即使加了额外的条件,执行时间还是很长呢?表格应该没有任何变化,但执行时间仍然很长。 - Nodja

1

因为阅读不会影响索引、触发器等等,所以呢?


1
在慢服务器或大型数据库中,我通常使用UPDATE DELAYED,它会等待“突破口”来更新数据库本身。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接