15 votes

Problèmes étranges de délais d'attente avec Dapper.net

J'ai commencé à utiliser dapper.net il y a quelque temps pour des raisons de performances et j'aime beaucoup la fonction de paramètres nommés par rapport à la simple exécution de "ExecuteQuery" dans LINQ To SQL.

Il fonctionne très bien pour la plupart des requêtes mais j'obtiens de temps en temps des timeouts vraiment étranges. Le plus étrange est que ce timeout ne se produit que lorsque le SQL est exécuté via dapper. Si je prends la requête exécutée copiée à partir du profileur et que je l'exécute dans Management Studio, elle est rapide et fonctionne parfaitement. Et ce n'est pas seulement un problème temporaire. La requête fait constamment l'objet d'un timeout via dapper et fonctionne toujours parfaitement dans 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

C'est la requête que j'ai copié-collé de SQL Profiler. Je l'exécute comme ceci dans mon code.

            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();
        }

Je ne sais pas par où commencer. Je suppose qu'il doit y avoir quelque chose qui se passe avec dapper puisqu'il fonctionne bien quand j'exécute simplement le code.

Comme vous pouvez le voir dans cette capture d'écran. Il s'agit de la même requête exécutée via le code d'abord et ensuite via Management Studio.

enter image description here

Je peux également ajouter que cela ne se produit (je pense) que lorsque j'ai deux mots ou plus ou lorsque j'ai un caractère "stop" dans la chaîne de recherche. Il se peut donc que cela ait quelque chose à voir avec la recherche en texte intégral, mais je n'arrive pas à trouver comment le déboguer puisque cela fonctionne parfaitement depuis Management Studio.

Et pour aggraver les choses, cela fonctionne bien sur mon hôte local avec une base de données presque identique, à la fois dans le code et dans Management Studio.

13voto

Marc Gravell Points 482669

Dapper n'est rien de plus qu'une enveloppe utilitaire sur ado.net ; il ne change pas le fonctionnement d'ado.net. Il me semble que le problème ici est "fonctionne dans ssms, échoue dans ado.net". Ce n'est pas unique : il est assez courant de rencontrer ce problème occasionnellement. Candidats probables :

  • Option "set" : ces options ont des valeurs par défaut différentes dans ado.net - et peuvent avoir un impact sur les performances, en particulier si vous avez des choses comme des colonnes calculées+persistantes+indexées - si les options "set" ne sont pas compatibles, il peut décider qu'il ne peut pas utiliser la valeur stockée, donc pas l'index - et à la place, balayer la table et recalculer. Il existe d'autres scénarios similaires.
  • charge du système / niveau d'isolation des transactions / blocage ; l'exécution de quelque chose dans ssms ne reproduit pas la charge totale du système à ce moment-là
  • les plans de requête mis en cache : parfois un mauvais plan est mis en cache et utilisé ; l'exécution à partir de ssms forcera généralement un nouveau plan - qui sera naturellement ajusté pour les paramètres que vous utilisez dans votre test. Mettez à jour toutes vos statistiques d'index, etc., et envisagez d'ajouter l'indication de requête "optimiser pour".

8voto

Georg Points 1

Dans ADO, la valeur par défaut de CommandTimeout est de 30 secondes, dans Management Studio, elle est infinie. Ajustez le délai de commande pour l'appel de Query<>, voir ci-dessous.

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();
}

Voir aussi Propriété SqlCommand.CommandTimeout sur MSDN

3voto

aditya goyal Points 21

Pour Dapper, le délai d'attente par défaut est de 30 secondes. Mais nous pouvons augmenter le délai d'attente de cette façon. Ici, nous augmentons le délai de 240 secondes (4 minutes).

    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);
        }
    }

Dans la couche référentiel, nous pouvons appeler notre méthode ExecuteSP personnalisée pour les procédures stockées avec des paramètres supplémentaires "queryTimeoutInSeconds".

Et ci-dessous, la méthode "ExecuteSP" pour dapper:-

    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);
        }
    }

2voto

Jamie Points 92

Cela pourrait être une question de réglage du délai de commande dans Dapper. Voici un exemple de comment ajuster le délai de commande dans Dapper : Réglage du délai d'attente des commandes dans Dapper

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X