2016-06-17 3 views
1

Я использую этот код, чтобы вызвать функцию SQL, которая возвращает данные из таблицы базы данных SQL ServerSqlCommand.ExecuteReader стал очень медленно

string cmd = String.Format("select * from dbo.GetData(@userId, @fileId, @created);"); 

using (SqlConnection conn = new SqlConnection(connectionString)) 
{ 
    if (conn.State != ConnectionState.Open) 
     conn.Open(); 

    SqlCommand command = new SqlCommand(cmd, conn); 

    if (String.IsNullOrEmpty(userId)) 
     command.Parameters.AddWithValue("@userId", DBNull.Value); 
    else 
     command.Parameters.AddWithValue("@userId", userId); 

    if (String.IsNullOrEmpty(fileId)) 
     command.Parameters.AddWithValue("@fileId", DBNull.Value); 
    else 
     command.Parameters.AddWithValue("@fileId", docId); 

    command.Parameters.AddWithValue("@created", created); 

    internalWatch.Reset(); 
    internalWatch.Start(); 

    IDataReader reader = command.ExecuteReader();     
    table = GetDataTableFromDataReader(reader); 

    reader.Close(); 
    reader.Dispose(); 

    conn.Close(); 

    internalWatch.Stop(); 

В таблице я работаю с содержит немного больше, чем 1500000 и должны возвращать бит более 250 тыс. записей.

Если я выполняю функцию SQL в SSMS, для возврата результатов требуется 8 секунд, и я уже использовал код выше на прошлой неделе, чтобы получить результаты в своем рабочем приложении. В это время все было в порядке. Для получения результатов требуется код от 10 до 12 секунд.

Странно, что на сегодняшний день для выполнения тех же результатов требуется более 40 секунд, но я ничего не изменяю в функции SQL или самом коде. Единственное изменение, которое я сделал в моей программе, - это добавить еще несколько классов, которые не имеют никакого отношения к приведенному выше коду.

Если я отладки кода, я могу видеть, что линии

IDataReader reader = command.ExecuteReader(); 

необходимо большую часть времени.

Поскольку я ничего в функции SQL или сам код не изменится, я не могу понять, почему он так долго теперь ...

И если нужно, здесь функцию SQL, я я использую:

ALTER FUNCTION [dbo].[GetData] 
(@userId varchar(128) = NULL, 
@fileId varchar(192) = NULL, 
@created DateTimeOffset(7)) 
RETURNS TABLE 
AS 
    RETURN (
     WITH FindNewestVersion AS 
     (
      SELECT 
       *, 
       ROW_NUMBER() OVER (PARTITINO BY FileId, UserId 
            ORDER BY created DESC) rn 
      FROM 
       table1 
     ) 
     SELECT   
      q.Created, q.Updated, q.FileId, q.UserId, 
      F.column1, F.column2, F.column3 
     FROM    
      table2 AS F 
     INNER JOIN 
      table1 AS q ON F.column4 = q.PersonId AND F.created = q.created 
     INNER JOIN 
      (SELECT 
       created, PersonId, DocumentId 
      FROM 
       FindNewestVersion 
      WHERE 
       rn = 1) AS x ON q.created = x.created 
           AND q.PersonId = x.PersonId 
           AND q.FileId = x.FileId 

     WHERE   
      (F.column1 = 'Sample') 
      AND (q.Created <= @created) 
      AND (q.Updated >= @created) 
      AND Q.PersonId = ISNULL(@userId, Q.PersonId) 
      AND Q.FileId = ISNULL(@fileId, Q.FileId) 
) 

Благодарим за любые предложения!

+0

Это звучит как параметр sniffing. Если входной параметр UserId равен NULL, будет ли параметр fileID равно null? – DB101

+0

Нет, они отделены друг от друга. Таким образом, возможно, что userId имеет значение null, а fileId имеет значение и наоборот. Создается единственный параметр, который всегда требует значения. – Echelon

+0

Выполнено ли время выполнения в SSMS? – Andreas

ответ

2

Это похоже на случай параметра нюхает

Одна вещь, которую вы могли бы сделать, это переписать процедуру следующим образом:

`

DROP FUNCTION [dbo].[GetData] 
CREATE PROCEDURE[dbo].[GetData] 

(
@userId varchar(128) = NULL, 
@fileId varchar(192) = NULL, 
@created DateTimeOffset(7) 
) 

RETURNS TABLE 
AS 
DECLARE @l_userId varchar(128) = NULL, 
DECLARE @l_fileId varchar(192) = NULL, 
DECLARE @l_created DateTimeOffset(7) 

SET @l_userId = userId 
SET @l_fileId = fileId 
SET @l_created = @created 



(

WITH FindNewestVersion as 
(
    Select *, ROW_NUMBER() 
    over (partition by FileId, UserId ORDER BY created DESC)rn from table1 
) 


SELECT  q.Created, q.Updated, q.FileId, q.UserId, 
       F.column1, F.column2, F.column3 
FROM   table2 AS F INNER JOIN 
       table1 AS q 
       ON F.column4 = q.PersonId AND F.created = q.created 
       INNER JOIN 
       (
        select created, PersonId, DocumentId from FindNewestVersion where rn = 1 
       ) AS x ON q.created = x.created AND q.PersonId = x.PersonId AND q.FileId = x.FileId 

WHERE  (F.column1 = 'Sample') AND (q.Created <= @created) AND (q.Updated >= @created) 
And Q.PersonId = ISNULL(@l_userId, Q.PersonId) 
And Q.FileId = ISNULL(@l_fileId, Q.FileId) 
) 

` Вы можете получить вам данные, вы бы вызвали хранимую процедуру.

+0

Вы уверены, что синтаксис верен? Я не могу использовать «DECLARE» и «SET», как вы. Он говорит мне, что он ожидает «BEGIN_CS» или «RETURN» после «RETURNS TABLE AS», а также не знает параметра на данный момент – Echelon

+0

Я преобразовал его в хранимую процедуру. Вам нужно будет изменить свой C#, чтобы правильно это назвать – DB101

+0

Теперь это сработало для меня. Я не могу понять, почему это может иметь такое значение, но время исполнения лучше. Фактически, как хранимая процедура (или с объявлением, я не знаю), она даже немного быстрее, чем когда-либо прежде. Благодаря! – Echelon

Смежные вопросы