实现批量操作是常见的任务,比如批量删除一批数据,如果在应用程序端循环调用DAL.Entity.Delete则效率非常低,因为数据库往返次数取决与数据量大小。而编写一个存储过程效率更高。
做这个批量操作的存储过程使用什么作为参数是一个问题。如果使用VARCHAR(MAX),内容是,例如要删除记录的id并以逗号隔开,例如“1,2,3,4,…..”,这样的话就会存在最大长度受限制的问题。
这儿介绍一种使用XML的VARBINARY类型作为参数的高效方法。
首先是xml的格式:
<Employees>
<Employee EmployeeID="1" EmployeeName="Bush" EmployeeAddress="WashtonD.C." />
<Employee EmployeeID="2" EmployeeName="Jamson" EmployeeAddress="Russia" />
<Employee EmployeeID="3" EmployeeName="Brown" EmployeeAddress="London" />
</Employees>
把这个XML转换为Binary类型:
using System.IO;using System.Xml;private byte[] GetEmployeesListXmlStream(IList EmployeesList)
{byte[] result = null;
using (MemoryStream stream = new MemoryStream())
{ XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.OmitXmlDeclaration = true; settings.IndentChars = "\t";XmlWriter writer = XmlWriter.Create(stream, settings);
writer.WriteStartDocument();
writer.WriteStartElement("Employees");foreach (Employee var in EmployeesList)
{ writer.WriteStartElement("Employee"); writer.WriteAttributeString("EmployeeID", var.EmployeeID.ToString()); writer.WriteAttributeString("EmployeeName", var.EmployeeName); writer.WriteAttributeString("EmployeeAddress", var.EmployeeAddress);writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
writer.Close();
result = stream.ToArray();
}
return result;}
大家也知道,DataSet中的数据可以直接序列化成xml,通过dataSet.GetXml(),然后转化为binary即可。
XML的VARBINARY类型作为参数,批量删除的存储过程:
1: CREATE PROCEDURE [dbo].[_Employee_BulkDelete]
2: ( 3: @EmployeeList VARBINARY(MAX)
4: ) 5: AS
6: 7: --XML ----
8: DECLARE @EmployeeListXML XML;
9: 10: -- TABLE to store XML records ----
11: DECLARE @TempEmployees TABLE
12: (13: EmployeeID BIGINT NULL,
14: EmployeeName NVARCHAR(512) NULL DEFAULT(''),
15: EmployeeAddress NVARCHAR(512) NULL DEFAULT('')
16: ) 17: 18: -- Get XML from binary stream -----
19: SET @EmployeeListXML = CONVERT(XML, @EmployeeList);
20: 21: -- Fill to table-------
22: INSERT INTO @TempEmployees
23: ( 24: EmployeeID, 25: EmployeeName, 26: EmployeeAddress 27: ) 28: SELECT
29: nref.value('@id', 'BIGINT'),
30: nref.value('@name', 'NVARCHAR(512)'),
31: nref.value('@address', 'NVARCHAR(512)')
32: FROM
33: @EmployeeListXML.nodes('/Employees/Employee') R(nref)
34: 35: --- Delete ----Maybe more complicated routine here !----------
36: 37: DELETE [dbo].[TempEmployees]
38: FROM [dbo].[TempEmployees] AS T1
39: INNER JOIN @TempEmployees AS T2
40: ON (T1.EmployeeID = T2.EmployeeID)
41: WHERE (EmployeeSalary > 500000)
最后,如果想进一步优化该存储过程的效率,可以优化索引,使用临时表等。
------- 批量插入可以用SqlBulkCopy 参考:http://www.cnblogs.com/xiaoweinet/archive/2010/03/02/1676478.html