3

所以我对为什么这么慢已经没有想法了。也许你可以帮忙。因此,我正在尝试使用 nHibernate 通过代码映射从 oracle db 中进行简单的记录。我正在使用来自 nuget 的 nHibernate 版本 3.3.1.4。

这是映射代码:

public class Person
{
    public virtual PersonKey Key { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
}

public class PersonKey
{
    public virtual string PersonId { get; set; }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;
        var t = obj as PersonKey;
        if (t == null)
            return false;
        if (PersonId == t.PersonId)
            return true;
        return false;
    }
    public override int GetHashCode()
    {
        return (PersonId).GetHashCode();
    }
}

public class PersonMap : ClassMapping<Person>
{
    public PersonMap()
    {
        Schema("MyDB");
        Table("Person");
        ComponentAsId(id => id.Key, idMapper => idMapper.Property(p => p.PersonId));
        Property(i => i.FirstName);
        Property(i => i.LastName);
    }
}

这是创建会话工厂和检索数据的代码。

var mapper = new ModelMapper();
        var cfg = new Configuration();

        mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes());

        cfg.DataBaseIntegration(c =>
        {
            c.ConnectionString = @"User Id=user;Password=password;Data Source=MyDB;";
            c.Driver<OracleClientDriver>();
            c.Dialect<Oracle10gDialect>();

            c.LogSqlInConsole = true;
            c.LogFormattedSql = true;
            c.AutoCommentSql = true;
        });

        cfg.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities());
        var sessionFactory = cfg.BuildSessionFactory();

        stopwatch.Stop();
        Console.WriteLine("Building session factory: {0}", stopwatch.ElapsedMilliseconds);
        stopwatch.Restart();

        Person entity = null;

        using (var session = sessionFactory.OpenSession())
        using(var tx = session.BeginTransaction())
        {
            entity = (Person) session.Get("Person", new PersonKey(){PersonId = "1"});
            tx.Commit();
        }

生成的查询如下:

SELECT person0_.PersonId as PersonId0_0_, 
person0_.FirstName as FirstName0_0_, person0_.LastName as LastName0_0_,  
FROM MyDB.Person person0_
WHERE person0_.PersonId=:p0;
:p0 = '1' 

平均大约需要 80-100 秒才能访问检索到的对象。这也包括创建会话。

所以我寻找了一些明显的东西:

  • personId 列被索引(它是表的主键)。
  • 数据库在服务器上,所以要检查它不是网络占用时间,我使用 AD0.Net (Oracleconnection + Oraclecommand) 运行上述生成的查询。这大约需要 180 毫秒,包括创建连接并将记录映射到实体类。
  • 通过 PL/SQL 开发人员运行查询(大约需要 32 毫秒)。
  • 检查生成查询的查询计划(确认使用索引唯一扫描而不是全表扫描)。
  • 我已经在我的本地上针对类似大小的 sql 2012 db 运行了上述代码,并且通过 NHibernate 代码大约 180 毫秒。
  • 运行 nhprof(评估)并得到以下结果:

NHibernate 分析器的结果

似乎查询已运行并且结果从数据库返回的速度非常快(根据 nhprof 结果),但可能是将查询的值水合到占用时间的实体中。我不知道可能会浪费时间!

我的下一步是将 nHibernate 源附加到解决方案并逐步完成它,但是工作中的下载访问是有限的(甚至是 github!)。到那时有什么想法吗?

干杯。

更新:所以我在我的项目中获得了 nHibernate 源代码并逐步完成了它。一切都在顺利进行,直到程序到达这段代码:

for (count = 0; count < maxRows && rs.Read(); count++)              

执行会rs.Read()消耗时间,其中 rs 是 oracle 数据读取器。这段代码在DoQueryLoader.cs 文件的函数中。

奇怪的是,如果传入的查询是一个非参数化的动态查询(例如select ... from person where personid = '1'),执行速度很快(~ 1 毫秒),但如果它是参数化的(例如select ... from person where personid = :p1),那么它的速度就慢得离谱。由于我想利用 nHibernate 的强大功能,我需要使用生成的参数化查询。我仍在试图弄清楚为什么甲骨文阅读器

4

2 回答 2

1

找到Deep Shah在此处发布的问题和解决方案。

从本质上讲,NHibernate 中的参数化查询以及 Microsoft 的 Oracle 驱动程序是造成瓶颈的原因。

他接着分享了两个解决方案:

  1. 用 oracle 开发的 Oracle Data Client Driver 替换当前的 Microsoft oracle 驱动程序。使用新驱动程序运行相同的查询消除了性能瓶颈。为此,您需要在要触发查询的计算机上安装 Oracle 数据访问组件 (ODAC)。

  2. 当通过 NHibernate 在查询上设置参数时,在查询 VARCHAR 列时使用“query.SetAnsiString”而不是“query.SetParameter”。

我已经验证了这两种解决方案,它们都有效。解决方案一是我使用的解决方案,因为我使用的是按代码映射,并且我将查询生成留给 nHibernate。

于 2012-07-31T01:01:08.897 回答
0

我相信您还可以在映射中将数据类型设置为 ansi 字符串,如本文所述: NHibernate 3 用 loquacious syntax 指定 sql 数据类型

于 2012-08-31T18:04:38.417 回答