Problemi di timeout bizzarri con Dapper.net

dapper database-performance sql

Domanda

Ho iniziato a usare dapper.net un po 'di tempo fa per motivi di prestazioni e mi piace molto la funzionalità dei parametri denominata rispetto a eseguire semplicemente "ExecuteQuery" in LINQ To SQL.

Funziona alla grande per la maggior parte delle query, ma di tanto in tanto ottengo dei timeout davvero strani. La cosa più strana è che questo timeout si verifica solo quando SQL viene eseguito tramite dapper. Se prendo la query eseguita copiata dal profiler e la eseguo in Management Studio è veloce e funziona perfettamente. E non sono solo problemi temporanei. La query è costantemente timeout tramite dapper e funziona in modo coerente in 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

Questa è la query che copio copiata da SQL Profiler. Lo eseguo così nel mio codice.

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

Non ho idea da dove cominciare qui. Suppongo che ci sia qualcosa che sta succedendo con dapper poiché funziona bene quando eseguo il codice.

Come puoi vedere in questo screenshot. Questa è la stessa query eseguita prima tramite il codice e poi tramite Management Studio.

inserisci la descrizione dell'immagine qui

Posso anche aggiungere che questo solo (penso) accade quando ho due o più parole o quando ho un carattere "stop" nella stringa di ricerca. Quindi potrebbe avere qualcosa da fare con la ricerca di testo completo, ma non riesco a capire come eseguire il debug poiché funziona perfettamente da Management Studio.

E per rendere le cose ancora peggiori, funziona bene sul mio localhost con un database quasi identico sia dal codice che da Management Studio.

Risposta accettata

Dapper non è altro che un involucro di utilità su ado.net; non cambia il modo in cui ado.net opera. Mi sembra che il problema qui sia "works in ssms, fail in ado.net". Questo non è unico: è abbastanza comune trovarlo ogni tanto. Probabili candidati:

  • opzione "set": questi hanno diversi valori predefiniti in ado.net e possono avere un impatto sulle prestazioni, specialmente se hai cose come calcolato + persistente + colonne indicizzate - se le opzioni "set" non sono compatibili, può decidere che non può usare il valore memorizzato, quindi non l'indice, e invece scansionare e ricalcolare la tabella. Ci sono altri scenari simili.
  • carico di sistema / livello di isolamento della transazione / blocco; eseguire qualcosa in SSMS non riproduce l'intero carico del sistema in quel momento
  • piani di query memorizzati nella cache: a volte un piano duff viene memorizzato nella cache e utilizzato; l'esecuzione da ssms di solito impone un nuovo piano, che sarà naturalmente ottimizzato per i parametri che si stanno utilizzando nel test. Aggiorna tutte le statistiche dell'indice, ecc. E considera l'aggiunta del suggerimento per le query "ottimizza per"

Risposta popolare

In ADO è il valore predefinito per CommandTimeout 30 secondi, in Management Studio infinity. Regola il timeout del comando per chiamare la query <>, vedi sotto.

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

Vedi anche Proprietà SqlCommand.CommandTimeout su MSDN



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow