我正在使用nHibernate,每个方法有一个会话。我正在使用Castle Dynamic Proxy在执行方法之前打开会话和事务,我提交事务并在执行此方法后立即关闭会话。
我正在使用SQLite数据库,如果将cascade设置为SaveUpdate,则None不会更改任何内容。 nHIbernate使用默认配置Fluent nHibernate进行配置。
当我刷新会话时,需要2秒以上。
public void AddNewChild(LightPatientDto patient, LightPatientDto child)
{
var ePatient = this.Session.Load<Patient>(patient.Id);
var eChild = this.Session.Load<Patient>(child.Id);
switch (ePatient.Gender)
{
case Gender.Male:
eChild.Father = ePatient;
break;
case Gender.Female:
eChild.Mother = ePatient;
break;
default:
Assert.FailOnEnumeration(eChild.Gender);
break;
}
this.Session.Update(eChild);
this.Session.Flush(); // <== takes more than 2 seconds
}
NHibernate profiler给我这个SQL在2008 ms执行。当我使用SQLite管理工具复制粘贴此SQL时,它会在90毫秒内执行。
UPDATE Patient
SET BirthDate = '1964-05-06T00:00:00.00' /* @p0 */,
Fee = 0 /* @p1 */,
Height = 0 /* @p2 */,
InscriptionDate = '2007-05-21T00:00:00.00' /* @p3 */,
PlaceOfBirth = 'xxxxxx' /* @p4 */,
PrivateMail = '' /* @p5 */,
PrivateMobile = NULL /* @p6 */,
PrivatePhone = '0496/xx.xx.xx' /* @p7 */,
Reason = 'diabète' /* @p8 */,
Father_id = 2 /* @p9 */,
Insurance_id = 1 /* @p10 */,
Mother_id = NULL /* @p11 */,
Practice_id = 1 /* @p12 */,
Profession_id = NULL /* @p13 */,
Reputation_id = 1 /* @p14 */
WHERE Person_id = 3 /* @p15 */
如何优化执行时间?
编辑1
正如@csanchez建议的那样,我已成功为我的实体添加动态更新。现在当我把SQL看成NH Profiler时,我得到了这个:
UPDATE Patient
SET Father_id = 2 /* @p0 */
WHERE Person_id = 21 /* @p1 */
这是一个很好的优化!但是,执行时间是...... 1852 ms o_O
在调试器中,我看到它提交的事务需要花费时间......而且我不知道它为什么这么慢......
编辑2
每位患者都有医疗图片,这些图片以字节数组的形式存储在表格中。这是表创建的SQL(由Fluent nHibernate完成)
CREATE TABLE Picture (
Id integer PRIMARY KEY AUTOINCREMENT,
Bitmap blob,
Creation datetime,
LastUpdate datetime,
Notes text,
IsImported bool,
Tag_id bigint,
Patient_id bigint,
ThumbnailBitmap blob,
/* Foreign keys */
FOREIGN KEY (Patient_id)
REFERENCES Patient(),
FOREIGN KEY (Tag_id)
REFERENCES "Tag"()
);
如果我使用DELETE Picture
删除数据并重新启动应用程序,则更新速度很快。
似乎nHibernate试图变得聪明并做一些减慢一切的事情。但是,如果我使用此代码执行纯SQL查询,则更新仍然需要超过一秒钟:
using (var tx = this.Session.BeginTransaction())
{
var sql = "UPDATE Patient SET Father_id = 2 WHERE Person_id = 21";
var query = this.Session.CreateSQLQuery(sql);
query.ExecuteUpdate();
tx.Commit();
}
答案 0 :(得分:1)
如果您更新的唯一内容是父母或母亲,您可以在患者的映射文件中使用dynamic-update="true"
。
答案 1 :(得分:0)
第一次提交数据库时,这个性能是否会受到影响。 SQLite可能有一些启动时间。
你说“每个方法的会话”但看起来你正在使用模块级会话变量。使用Session实例的次数越多,缓存就越慢。如果这将是一个批处理操作,请考虑StatelessSession。
同时检查NHibernate + Log4Net的日志配置。记录越详细,NH就越慢响应。
答案 2 :(得分:0)
每次更改数据时都不应刷新会话。您应该让NHibernate缓冲区更新并刷新批量更改。否则,他们会进行刷新隐式操作,而不用担心它。