【发布时间】:2022-08-23 21:14:36
【问题描述】:
TL;DR:在 Fluent NHibernate 中使用通配符/类似的查询比使用 Management Studio 执行完全相同的查询要长四倍。这只发生在 MS-SQL 中,而 Postgres 工作得很好。他们查询只返回两个命中。
我正在使用 Fluent NHibernate 使用通配符(如运算符)查询 1 亿行表,如下所示:
return await foobarQuery.Select(e => e.Id).ToListAsync();
我有控制台记录生成的 SQL 查询是这样的:
select
foobar0_.[Id] as col_0_0_
from
[FooBar] foobar0_
where
exists (
select
foobarfi1_.[Id]
from
[FooBarFile] foobarfi1_
where
foobar0_.[Id]=foobarfi1_.[FooBarId]
and (
foobarfi1_.[FileName] like \'%Lorem Ipsum%\'
)
)
order by
foobar0_.[Id] asc;
当我在 Microsoft SQL Management Studio 中执行此操作时,大约需要 30 秒。但是 NHibernate 查询需要两分钟才能完成!它只返回两次命中,因此罪魁祸首不可能是对返回数据的处理。
为了让事情变得更有趣,当我在 Postgres 数据库中尝试完全相同的事情时,在 pgAdmin 和我的 Fluent NHibernate 查询中都需要大约 15 秒才能完成。 (我想我必须接受 Postgres i 快三倍的事实,这个问题就是 NHibernate 查询慢得多的原因。)
那么问题来了,是什么导致 MS SQL + Fluent NHibernate 变得这么慢呢?它几乎是 Management Studio 中直接查询的四倍,而使用 Postgres 时几乎没有等效的开销。
示例代码:
public static async Task<ICollection<int>> GetFooBarIdsAsync(ISession session)
{
Expression<Func<FooBarFile, bool>> predicate = null;
predicate = predicate.OR(ef => ef.FileName.Like(\"%lorem Ipsum%\"));
var foobars = session.Query<FooBar>();
foobars = foobars.Where(e => e.FooBarFiles.AsQueryable().Any(predicate));
var sw = Stopwatch.StartNew();
var result = await foobars.Select(e => e.Id).ToListAsync();
var time = sw.Elapsed;
return result;
}
-
所以这可能是一个 sql-parameter-sniffing 问题。你可以看看这篇文章。 dba.stackexchange.com/questions/11710/… 另一个可能的\"trick\" .. 是添加一个\"always equates with a random value\" 子句。 foobarfi1_.[FileName] like \'%Lorem Ipsum%\' AND \'abc123\' = \'abc123\' << 使用实体框架,我使用字符串 randomParameterSniffingBuster = Guid.NewGuid().ToString(\" N\"); qry = qry.Where(ent => randomParameterSniffingBuster.Equals(randomParameterSniffingBuster));
-
其中 qry 是(System.Linq)公共接口 IQueryable .. 和 abc123 .. 你希望这个值每次都不同......因此我的 randomParameterSniffingBuster 值基于 NewGuid。
-
感谢您的反馈@granadaCoder。正如链接文章所建议的那样,我们上周使用“option(recompile)”实现了一个解决方案。随时将其发布为答案,我会接受。 :-)
标签: c# .net sql-server nhibernate fluent-nhibernate