Dapper.net 的奇怪超时问题

Posted

技术标签:

【中文标题】Dapper.net 的奇怪超时问题【英文标题】:Weird timeout issues with Dapper.net 【发布时间】:2013-03-18 23:18:33 【问题描述】:

出于性能原因,我不久前开始使用 dapper.net,与仅在 LINQ To SQL 中运行“ExecuteQuery”相比,我真的很喜欢命名参数功能。

它适用于大多数查询,但我有时会遇到一些非常奇怪的超时。最奇怪的是,这种超时只发生在通过 dapper 执行 SQL 时。如果我从分析器中复制执行的查询并在 Management Studio 中运行它,它的速度很快,而且效果很好。这不仅仅是一个暂时的问题。查询始终通过 dapper 超时,并且在 Management Studio 中始终正常工作。

exec sp_executesql N'SELECT Item.Name,dbo.PlatformTextAndUrlName(Item.ItemId) As PlatformString,dbo.MetaString(Item.ItemId) As MetaTagString, Item.StartPageRank,Item.ItemRecentViewCount
                    NAME_SRCH.RANK as NameRank,
                    DESC_SRCH.RANK As DescRank, 
                    ALIAS_SRCH.RANK as AliasRank, 
                    Item.itemrecentviewcount,
                    (COALESCE(ALIAS_SRCH.RANK, 0)) + (COALESCE(NAME_SRCH.RANK, 0)) + (COALESCE(DESC_SRCH.RANK, 0) / 20) + Item.itemrecentviewcount / 4 + ((CASE WHEN altrank > 60 THEN 60 ELSE altrank END) * 4) As SuperRank
                    FROM dbo.Item
                    INNER JOIN dbo.License on Item.LicenseId = License.LicenseId

                    LEFT JOIN dbo.Icon on Item.ItemId = Icon.ItemId
                    LEFT OUTER JOIN FREETEXTTABLE(dbo.Item, name, @SearchString) NAME_SRCH ON
                    Item.ItemId = NAME_SRCH.[KEY] 
                    LEFT OUTER JOIN FREETEXTTABLE(dbo.Item, namealiases, @SearchString) ALIAS_SRCH ON
                    Item.ItemId = ALIAS_SRCH.[KEY] 
                    INNER JOIN FREETEXTTABLE(dbo.Item, *, @SearchString) DESC_SRCH ON
                    Item.ItemId = DESC_SRCH.[KEY]
                    ORDER BY SuperRank DESC OFFSET @Skip ROWS FETCH NEXT @Count ROWS ONLY',N'@Count int,@SearchString nvarchar(4000),@Skip int',@Count=12,@SearchString=N'box,com',@Skip=0

这是我从 SQL Profiler 复制粘贴的查询。我在我的代码中这样执行它。

            using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Conn"].ToString())) 
            connection.Open();
            var items = connection.Query<MainItemForList>(query, new  SearchString = searchString, PlatformId = platformId, _LicenseFilter = licenseFilter, Skip = skip, Count = count , buffered: false);
            return items.ToList();
        

我不知道从哪里开始。我想 dapper 一定有什么问题,因为当我执行代码时它工作正常。

正如您在此屏幕截图中看到的那样。这是先通过代码然后通过 Management Studio 执行的相同查询。

我还可以补充一点,这仅(我认为)在我有两个或更多单词或搜索字符串中有“停止”字符时发生。所以它可能与全文搜索有关,但我不知道如何调试它,因为它可以在 Management Studio 中完美运行。

更糟糕的是,它在我的本地主机上运行良好,使用代码和 Management Studio 几乎相同的数据库。

【问题讨论】:

【参考方案1】:

Dapper 只不过是 ado.net 上的实用程序包装器;它不会改变 ado.net 的运作方式。在我看来,这里的问题是“在 ssms 中有效,在 ado.net 中失败”。这不是唯一的:偶尔会发现这种情况很常见。可能的候选人:

