我正在使用nhibernate作为ORM。我的一个选择是令人难以置信的缓慢。问题是,生成sql需要很长时间。我确定这不是sql查询本身很慢,因为我用sql profiler定时查询本身。并且它表明在开始执行nhibernate代码和实际发送到db的查询之间存在~15秒的差距。生成的SQL查询本身就像我预期的那样快。
选择代码(在存储库中)如下
public IEnumerable<Document> GetAllDocumentsReadyForDeletion()
{
return from doc in _session.Query<Document>()
where doc.StorageType == 'D'
select doc;
}
我也尝试过:
return _session.CreateCriteria<Document>()
.Add(Restrictions.Eq("StorageType", 'D'))
.List<Document>();
等等(对吗?)。但是,它们的执行速度大致相同(缓慢,如15秒生成sql查询)
然而,这样做的速度和我想要的一样快,我不知道为什么:
return _session.CreateQuery(
"from Document doc where doc.StorageType = 'D'")
.List<Document>();
我真的想使用linq来nhibernate版本。知道为什么代码表现不同吗? (如果您需要更多详细信息,请询问!)
EDIT1
哦,伙计,我犯了一个愚蠢的错误或是什么..我错误地读取了sql profiler中错误的列.. ehm,前两个的实际执行时间是~18秒,第三个是~0秒。我试图找到sql atm的差异......
EDIT2
这实际上成了一个完全不同的问题。生成的查询几乎完全相同,除了前两个被包装在“exec sp_executesql”中
现在我用查询分析器跟踪了这一点,慢速查询只有一步:
clustered index scan.
快速查询有两个步骤:
Index seek
Bookmark lookup
有这样的经历吗?
答案 0 :(得分:1)
他们实际上生成了不同的sql。其中一个使用索引,而其中一个没有。这就是为什么。为什么其中一个使用索引而另一个不满足下一个问题。
(简体)生成的SQL
快速版:
SELECT Id, Name FROM documents WHERE StorageType = 'D'
慢速版本(linq和条件)(从内存atm键入,稍后会检查):
sp_execsql N'SELECT Id, Name FROM documents WHERE StorageType = @p0', N'@p0 nchar(1)', N'D'
请注意,'StorageType'的类型为varchar(1)。 This博客文章解释了为什么这很慢
这里的问题是@p0作为NCHAR(1)(也就是Unicode字符)传递,该列与非Unicode的列索引不匹配。这就是索引扫描。
显然,此表上的索引扫描大约需要17秒。
答案 1 :(得分:0)
它们是NHibernate中的不同路径,以获取相同的数据。他们使用不同的代码构造查询。有关NHibernate的linq提供程序的问题的讨论。我最后编写了自己的LINQ提供程序,将LINQ引入NHibernate,只在第二个示例中创建字符串,然后使用它来获取数据。