【问题标题】:Slow query in MS-SQL + Fluent NHibernateMS-SQL + Fluent NHibernate 中的慢查询
【发布时间】: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\" 子句。 foob​​arfi1_.[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


【解决方案1】:

所以这可能是一个 sql-parameter-sniffing 问题。你可以看看这篇文章。

https://dba.stackexchange.com/questions/11710/nhibernate-parameter-sniffing-sql-server-2005-vs-sql-server-2008

简而言之,你试图得到

"option(recompile)"

成为您查询的一部分以避免缓存/参数嗅探问题。

另一个可能的“技巧”.. 是添加“始终等同于随机值”子句。

foobarfi1_.[FileName] like '%Lorem Ipsum%' AND 'abc123changesEveryTime' = 'abc123changesEveryTime'

使用实体框架,我这样做

(System.Linq.IQueryable qry = /* all the other stuff to start your query */

string randomParameterSniffingBuster = Guid.NewGuid().ToString("N"); 
qry = qry.Where(ent => randomParameterSniffingBuster.Equals(randomParameterSniffingBuster)); 

这类似于“我们”在过去为避免网络缓存所做的事情。 (除了“技巧”的想法之外,web-cache 和 ORM 数据库代码根本不相关)

www.somesite.com/thingThatCachesTooMuch?fakevalue=abc123changesEveryTime

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 2018-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多