Linq to Sql 与NHibernate数据库操作性能比较研究 测试程序源码
时间:2010-10-12 来源:Lester Duo
因本人编程的能力有限,程序肯定仍有很多可以值得修订的地方,请大家多多指教。让它们的对比更公平。
我也是初涉入orm这个领域,也参考了不少cnblog上的大侠们的文章,此次对比的两段小程序都没有经过任何优化,都是最简单的应用代码。
因为考虑到优化是一个大课题,针对不同的数据量级和应用环境,每一种ORM产品都有自己更独到的优化方式。Nhibernate有缓存延迟加载,
linq to sql 也能做预编译,这样在比较起来难免会因为我对某一种产品的优化方案有欠缺导致测试结果有失公平。
所以我对于linq to sql与Nhibernate采用了同样的简单的测试逻辑、测试用的代码段也基本相同,用这样的方式来对它们在公平的应用环境
下做一个性能的比较。这也同时排除了象我们这样的疑似小白们由于编程技巧问题引起的测试不公。
大家看看我这样的处理是不是有道理。
我帖出测试程序供大家参考。文章还在修改。希望大家也帮我多出些主意。谢谢。
首先在SQL SERVER2005中建立NTest数据库,然后用以下语句建立测试用数据表:
CREATE TABLE [dbo].[Person](
[ID] [varchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
[Name] [varchar](16) COLLATE Chinese_PRC_CI_AS NOT NULL,
[Sex] [varchar](2) COLLATE Chinese_PRC_CI_AS NOT NULL,
CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED
([ID] ASC)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
为测试程序配置NHibernate
(1)在项目中引入NHibernate.dll
(2)建立NHibernate配置文档hibernate.cgf.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<!—设定NHibernate的方言-->
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<!—设定NHibernate的数据库驱动-->
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<!—设定NHibernate的数据库连接字符串-->
<property name="connection.connection_string">Server=127.0.0.1;initial catalog=NTest;Integrated Security=SSPI</property>
</session-factory>
</hibernate-configuration>
(3) 建立针对数据表Person的实体类(Person.cs)的映射文件(Person.hbm.xml)
Person.cs |
Person.hbm.xml |
using System; using System.Collections.Generic; using System.Text; namespace Model { public class Person { public string ID { get; set; } public string Name { get; set; } public string Sex { get; set; } } } |
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Model" assembly="NhibernateTest"> <class name="Person" table="Person" lazy="false"> <id name="ID"> <column name="ID" sql-type="varchar(50)" not-null="true"/> <!--手工指定主键内容--> <generator class="Assigned" /> </id> <property name="Name"/> <property name="Sex"/> </class> </hibernate-mapping> |
为测试程序配置Linq to SQL
Linq to SQL的配置可交由VS.net 2008自动完成,具体的步骤如下
(1) 通过菜单“工具”、“连接到数据库”,连接至数据库
(2) 通过“解决方案资源管理器”、“添加”、“添加新项”、“Linq to SQL类”增加Person.dbml如2.2 所示
(3) 以鼠标拖动方式从“服务器资源管理器”将person表拖放入第(2)步建立的Person.dbml窗体内,数据表映射和类将自动建立完成,如图2.3所示
2.4编写Nhibernate和Linq to Sql数据库操作测试程序
根据图2.1所示的数据库操作逻辑,我们同时来编写NHibernate和Linq to Sql测试程序,并对比其各模块实现的代码。两个测试程序均按如下方式声明测试类
[TestFixture]
public class TestApp
{
[TestFixtureSetUp]
初始化函数
[Test]
测试函数
[TestFixtureTearDown]
卸载函数
………
}
为了同时对比两种框架在操作数据库时的易用性,我同时列出两个测试程序各测试模块,大家可对比其代码的简洁程度。
测试初始化模块 |
|
NHibernate |
Linq to SQL |
public static ISession session; public static ITransaction tc; [TestFixtureSetUp] public void ini(){ session = new NHibernate.Cfg.Configuration() .Configure("hibernate.cfg.xml") .AddAssembly("Model") .BuildSessionFactory() .OpenSession(); tc = session.BeginTransaction(); tc.Begin(); } |
public static DataContext dc; [TestFixtureSetUp] public void Ini(){ dc = new DataContext("Data Source=127.0.0.1;Initial Catalog=NTest;Integrated Security=True"); } |
写入数据测试模块 |
|
NHibernate |
Linq to SQL |
[Test] public void testInsert(){ for (int i = 0; i < 10000; i++){ Person ps = new Person(); ps.ID = Guid.NewGuid().ToString(); ps.Name = Utility.MakeRadomStr(16, 0); ps.Sex = Utility.MakeRadomStr(2, 0); session.Save(ps); ps = null;} }//Nhibernate下主键采用uuid.hex由128位唯一值生成的32位编码 |
[Test] public void testInsert(){ Table<Person> Persons = dc.GetTable<Person>(); for (int i = 0; i < 10000; i++){ Person ps = new Person(); ps.ID = Guid.NewGuid().ToString(); ps.Name = Utility.MakeRadomStr(16, 0); ps.Sex = Utility.MakeRadomStr(2, 0); Persons.InsertOnSubmit(ps); ps = null; } }//Linq to SQL下主键采用Guid算法 |
查询数据测试模块 |
|
NHibernate |
Linq to SQL |
[Test] public void testSelect(){ ICriteria cr = session.CreateCriteria(typeof(Person)) .Add(Restrictions.Like("FirstName","%d%")); IList<Person> p = cr.List<Person>(); } |
[Test] public void testSelect(){ Table<Person> persons = dc.GetTable<Person>(); var p = from c in persons wherec.Name.IndexOf("d") > 0 select c; List<Person> pl = p.ToList<Person>(); } |
更新数据测试模块 |
|
NHibernate |
Linq to SQL |
[Test] public void testUpdate(){ IQuery q = session.CreateQuery("from Person as p where p.FirstName like'%d%'"); IList<Person> p = q.List<Person>(); foreach (Person ap in p){ ap.Name = Utility.MakeRadomStr(16, 0); session.Save(ap); } } |
[Test] public void testUpdate(){ Table<Person> persons = dc.GetTable<Person>(); var p = from c in persons wherec.Name.IndexOf("d") > 0 select c; foreach (Person c in p){ c.Name = Utility.MakeRadomStr(16, 0); } } |
删除数据测试模块 |
|
NHibernate |
Linq to SQL |
[Test] public voidtestDelete() { session.Delete("from Person"); } |
[Test] public voidtestDelete() { Table<Person> Persons = dc.GetTable<Person>(); Persons.DeleteAllOnSubmit(Persons); } |
删除数据测试模块 |
|
NHibernate |
Linq to SQL |
[Test] public voidtestDelete() { session.Delete("from Person"); } |
[Test] public voidtestDelete() { Table<Person> Persons = dc.GetTable<Person>(); Persons.DeleteAllOnSubmit(Persons); } |
测试卸载模块 |
|
NHibernate |
Linq to SQL |
[TestFixtureTearDown] public void unload() { tc.Commit(); session.Close(); } |
[TestFixtureTearDown] public void unload() { dc.SubmitChanges(); dc = null; } |
按照千、万、10万、100万量级递增的数据规模,修订前面编写的测试程序相应模后,以Nunit运行指定的测试,在测试完成后结果的窗口中即可得到单元测试的结论和运行时间。
最终测试的结论数据可以参考 http://www.cnblogs.com/pcode/archive/2008/11/13/1332402.html