LINQ to XML vs XPath的簡單效能測試

如果你使用的平台是.NET 3.5,在操作XML文件時會有三種選擇: LINQ to XML, LINQ to XML with XPath以及傳統的XmlDocument。既然有三種選擇,排除個人主觀偏好,想知道哪一種做法的效能最好呢?

之前有個迷思,一直覺得LINQ表達方式友善,理論上會付出效能上的代價(正所謂有一好沒兩好)。所以有時針對複雜的元素查詢,我會using System.Xml.XPath,然後改用XPathSelectElements()查詢,直到無意間發現了一篇談LINQ to XML與XPath Benchmark的文章,才發現我錯了。該文作者試了一個120,000筆資料, 54MB大小的XML檔案,LINQ to XML用LINQ語法查詢,竟比叫用XPathSelectElements()快了五倍!!

我自己也做了一個測試,產生一個36M大小20,000 * 100個Node的XML文件,分別用LINQ to XML, XPathSelectElements及XmlDocument.SelectNodes去查詢同樣條件,統計Node數。依我的測試結果,也驗證了LINQ to XML確實比XPathSelectElements來得快,至於XmlDocument,我們就忘了它吧...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;
using System.Diagnostics;
using System.Xml.XPath;
using System.Xml;
 
namespace TestXmlPerformance
{
    class Program
    {
        static void GenSampleXml()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<root>");
            Random rnd = new Random();
            for (int i = 0; i < 20000; i++)
            {
                sb.AppendFormat("<pack id=\"{0}\">", i);
                for (int j = 0; j < 100; j++)
                    sb.AppendFormat("<item model=\"{0}\" />",
                        rnd.Next(20));
                sb.Append("</pack>");
            }
            sb.Append("</root>");
            File.WriteAllText(".\\Sample.xml", sb.ToString());
        }
 
        static void Main(string[] args)
        {
            //GenSampleXml();
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                XDocument xd = XDocument.Load(".\\Sample.xml");
                var q = from o in xd.Descendants("item")
                        where o.Attribute("model").Value == "7"
                        select o;
                Console.WriteLine(q.Count());
                sw.Stop();
                Console.WriteLine("Test 1: {0}ms", 
                    sw.ElapsedMilliseconds);
            }
 
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                XDocument xd = XDocument.Load(".\\Sample.xml");
                Console.WriteLine(
                    xd.XPathSelectElements("root/pack/item[@model='7']")
                    .Count()
                );
                sw.Stop();
                Console.WriteLine("Test 2: {0}ms", 
                    sw.ElapsedMilliseconds);
            }
 
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                XmlDocument xd = new XmlDocument();
                xd.Load(".\\Sample.xml");
                Console.WriteLine(
                    xd.DocumentElement
                    .SelectNodes("pack/item[@model='7']").Count
                );
                sw.Stop();
                Console.WriteLine("Test 3: {0}ms", 
                    sw.ElapsedMilliseconds);
            }
 
            Console.Read();
        }
    }
}

【 測試數據 】

100507
Test 1: 3268ms
100507
Test 2: 3960ms
100507
Test 3: 9246ms

歡迎推文分享:
Published 15 December 2009 09:08 PM 由 Jeffrey
Filed under: ,


意見

# ina2588 said on 15 December, 2009 07:04 PM

感謝指導.可惜試了一下還是躲不開網路遠端xml讀取的gui延遲.backgroundWorker還是要用.

# Ernest said on 29 December, 2009 07:06 PM

黑大, 請教一下

如果想用ASP.NET + LINQ 運行一個SQL SP,

而該SP 一行就是10-15分鐘, 有可能不TIME OUT 嗎?

我可能怎樣做?

# Jeffrey said on 30 December, 2009 03:44 AM

to Ernest, DataContext有個CommandTimeout屬性(單位: 秒),把值加大應該就可以解決。msdn.microsoft.com/.../system.data.linq.datacontext.commandtimeout.aspx

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 

請輸入以上的數字:

搜尋

Go

<December 2009>
SunMonTueWedThuFriSat
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication