我的问题同时又简单而复杂:
我正在使用NHibernate 3.3和带有ODP驱动程序的Oracle 11g。
这段代码就像一个魅力:
var query = Session.CreateSQLQuery("SELECT * FROM wip_event_log WHERE track_id='" + trackId + "'");
query.AddEntity("l", typeof(MotIdenWipEventLog));
var results = query.List<MotIdenWipEventLog>();
几毫秒我得到了结果集。 ( 11.000.000 记录表中只有 5 记录)
另一方面,这段代码:
var results = Session.Query<MotIdenWipEventLog>().Where(m => m.TRACK_ID == trackId).ToList();
需要 4秒才能获得5条记录!
我读到了Oracle数据库中AnsiString
列的问题(http://bit.ly/1bbSlB7)并添加了一个自定义约定,用于在我的流畅配置上使用字符串:
Fluently
.Configure(new Configuration().Configure())
.Database(OracleClientConfiguration
.Oracle10
.ConnectionString(c => c.Is("User ID=XXXX;Password=XXXX;Data Source=(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 1.1.1.1)(PORT = 1521)))(CONNECT_DATA = (SID = iden01)))"))
)
.Mappings(
cfg => cfg.FluentMappings.LocalAddFromAssemblyOf<MotIdenPackSalesModelsHeaderMap>().Conventions.Add<OracleStringPropertyConvention>()
).BuildConfiguration();
,自定义约定MotIdenPackSalesModelsHeaderMap
为:
public class OracleStringPropertyConvention : IPropertyConvention
{
public void Apply(IPropertyInstance instance)
{
if (instance.Property.PropertyType == typeof(string)) instance.CustomType("AnsiString");
}
}
实体MotIdenWipEventLog
定义如下:
[Serializable]
public class MotIdenWipEventLog
{
public virtual String TRACK_ID { get; set; } // VARCHAR2(16 BYTE) No
public virtual String ASSY_PART_NUM { get; set; } // VARCHAR2(20 BYTE) Yes
public virtual String ASSY_VER_CODE { get; set; } // VARCHAR2(4 BYTE) Yes
public virtual int PROC_ID { get; set; } // NUMBER(9,0) Yes
public virtual String WIP_EVENT_CODE { get; set; } // VARCHAR2(4 BYTE) Yes
public virtual DateTime EVENT_DATETIME { get; set; } // DATE No
public virtual int EVENT_CLKSEQ { get; set; } // NUMBER(12,0) Yes
public virtual String AREA_ID { get; set; } // VARCHAR2(8 BYTE) Yes
public virtual String PERSONNEL_ID { get; set; } // VARCHAR2(11 BYTE) Yes
public virtual String STN_ID { get; set; } // VARCHAR2(20 BYTE) Yes
public virtual int WIP_COUNT { get; set; } // NUMBER(3,0) Yes
public virtual String STN_GROUP { get; set; } // VARCHAR2(8 BYTE) Yes
}
映射到班级MotIdenWipEventLogMap
:
public class MotIdenWipEventLogMap : ClassMap<MotIdenWipEventLog>
{
public MotIdenWipEventLogMap()
{
Table("WIP_EVENT_LOG");
Id(m => m.TRACK_ID, "TRACK_ID").GeneratedBy.Assigned();
#region Fields
Map(m => m.TRACK_ID).Not.Nullable()
.Length(16).Index("WIP_EVENT_LOG_IDX1"); // VARCHAR2(16 BYTE) No
Map(m=>m.ASSY_PART_NUM).Nullable().Length(20); // VARCHAR2(20 BYTE) Yes
Map(m=>m.ASSY_VER_CODE).Nullable().Length(4); // VARCHAR2(4 BYTE) Yes
Map(m=>m.PROC_ID).Nullable(); // NUMBER(9,0) Yes
Map(m=>m.WIP_EVENT_CODE).Nullable().Length(4); // VARCHAR2(4 BYTE) Yes
Map(m=>m.EVENT_DATETIME).Not.Nullable(); // DATE No
Map(m=>m.EVENT_CLKSEQ).Nullable(); // NUMBER(12,0) Yes
Map(m=>m.AREA_ID).Nullable().Length(8); // VARCHAR2(8 BYTE) Yes
Map(m=>m.PERSONNEL_ID).Nullable().Length(11); // VARCHAR2(11 BYTE) Yes
Map(m=>m.STN_ID).Nullable().Length(20); // VARCHAR2(20 BYTE) Yes
Map(m=>m.WIP_COUNT).Nullable(); // NUMBER(3,0) Yes
Map(m=>m.STN_GROUP).Nullable().Length(8); // VARCHAR2(8 BYTE) Yes
#endregion
}
}
在Log4Net
的调试级别中查看NHibernate的日志文件:
(...)
2013-11-06 14:24:22,375 DEBUG - Opened IDataReader, open IDataReaders: 1
2013-11-06 14:24:22,376 DEBUG - processing result set
2013-11-06 14:24:26,956 DEBUG - result set row: 0
2013-11-06 14:24:26,959 DEBUG - returning 'F7012B200ZMH' as column: TRACK1_6_
(...)
并在NHibernate类Loader.cs
的源代码中看到:
(...)
try
{
HandleEmptyCollections(queryParameters.CollectionKeys, rs, session);
EntityKey[] keys = new EntityKey[entitySpan]; // we can reuse it each time
if (Log.IsDebugEnabled)
{
Log.Debug("processing result set");
}
int count;
for (count = 0; count < maxRows && rs.Read(); count++)
{
if (Log.IsDebugEnabled)
{
Log.Debug("result set row: " + count);
}
object result = GetRowFromResultSet(rs, session, queryParameters, lockModeArray, optionalObjectKey, hydratedObjects, keys, returnProxies);
results.Add(result);
(...)
我无法找到问题所在......
我做错了什么?
有什么想法吗?
答案 0 :(得分:1)
而不是解决方案,但您可以创建基于函数的索引来匹配应用程序请求的类型。
,例如,
create index patch_index on your_table(cast(your_column as nvarchar2(16)));
使用EXPLAIN PLAN在Oracle 11g上进行说明。
使用
create table t(x varchar2(10));
create index idx on t(x);
insert into t values ('a');
查询
select * from t where x = 'a';
为您提供以下计划
| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 3 (0) | 00:00:01 |
|* 1 | TABLE ACCESS FULL | T | 1 | 7 | 3 (0) | 00:00:01 |
--------------------------------------------------------------------------
添加以下索引后
create index t2 on t(cast(x as nvarchar2(10)))
现在,相同的查询为您提供了以下计划
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 19 | 2 (0) | 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 19 | 2 (0) | 00:00:01 |
|* 2 | INDEX RANGE SCAN | T2 | 1 | | 1 (0) | 00:00:01 |
------------------------------------------------------------------------------------
如果无法在应用程序端修复问题,则可以应用此技术。