Метод SqlDataAdapter.Fill медленный

Почему хранимая процедура, которая возвращает таблицу с 9 столбцами, 89 строк с использованием этого кода, занимает 60 секунд для выполнения (.NET 1.1), когда она берет < 1 секунда для запуска в SQL Server Management Studio? Он запускается на локальном компьютере так мало/нет задержек в сети, быстро работает машина

Dim command As SqlCommand = New SqlCommand(procName, CreateConnection())
command.CommandType = CommandType.StoredProcedure
command.CommandTimeout = _commandTimeOut
Try
   Dim adapter As new SqlDataAdapter(command)
   Dim i as Integer
   For i=0 to parameters.Length-1
      command.Parameters.Add(parameters(i))
   Next
   adapter.Fill(tableToFill)
   adapter.Dispose()
Finally
   command.Dispose()
End Try

Набирается массив параметров (для этого SQL это только один параметр)

parameters(0) = New SqlParameter("@UserID", SqlDbType.BigInt, 0, ParameterDirection.Input, True, 19, 0, "", DataRowVersion.Current, userID)

Хранимая процедура - это только оператор select:

ALTER PROC [dbo].[web_GetMyStuffFool]
   (@UserID BIGINT)
AS
SELECT Col1, Col2, Col3, Col3, Col3, Col3, Col3, Col3, Col3
FROM [Table]

Ответ 1

Во-первых, убедитесь, что вы правильно профилируете производительность. Например, дважды запустите запрос из ADO.NET и посмотрите, будет ли второй раз намного быстрее, чем в первый раз. Это устраняет накладные расходы, ожидая, когда приложение будет компилироваться, а инфраструктура отладки развернется.

Затем проверьте настройки по умолчанию в ADO.NET и SSMS. Например, если вы запускаете SET ARITHABORT OFF в SSMS, вы можете обнаружить, что он работает так же медленно, как при использовании ADO.NET.

То, что я однажды обнаружил, состояло в том, что SET ARITHABORT OFF в SSMS вызвало перекомпилированную сохраненную копию и/или другую статистику, которая будет использоваться. И вдруг SSMS и ADO.NET сообщали примерно то же время выполнения.

Чтобы проверить это, просмотрите планы выполнения для каждого запуска, в частности таблицу syscacheobjects. Вероятно, они будут разными.

Запуск "sp_recompile" в конкретной хранимой процедуре приведет к удалению связанного плана выполнения из кеша, что дает SQL Server возможность создать, возможно, более подходящий план при следующем выполнении процедуры.

Наконец, вы можете попробовать " nuke it from orbit" подход к очистке всего кеша процедур и буферов памяти с использованием SSMS:

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

Выполняя это до того, как вы проверите свой запрос, запрещается использование кэшированных планов выполнения и кеша предыдущих результатов.

Ответ 2

Вот что я сделал:

Я выполнил следующий оператор SQL, чтобы перестроить индексы во всех таблицах в базе данных:

EXEC <databasename>..sp_MSforeachtable @command1='DBCC DBREINDEX (''*'')', @replacechar='*'
-- Replace <databasename> with the name of your database

Если бы я хотел увидеть одно и то же поведение в SSMS, я запускал proc следующим образом:

SET ARITHABORT OFF
EXEC [dbo].[web_GetMyStuffFool] @UserID=1
SET ARITHABORT ON

Другой способ обойти это - добавить это в свой код:

MyConnection.Execute "SET ARITHABORT ON"

Ответ 3

Я столкнулся с той же проблемой, но когда я перестроил индексы в таблице SQL, он работал нормально, поэтому вам может потребоваться перестроить индекс на стороне сервера sql

Ответ 4

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

EDIT:

Если вам нужно, чтобы он был DataTable, вы все равно можете извлечь данные из БД через DataReader, а затем в .NET-коде использовать DataReader для заполнения DataTable. Это должно быть быстрее, чем полагаться на DataSet и DataAdapter

Ответ 6

Я не знаю, почему это так медленно, но, как указывает Маркус, сравнение Mgmt Studio с заполнением набора данных - это яблоки для апельсинов. Наборы данных содержат много накладных расходов. Я ненавижу их и НИКОГДА не использую их, если могу помочь.

У вас могут возникнуть проблемы с несоответствиями старых версий стека SQL или некоторых таких (например, вы явно застряли в .NET 1.1). Рамочная платформа, вероятно, пытается использовать эквивалент базы данных "Reflection" для вывода схемы etc etc etc

Одна вещь, которую следует рассмотреть с вашим неудачным ограничением, - это доступ к базе данных с помощью datareader и создание собственного набора данных в коде. Вы можете легко найти образцы через google.