NHibernate 执行简单查询需要更长的时间

Posted

技术标签:

【中文标题】NHibernate 执行简单查询需要更长的时间【英文标题】:NHibernate taking longer time executing simple query 【发布时间】:2012-08-17 01:23:50 【问题描述】:

我在 NHibernate 遇到了一个非常奇怪的问题,现在它变得头疼了。

NHibernate 执行这样一个简单查询所花费的时间(2-3 分钟)比预期的时间(几毫秒)要长。数据库是 Oracle,我正在使用 ODP 驱动程序。我已经检查了 NHibernate 和 Spring 的所有必要配置,这对我来说看起来不错。当我在 sqldeveloper 中执行相同的查询时,它会以毫秒为单位给出结果。

仅供参考 - 当我执行另一个查询时,该查询具有三个具有相同 NHibernate 配置的复杂模型的内部联接,我得到了预期的结果。

在调试日志中,我可以看到以下几行浪费时间:

2012-08-17 09:53:20,754 [TestRunnerThread] DEBUG - NHibernate.Connection.DriverConnectionProvider - Obtaining IDbConnection from Driver
2012-08-17 09:55:09,369 [TestRunnerThread] DEBUG - NHibernate.AdoNet.AbstractBatcher - ExecuteReader took 108720 ms

NHibernate 属性设置:

<nhibernatePropertiesSettings>
<setting name="nhibernate.connection.provider" serializeAs="String">
 <value>NHibernate.Connection.DriverConnectionProvider</value>
</setting>
<setting name="nhibernate.connection.driver.class" serializeAs="String">
 <value>NHibernate.Driver.OracleDataClientDriver</value>
</setting>
<setting name="nhibernate.dialect" serializeAs="String">
 <value>NHibernate.Dialect.Oracle10gDialect</value>
</setting>
<setting name="nhibernate.show.sql" serializeAs="String">
 <value>true</value>
</setting>
<setting name="nhibernate.query.substitutions" serializeAs="String">
 <value>true 1, false 0, yes 'Y', no 'N'</value>
</setting>
<setting name="nhibernate.use.proxy.validator" serializeAs="String">
 <value>false</value>
</setting>
<setting name="nhibernate.template.flush.mode" serializeAs="String">
 <value>Never</value>
</setting>
</nhibernatePropertiesSettings>

弹簧属性设置:

<springPropertiesSettings>
 <setting name="spring.db.provider" serializeAs="String">
  <value>OracleODP-11-2.0</value>
 </setting>
</springPropertiesSettings>

映射:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="XYZ.PaymentInvestigation.Service.Model.PaymentMessageHistory, PaymentInvestigation.Service.Model" table="MESSAGE_HIST_T" lazy="false">    
    <composite-id name="PaymentMessageHistoryId" class="XYZ.PaymentInvestigation.Service.Model.PaymentMessageHistoryId, PaymentInvestigation.Service.Model" unsaved-value="undefined">
      <key-property name="TransactionDate" column="TRN_DATE" />
      <key-property name="TransactionReferenceNumber" column="TRN_NUMBER" />
      <key-property name="TransactionTimeStamp" column="TRN_TIMESTAMP" />
      <key-property name="HistoryNumber" type="AnsiString" column="HIST_NO" />
      <key-property name="SubHistoryNumber" type="AnsiString" column="SUB_HIST_NO" />
    </composite-id>
    <property name="EntryType" column="ENTRY_TYPE" update="false" insert="false" />
    <property name="Location" column="LOC" update="false" insert="false" />
    <property name="QueLineId" column="QUE_LINE_ID" update="false" insert="false" />
    <property name="DateTime" column="DATE_TIME" update="false" insert="false" />
    <property name="SequenceNo" column="SEQUENCE_NO" update="false" insert="false" />
    <property name="OperatorInitials" column="OPR_INITIALS" update="false" insert="false" />
    <property name="Amount" column="AMOUNT" update="false" insert="false" />
    <property name="MsgInfo" column="MSG_INFO" update="false" insert="false" />
    <property name="RecordExpired" column="RECORD_EXPIRED" update="false" insert="false" />
    <property name="RecordUpdated" column="RECORD_UPDATED" update="false" insert="false" />
    <property name="Details" column="DETAILS" update="false" insert="false" /> 
 </class>

查询:

IList<PaymentMessageHistory> paymentMessageHistories =
    HibernateTemplate.ExecuteFind(session => session
        .QueryOver<PaymentMessageHistory>()
        .Where(x =>
            x.PaymentMessageHistoryId.TransactionDate == paymentMessageId.TransactionDate &&
            x.PaymentMessageHistoryId.TransactionReferenceNumber == paymentMessageId.TransactionReferenceNumber)
        .List());

PaymentMessageHistoryId 模型:

public class PaymentMessageHistoryId : IEquatable<PaymentMessageHistoryId>

    public virtual DateTime TransactionDate  get; set; 
    public virtual int TransactionReferenceNumber  get; set; 
    public virtual double TransactionTimeStamp  get; set; 
    public virtual string HistoryNumber  get; set; 
    public virtual string SubHistoryNumber  get; set; 

    public bool Equals(PaymentMessageHistoryId other)
    
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return other.TransactionDate.Equals(TransactionDate) && other.TransactionReferenceNumber == TransactionReferenceNumber && other.TransactionTimeStamp.Equals(TransactionTimeStamp) && Equals(other.HistoryNumber, HistoryNumber) && Equals(other.SubHistoryNumber, SubHistoryNumber);
    

    public override bool Equals(object obj)
    
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != typeof (PaymentMessageHistoryId)) return false;
        return Equals((PaymentMessageHistoryId) obj);
    

    public override int GetHashCode()
    
        unchecked
        
            int result = TransactionDate.GetHashCode();
            result = (result*397) ^ TransactionReferenceNumber;
            result = (result*397) ^ TransactionTimeStamp.GetHashCode();
            result = (result*397) ^ (HistoryNumber != null ? HistoryNumber.GetHashCode() : 0);
            result = (result*397) ^ (SubHistoryNumber != null ? SubHistoryNumber.GetHashCode() : 0);
            return result;
        
    

    public static bool operator ==(PaymentMessageHistoryId left, PaymentMessageHistoryId right)
    
        return Equals(left, right);
    

    public static bool operator !=(PaymentMessageHistoryId left, PaymentMessageHistoryId right)
    
        return !Equals(left, right);
    

    public override string ToString()
    
        return string.Format("TransactionDate: 0, TransactionReferenceNumber: 1, TransactionTimeStamp: 2, HistoryNumber: 3, SubHistoryNumber: 4", TransactionDate, TransactionReferenceNumber, TransactionTimeStamp, HistoryNumber, SubHistoryNumber);
    

PaymentMessageHistory 模型:

public class PaymentMessageHistory : IEquatable<PaymentMessageHistory>

    public virtual PaymentMessageHistoryId PaymentMessageHistoryId  get; set; 
    public virtual string EntryType  get; set; 
    public virtual string Location  get; set; 
    public virtual string QueLineId  get; set; 
    public virtual string DateTime  get; set; 
    public virtual string SequenceNo  get; set; 
    public virtual string OperatorInitials  get; set; 
    public virtual decimal Amount  get; set; 
    public virtual string MsgInfo  get; set; 
    public virtual double RecordExpired  get; set; 
    public virtual string RecordUpdated  get; set; 
    public virtual string Details  get; set; 

    public bool Equals(PaymentMessageHistory other)
    
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Equals(other.PaymentMessageHistoryId, PaymentMessageHistoryId) && Equals(other.EntryType, EntryType) && Equals(other.Location, Location) && Equals(other.QueLineId, QueLineId) && Equals(other.DateTime, DateTime) && Equals(other.SequenceNo, SequenceNo) && Equals(other.OperatorInitials, OperatorInitials) && other.Amount == Amount && Equals(other.MsgInfo, MsgInfo) && other.RecordExpired.Equals(RecordExpired) && Equals(other.RecordUpdated, RecordUpdated) && Equals(other.Details, Details);
    

    public override bool Equals(object obj)
    
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != typeof (PaymentMessageHistory)) return false;
        return Equals((PaymentMessageHistory) obj);
    

    public override int GetHashCode()
    
        unchecked
        
            int result = (PaymentMessageHistoryId != null ? PaymentMessageHistoryId.GetHashCode() : 0);
            result = (result*397) ^ (EntryType != null ? EntryType.GetHashCode() : 0);
            result = (result*397) ^ (Location != null ? Location.GetHashCode() : 0);
            result = (result*397) ^ (QueLineId != null ? QueLineId.GetHashCode() : 0);
            result = (result*397) ^ (DateTime != null ? DateTime.GetHashCode() : 0);
            result = (result*397) ^ (SequenceNo != null ? SequenceNo.GetHashCode() : 0);
            result = (result*397) ^ (OperatorInitials != null ? OperatorInitials.GetHashCode() : 0);
            result = (result*397) ^ Amount.GetHashCode();
            result = (result*397) ^ (MsgInfo != null ? MsgInfo.GetHashCode() : 0);
            result = (result*397) ^ RecordExpired.GetHashCode();
            result = (result*397) ^ (RecordUpdated != null ? RecordUpdated.GetHashCode() : 0);
            result = (result*397) ^ (Details != null ? Details.GetHashCode() : 0);
            return result;
        
    

    public static bool operator ==(PaymentMessageHistory left, PaymentMessageHistory right)
    
        return Equals(left, right);
    

    public static bool operator !=(PaymentMessageHistory left, PaymentMessageHistory right)
    
        return !Equals(left, right);
    

    public override string ToString()
    
        return string.Format("PaymentMessageHistoryId: 0, EntryType: 1, Location: 2, QueLineId: 3, DateTime: 4, SequenceNo: 5, OperatorInitials: 6, Amount: 7, MsgInfo: 8, RecordExpired: 9, RecordUpdated: 10, Details: 11", PaymentMessageHistoryId, EntryType, Location, QueLineId, DateTime, SequenceNo, OperatorInitials, Amount, MsgInfo, RecordExpired, RecordUpdated, Details);
    

我经历了这个NHibernate taking a long time to run query,但对我不起作用。

请帮忙!

问候, 温和的

【问题讨论】:

我的最新发现:当我删除 x.PaymentMessageHistoryId.TransactionDate == paymentMessageId.TransactionDate 条件时,它工作正常。表示与数据类型有关。 【参考方案1】:
public class OracleDataClientDriver2 : OracleDataClientDriver

    protected override void InitializeParameter(IDbDataParameter dbParam, string name, SqlType sqlType)
    
        switch (sqlType.DbType)
        
            //Timestamp columns not indexed by Oracle 11g date columns. - Use Date 
            case DbType.DateTime:
                base.InitializeParameter(dbParam, name, SqlTypeFactory.Date);
                break;
            default:
                base.InitializeParameter(dbParam, name, sqlType);
                break;
        
    

并更改 connection.driver_class= nameSpace.OracleDataClientDriver2, AssemblyName 的值

【讨论】:

这里是解决方案***.com/questions/7684163/…【参考方案2】:

比继承 oracle 驱动程序类更简单的解决方案是在您的属性中添加类型属性,值将是“日期”。这是 NHibernate 类型。

<key-property name="TransactionDate" type="Date" column="TRN_DATE" />

【讨论】:

以上是关于NHibernate 执行简单查询需要更长的时间的主要内容,如果未能解决你的问题,请参考以下文章

SQL-query 在代码中比直接查询 db 花费更长的时间

Spring DAO - 使用 JdbcTemplate 的第一次查询需要更长的时间

带有 SQL 注入保护的简单查询比没有的要花费更长的时间

为啥通过 ASP.NET 方法运行查询比原生 SQL 需要更长的时间?

使用子查询的查询比使用固定数据而不是子查询的相同查询需要更长的时间

涉及不查询几何本身的具有几何的表的查询是不是比没有几何的表需要更长的查询时间?