“set”选项:这些在 ado.net 中具有不同的默认值 - 并且可能会影响性能,特别是如果您有计算 + 持久 + 索引列之类的东西 - 如果“set”选项不兼容,它可以决定它可以t 使用存储的值,因此不使用索引 - 而是使用表扫描和重新计算。还有其他类似的场景。 系统负载/事务隔离级别/阻塞;在 ssms 中运行某些东西并不会及时重现整个系统负载 缓存的查询计划:有时会缓存和使用 duff 计划;从 ssms 运行通常会强制执行新计划 - 自然会针对您在测试中使用的参数进行调整。更新所有索引统计信息等,并考虑添加“优化”查询提示

【讨论】:

很抱歉我的回复晚了,但测试起来有点困难。无论如何,我认为这与缓存的查询计划有关。我现在在本地超时并重新启动服务器,然后它工作了。我现在尝试添加一个“优化”的东西。希望这会有所帮助。感谢您的见解! 如何正确管理传入 Dapper/SqlCommand.ExecuteReader 的即席查询的“设置”选项? @Terry "set" 选项位于连接级别 - 所以您需要打开连接,然后(例如)connection.Execute("SET CONCAT_NULL_YIELDS_NULL ON");,然后(其余代码);您还可以在单​​个命令前加上 SET 指令。但是请注意,并非所有SET 选项都由sp_reset_connection 重置(在重新启动连接时自动执行) - 例如(特别是)SET TRANSACTION ISOLATION LEVEL blah; 即使在连接重置之间仍然存在,这可以...有趣 谢谢。以及调试为什么 ADO.NET 与 SSMS 超时的过程,只需开始切换 SET 选项,看看哪个会影响它? @akraines recompile 是一个可怕的提示,几乎不应该使用它; for unknown 可能是你想要的那个【参考方案2】:

在 ADO 中是​​ CommandTimeout 30 秒的默认值,在 Management Studio 中为无穷大。调整调用Query的命令超时时间,见下文。

var param = new  SearchString = searchString, PlatformId = platformId, _LicenseFilter = licenseFilter, Skip = skip, Count = count ;
var queryTimeoutInSeconds = 120;
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Conn"].ToString()))

    connection.Open();
    var items = connection.Query<MainItemForList>(query, param, commandTimeout: queryTimeoutInSeconds, buffered: false);
    return items.ToList();

另请参阅 SqlCommand.CommandTimeout Property on MSDN

【讨论】:

英文链接:docs.microsoft.com/en-us/dotnet/api/…【参考方案3】:

对于 Dapper,默认超时是 30 秒,但是我们可以通过这种方式增加超时。在这里,我们将超时时间增加 240 秒(4 分钟)。

    public DataTable GetReport(bool isDepot, string fetchById)
    
        int? queryTimeoutInSeconds = 240;
        using (IDbConnection _connection = DapperConnection)
        
            var parameters = new DynamicParameters();
            parameters.Add("@IsDepot", isDepot);
            parameters.Add("@FetchById", fetchById);
            var res = this.ExecuteSP<dynamic>(SPNames.SSP_GetSEPReport, parameters, queryTimeoutInSeconds);
            return ToDataTable(res);
        
    

在存储库层,我们可以为存储过程调用自定义的 ExecuteSP 方法,并带有附加参数“queryTimeoutInSeconds”。

下面是dapper的“ExecuteSP”方法:-

    public virtual IEnumerable<TEntity> ExecuteSP<TEntity>(string spName, object parameters = null, int? parameterForTimeout = null)
    
        using (IDbConnection _connection = DapperConnection)
        
            _connection.Open();
            return _connection.Query<TEntity>(spName, parameters, commandTimeout: parameterForTimeout, commandType: CommandType.StoredProcedure);
        
    

【讨论】:

【参考方案4】:

可能是在 Dapper 中设置命令超时的问题。以下是如何在 Dapper 中调整命令超时的示例: Setting Command Timeout in Dapper

【讨论】:

以上是关于Dapper.net 的奇怪超时问题的主要内容,如果未能解决你的问题,请参考以下文章

奇怪的git代理超时问题

Laravel 邮件奇怪的超时错误

使用Dapper.NET异步API时如何尊重CommandTimeout

表值函数真的很奇怪的问题

Eclipse 在调试模式下狂奔 - 几次后部署超时

奇怪的 G-WAN 响应速度差异