为什么我的NHibernate查询这么慢?

时间:2013-06-12 11:50:54

标签: c# sql performance nhibernate fluent-nhibernate

我正在使用Fluent NHibernate v2.0.50727构建一个ASP Web表单应用程序到SQL服务器后端。

由于某些原因,查询具有小数据(~14行)的表需要几秒钟。

地图非常简单:Id(x => x.Id)Map(x => x.Name)。 CertificateGroup还有Map()的ColorRank

我已经隔离了用于测试的nhibernate代码:(这不是我的应用程序的代表,但是为了SO而被简化和隔离)

protected void Page_Load(object sender, EventArgs e)
{
    var config = Fluently.Configure()
                             .Database(MsSqlConfiguration.MsSql2008.ConnectionString("..."))
                             .Mappings(m => m.FluentMappings.AddFromAssemblyOf<PersonMap>())                                 .BuildConfiguration();
    var factory = config.BuildSessionFactory();

    using (var session = factory.OpenSession())
    {
        using (var transaction = session.BeginTransaction())
        {
            var departments = session.QueryOver<DepartmentModel>().List(); // these all take seconds to execute - this has 14 results
            var jobs = session.QueryOver<JobModel>().List(); // 113 results
            var certificates = session.QueryOver<CertificateModel>().List(); //this one about 4 seconds for 210 results
            var groups = session.QueryOver<CertificateGroupModel>().List();

            var association = new CertificateAssociationModel
                {
                    Department = departments.First(),
                    Job = jobs.First(),
                    Certificate = certificates.First(),
                    Group = groups.First()
                };
            session.SaveOrUpdate(association);
            transaction.Commit();
        }
    }
}

我将nhibernate交换为实体框架并运行上面的代码并且提取是即时的。

任何帮助表示感谢。

编辑:

以下是映射(如上所述): 部门,工作和证书:

public class DepartmentMap : ClassMap<DepartmentModel>
{
    public DepartmentMap()
    {
        Table("tblDepartment");
        Id(x => x.Id);
        Map(x => x.Name);
    }
}

CertificateGroupModel也有     Map(x => x.Rank);            Map(x => x.Color);

实体类都是一样的:

public class CertificateModel
{
    public virtual Int32 Id { get; protected set; }
    public virtual String Name { get; set; }
}

除了CertificateGroupModel,它也有:

public virtual String Color { get; set; }
public virtual Int32 Rank { get; set; }

以下是我的NHiberate个人资料结果:

 -- statement #1
begin transaction with isolation level: Unspecified

-- statement #2
SELECT this_.Id   as Id4_0_,
       this_.Name as Name4_0_
FROM   tblDepartment this_

-- statement #3
SELECT this_.Id   as Id5_0_,
       this_.Type as Type5_0_
FROM   tblJobTitles this_

-- statement #4
SELECT this_.Id   as Id2_0_,
       this_.Name as Name2_0_
FROM   tblCertificate this_

-- statement #5
SELECT this_.Id    as Id1_0_,
       this_.Name  as Name1_0_,
       this_.Rank  as Rank1_0_,
       this_.Color as Color1_0_
FROM   tbl_certificate_groups this_

-- statement #6
INSERT INTO lnk_certificate_associations
            (Certificate_id,
             Department_id,
             Job_id,
             Group_id)
VALUES      (1 /* @p0 */,
             1 /* @p1 */,
             1 /* @p2 */,
             1 /* @p3 */);



select SCOPE_IDENTITY()


-- statement #7
commit transaction

nhibprofile http://i.snag.gy/bTKHm.jpg

生成的IL代码:

                      var departments = session.QueryOver<DepartmentModel>().List();
IL_008F: ldloc.2      /* session */
IL_0090: callvirt     instance NHibernate.IQueryOver`2<!!0, !!0> NHibernate.ISession::QueryOver<Core.Domain.Model.DepartmentModel>()
IL_0095: callvirt     instance [mscorlib]System.Collections.Generic.IList`1<!0> NHibernate.IQueryOver`1<Core.Domain.Model.DepartmentModel>::List()
IL_009A: stloc.s      departments

2 个答案:

答案 0 :(得分:0)

猜测一下,因为你还没有在这里发布你的映射和表格......

您的数据库中是否有任何可以为空的列映射到不可为空的类型(例如,在模型中映射到int的nullable int)?

这会导致您看到的行为,因为当NHibernate加载您的实体时(让我们假设上面的DepartmentModel场景,属性Prop1是int),如果Prop1在数据库中为null,那么会话将会具有null的内部状态,但由于您无法将Prop1设置为null,因此将为其分配值0,并且当会话检查是否有任何更改时,它将看到Prop1已更改(从null更改为0),并且导致一大堆更新,这反过来会减慢很多事情。

如果是这种情况,解决方案是更新表定义或更新实体以获得正确(可为空)的类型。

有多种方法可以实现,我刚刚给出了一个简单的例子 - 如果你可以包含你的映射,表定义和实体类,它会有所帮助......

答案 1 :(得分:0)

至于插入问题,如果你正在使用Id的Identity生成器,那么nHibernate将首先要求数据库(INSERT...SELECT SCOPE_IDENTITY())为你的实体创建记录,然后用正确的Id和数据插入它({{1} })

请注意,其他实体的引用将在UPDATE中更新,因为您只看到'?'在插入