关键字: XML节点,字符串
背景: Server A中的系统在处理表单时会通过Server B中的WebService将资料塞入Server C中的DB,当资料量超过200~300以上时就会导致WebService响应不及时而中断A、B之间的网络(规则:A、B之间传输资料超过3分钟就会中断网络)。
排除了网络性能的影响,最终发现是由于这支WebService对传入的XML资料进行加工的效率太低造成的。
摘要: 取得XML节点值的效率改进以及拼接字符串的效率改进
内容:
分两部分对XML资料的加工进行改进:XML资料的取得(取XML节点值)和SQL语句的组装(字符串拼接)。
一个资料920笔的测试结果:
1 | 原程式所花的时间(跑了30分钟还没跑完) | 〉30分 |
2 | 对XML的操作改进 | 1.55分 |
3 | 对字符串拼接的改进 | 1.4375秒 |
² 对XML的操作主要有以下两点改进:
1. XML操作中,明确是单节点,使用遍历路径(Xml//Head//Form_no),不如(Xml/Head/Form_no)效率高
/ | 选取根节点 |
// | 选取文档中所有符合条件的节点,不管该节点位于何处 |
Xml/Head/Form_no | 选取Xml节点下的Head节点下的所有Form_no节点 |
Xml//Head//Form_no | 选取文档中所有处于Xml节点下的Head节点下的Form_no节点 |
这两者的不同之处在于“/”是从当前节点开始搜索,而“//”是从整篇文档进行搜索的。
这点对于XML非常庞大时就有影响了。
Origin: strFormNo = xmlHead.SelectSingleNode("Xml//Head//Form_no").InnerText.Trim(); |
Improved: strFormNo = xmlHead.SelectSingleNode("Xml/Head/Form_no").InnerText.Trim(); |
2. 当对XML的多个子节点进行循环时,每次都对整个XML文档进行全文搜索(Xml//Head//Form_no),这里并且采用的是Item(intCount)的随机访问方式进行循环访问,随着intCount的增大,访问时间越来越长,这一点是影响性能的主要原因。
改进后,先取出XML的节点列表,采用foreach的顺序访问方式取得节点值。
Origin: intToNote=xmlDetail.SelectNodes("Xml//Detail").Count; for(intCount=0;intCount<intToNote;intCount++) { strFormNo=xmlDetail.SelectNodes("Xml//Detail//Form_no").Item(intCount).InnerText.Trim(); … } |
Improved: XmlNodeList detailList = xmlDetail.SelectNodes("Xml/Detail"); foreach(XmlNode node in detailList) { strFormNo=node.SelectSingleNode("Form_no").InnerText.Trim(); … } |
² 对字符串拼接的改进:这个是个老生常谈的问题,之前也遇到过了,采用“StringBuilder”代替“+=”使大数据量String频繁拼接效率提高。
string对象是不可改变的类型,当我们对一个string对象修改后将会产生一个新的string对 象,因此在需要经常更改的字符对象时,建议使用StringBuilder类
总结:XML选取、字符串拼接的不良写法,常常是实际发生的性能问题的主要原因。对于小数据量能支持的某些写法在大数据量面前可能就不能很好的展现其功能了。
参考:
最常使用的路径表达式:
Expression | Description |
nodename | Selects all child nodes of the node |
/ | Selects from the root node |
// | Selects nodes in the document from the current node that match the selection no matter where they are |
. | Selects the current node |
.. | Selects the parent of the current node |
@ | Selects attributes |