SQL-запрос медленный в приложении .NET, но мгновенный в SQL Server Management Studio - PullRequest
55 голосов
/ 29 апреля 2010

Вот SQL

SELECT tal.TrustAccountValue
FROM TrustAccountLog AS tal
INNER JOIN TrustAccount ta ON ta.TrustAccountID = tal.TrustAccountID
INNER JOIN Users usr ON usr.UserID = ta.UserID
WHERE usr.UserID = 70402 AND
ta.TrustAccountID = 117249 AND
tal.trustaccountlogid =  
(
 SELECT MAX (tal.trustaccountlogid)
 FROM  TrustAccountLog AS tal
 INNER JOIN TrustAccount ta ON ta.TrustAccountID = tal.TrustAccountID
 INNER JOIN Users usr ON usr.UserID = ta.UserID
 WHERE usr.UserID = 70402 AND
 ta.TrustAccountID = 117249 AND
 tal.TrustAccountLogDate < '3/1/2010 12:00:00 AM'
)

По сути, есть таблица Users, таблица TrustAccount и таблица TrustAccountLog.
Пользователи: содержит пользователей и их данные
TrustAccount: пользователь может иметь несколько TrustAccounts.
TrustAccountLog: содержит аудит всех «движений» TrustAccount.
TrustAccount связан с несколькими записями TrustAccountLog. Теперь этот запрос выполняется в миллисекундах внутри SQL Server Management Studio, но по какой-то странной причине он выполняется в моем приложении на C # вечно, а иногда даже в тайм-ауте (120 с).

Вот код в двух словах. Он вызывается несколько раз в цикле, и оператор готовится.

cmd.CommandTimeout = Configuration.DBTimeout;
cmd.CommandText = "SELECT tal.TrustAccountValue FROM TrustAccountLog AS tal INNER JOIN TrustAccount ta ON ta.TrustAccountID = tal.TrustAccountID INNER JOIN Users usr ON usr.UserID = ta.UserID WHERE usr.UserID = @UserID1 AND ta.TrustAccountID = @TrustAccountID1 AND tal.trustaccountlogid =  (SELECT MAX (tal.trustaccountlogid) FROM  TrustAccountLog AS tal INNER JOIN TrustAccount ta ON ta.TrustAccountID = tal.TrustAccountID INNER JOIN Users usr ON usr.UserID = ta.UserID WHERE usr.UserID = @UserID2 AND ta.TrustAccountID = @TrustAccountID2 AND tal.TrustAccountLogDate < @TrustAccountLogDate2 ))";
cmd.Parameters.Add("@TrustAccountID1", SqlDbType.Int).Value = trustAccountId;
cmd.Parameters.Add("@UserID1", SqlDbType.Int).Value = userId;
cmd.Parameters.Add("@TrustAccountID2", SqlDbType.Int).Value = trustAccountId;
cmd.Parameters.Add("@UserID2", SqlDbType.Int).Value = userId;
cmd.Parameters.Add("@TrustAccountLogDate2", SqlDbType.DateTime).Value =TrustAccountLogDate;

// And then...

reader = cmd.ExecuteReader();
if (reader.Read())
{
   double value = (double)reader.GetValue(0);
   if (System.Double.IsNaN(value))
      return 0;
   else
      return value;
}
else
   return 0;

Ответы [ 14 ]

0 голосов
/ 09 ноября 2015

Я понимаю, что OP не упоминает об использовании хранимых процедур, но есть альтернативное решение проблем перехвата параметров при использовании хранимых процедур, которое менее изящно, но сработало для меня, когда OPTION(RECOMPILE), похоже, ничего не делает .

Просто скопируйте ваши параметры в переменные, объявленные в процедуре, и используйте их вместо этого.

Пример:

ALTER PROCEDURE [ExampleProcedure]
@StartDate DATETIME,
@EndDate DATETIME
AS
BEGIN

--reassign to local variables to avoid parameter sniffing issues
DECLARE @MyStartDate datetime,
        @MyEndDate datetime

SELECT 
    @MyStartDate = @StartDate,
    @MyEndDate = @EndDate

--Rest of procedure goes here but refer to @MyStartDate and @MyEndDate
END
0 голосов
/ 20 декабря 2010

У меня была проблема с другой первопричиной, которая точно соответствовала названию симптомов этого вопроса.

В моем случае проблема заключалась в том, что набор результатов оставался открытым .NET-кодом приложения, в то время как он проходил по каждой возвращенной записи и выполнял еще три запроса к базе данных! Из-за нескольких тысяч строк этот вводящий в заблуждение исходный запрос выглядел так, как будто он медленно выполнялся на основе информации о времени из SQL Server.

Поэтому исправление состояло в том, чтобы реорганизовать код .NET, выполняющий вызовы, чтобы он не оставлял результирующий набор открытым при обработке каждой строки.

0 голосов
/ 29 апреля 2010

Похоже, вы не закрываете свой считыватель данных - это может начать складываться за несколько итераций ...

0 голосов
/ 29 апреля 2010

Я предлагаю вам попытаться создать хранимую процедуру, которая может быть скомпилирована и кэширована Sql Server и таким образом повысить производительность

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...