1818IP-服务器技术教程,云服务器评测推荐,服务器系统排错处理,环境搭建,攻击防护等

当前位置:首页 - 数据库 - 正文

君子好学,自强不息!

Oracle数据库GUID作为主键执行速度过慢的原因到底在哪里呢?接下来我们开始介绍。首先介绍一下环境。数据库使用Oracle10g,所有字符类型的字段都是varchar2[1]。所有的主键都使用Guid,在数据库里是varchar2(36) 类型,相应的,实体的Id 属性的类型是string。ORM 使用的是NHibernate 2.1.0 和 FluentNHibernate1.1。

经过一番排查之后发现,问题的根源是NH将SQL语句传递给Oracle 时,所有字符型的参数都是nvarchar2 类型,而数据库里对应的字段却是varchar2 类型,这将导致Oracle 无法使用索引,终于造成全表扫描,所以数据量稍大就慢得不行。

***种解决方法是,把数据库中所有的字符型字段的类型由varchar2 更改为nvarchar2,出于种种原因我们不希望这么做。

第二种解决方法是,让NH把varchar2 作为参数类型传递给Oracle。

事实上,NH 默认把.net 的string 映射为DbType.String[2],把DbType.String映射为nvarchar2[3]。把DbType.AnsiString 映射为varchar2[4]。

所以对于查询比较简单,只要把HQL的参数类型指定为AnsiString 就行了。

varquery=Session.CreateQuery(@"selecttfromRegionast 

wheret.Id=:Id") 

.SetAnsiString("Id",id); 

varquery=Session.CreateQuery(@"selecttfromRegionast 

wheret.Idin(:Ids)") 

.SetParameterList("Ids",ids.ToList(),NHibernateUtil.AnsiString);

但是如何设置Update 和Delete语句的参数类型呢?这里有个小小的秘技,把映射文件里的属性类型指定为“AnsiString”即可。

publicclassRegionMap:TreeNodeMap<Region>

{ 

publicRegionMap() 

{ 

Table("INFRA_REGION"); 

Id(t=>t.Id,"REGION_ID").CustomType("AnsiString"); 

... 

} 

}

注意:一定要使用CustomType()而不是CustomSqlType()。

当然了,要是把每一个配置文件都改一遍实在很烦,好像项目使用了FluentNHibernate,只要添加一个 IdConvention 就行了。

publicclassIdConvention:FluentNHibernate.Conventions.IIdConvention 

{ 

publicvoidApply(FluentNHibernate.Conventions.Instances.IIdentityInstanceinstance) 

{ 

instance.CustomType("AnsiString"); 

} 

}

想要彻底一点的话,可以再加一个string类型的property的convention。

publicclassStringPropertyConvention:IPropertyConvention,IPropertyConventionAcceptance 

{ 

publicvoidAccept(IAcceptanceCriteria<IPropertyInspector>criteria) 

criteria.Expect(x=>x.Property.PropertyType==typeof(string)); 

publicvoidApply(IPropertyInstanceinstance) 

{ 

instance.CustomType("AnsiString"); 

} 

}

把这两个Convention 加到配置里面:

Session["SessionFactory"]=Fluently.Configure() 

.Database(OracleClientConfiguration.Oracle10 

.Dialect<Oracle10gDialect>() 

.ConnectionString("UserID=iBlast;Password=不可说;DataSource=Moki") 

.QuerySubstitutions("true1,false0,yes'Y',no'N'") 

.UseOuterJoin() 

.ProxyFactoryFactory<ProxyFactoryFactory>() 

.AdoNetBatchSize(1000) 

.Driver<OracleClientDriver>()) 

.Mappings(m=>{m.HbmMappings.AddFromAssembly(Assembly.Load("Infrastructure.Repositories")); 

m.FluentMappings.AddFromAssembly(Assembly.Load("Infrastructure.Repositories")) 

.Conventions.Add<EnumConvention>() 

.Conventions.Add<HasManyConvention>() 

.Conventions.Add<HasManyToManyConvention>() 

.Conventions.Add<StringPropertyConvention>() 

.Conventions.Add<IdConvention>() 

.ExportTo(@"F:\temp\");}) 

.BuildSessionFactory();

注意倒数第二行的.ExportTo(@"F:\temp\") 是为了测试一下生成的映射文件对不对而把映射文件输出到了 “F:\temp\”,映射文件应该像这个样子:

<hibernate-mappingxmlns="urn:nhibernate-mapping-2.2"default-access="property"auto-import="true"default-cascade="none"default-lazy="true">

<classxmlns="urn:nhibernate-mapping-2.2"dynamic-insert="true"dynamic-update="true"mutable="true"where="IsDelete=0"name="Dawn.HIS.Infrastructure.Core.Data.Region,Infrastructure.Core,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"table="INFRA_REGION">

<idname="Id"type="AnsiString">

<columnname="REGION_ID"/>

<generatorclass="assigned"/>

</id>

<versionname="Version"type="System.Int32,mscorlib,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089">

<columnname="Version"/>

</version>

<propertyname="CreateTime"type="System.DateTime,mscorlib,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089">

<columnname="CREATETIME"/>

</property>

<propertyname="Name"type="AnsiString">

<columnname="NAME"/>

</property>

... 

</class>

</hibernate-mapping>

说明:

[1] 之所以使用varchar2 而不是 nvarchar2,除了考虑 varchar2 可以节省空间之外,主要是为了避免nvarchar2 排序时的性能问题。

[2] 见 NHibernate-2.1.0.GA-src\src\NHibernate\Type\TypeFactory.cs 第 197 行。

[3] 见NHibernate-2.1.0.GA-src\src\NHibernate\Dialect\Oracle8iDialect.cs 第 92行。

[4] 见NHibernate-2.1.0.GA-src\src\NHibernate\Dialect\Oracle8iDialect.cs 第88行。

本文来源:1818IP

本文地址:https://www.1818ip.com/post/10312.html

免责声明:本文由用户上传,如有侵权请联系删除!

发表评论

必填

选填

选填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。