2016-05-03 5 views
0

Полутехнический клиент сообщил, что их приложение на основе SQLServer (сторонняя сторона) периодически разбилось. Они не смогли определить, какой набор входных данных вызвал это, но, похоже, это происходит, когда конкретный SP был вызван на конкретный «код проекта».Курсоры SQL Server, ужасная производительность?

Так что я написал T-SQL скрипт для запуска каждого SP с каждым возможным входом и запустил его в SQL Server Studio:

--doing this makes it easier to see error messages 
SET NOCOUNT ON 

DECLARE @sp_name NVARCHAR(50) -- proc name 
DECLARE @id_proj NVARCHAR(50) -- project name 
DECLARE @SQL NVARCHAR(250) -- SQL command- 

DECLARE sp_cursor CURSOR FOR SELECT SPECIFIC_NAME FROM information_schema.routines WHERE routine_type = 'PROCEDURE' 

OPEN sp_cursor 
FETCH NEXT FROM sp_cursor INTO @sp_name 
WHILE @@FETCH_STATUS = 0 
BEGIN 
DECLARE pr_cursor CURSOR FOR SELECT ProjName FROM dtaprojects 
OPEN pr_cursor 
FETCH NEXT FROM pr_cursor INTO @id_proj 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SET @SQL = 'EXEC ' + @sp_name + ' ''' + @id_proj + '''' 
     BEGIN TRY 
      EXECUTE sp_executesql @SQL 
     END TRY 
     BEGIN CATCH 
      PRINT 'Error when running SP ''' + @sp_name + ''' with project ''' + @id_proj + '''' 
     END CATCH 
     FETCH NEXT FROM pr_cursor INTO @id_proj 
    END 
    CLOSE pr_cursor 
    DEALLOCATE pr_cursor 
    FETCH NEXT FROM sp_cursor INTO @sp_name 
END; 
CLOSE sp_cursor 
DEALLOCATE sp_cursor 

--and just to be safe... 
SET NOCOUNT OFF 

После запуска в течение 7 минут, студия обрушится. Несколько прогонов, никаких улучшений.

Так что я переписал код в VBA в Excel с помощью ADO:

Public Sub TestStoredProcs() 
    Dim WS As Worksheet 
    Set WS = ThisWorkbook.Sheets(1) 
    Dim R As Long 
    R = 1 

    Dim SQL As String 

    Dim DS As New Recordset 
    Dim DP As New Recordset 
    Dim DR As New Recordset 

    Dim Cnn As New Connection 
    Cnn.ConnectionString = cConStr 
    Cnn.Open 

    DS.Open "SELECT SPECIFIC_NAME FROM information_schema.routines WHERE routine_type='PROCEDURE'", Cnn 
    Do Until DS.EOF 
     DP.Open "SELECT ProjName FROM dtaprojects", Cnn 
     Do Until DP.EOF 
      SQL = "N'EXEC " & Trim(DS!SPECIFIC_NAME) & " ''" & Trim(DP!projname) & "'''" 
      WS.Cells(R, 1) = DS!SPECIFIC_NAME 
      WS.Cells(R, 2) = DP!projname 

      Debug.Print "EXECUTE sp_executesql " & SQL 

      DR.Open "EXECUTE sp_executesql " & SQL, Cnn 
      WS.Cells(R, 3) = DR.RecordCount 
      DR.Close 

      R = R + 1 
      DP.MoveNext 
     Loop 
     DP.Close 
     DS.MoveNext 
    Loop 
    DS.Close 
End Sub 

Это работает в 26 секунд.

Хорошо, так что здесь происходит? Являются ли курсоры T-SQL действительно , что slow? Я имею в виду, что версия VBA должна запускать три отдельных запроса ADO для каждой итерации, каждый из которых проходит по каналу и обратно, и в конечном итоге выполняет точный запрос . Итак, как может это возможно быть 100 раз быстрее, чем запустить код на самом сервере на своем родном языке? Это заставляет мой мозг болеть.

Или я вижу проблему в самой студии? Я подумал, что, возможно, у него заканчивается память, но, наблюдая за ее запуском, я не вижу, чтобы она работала быстрее, чем раньше. Но возможность все еще существует ... может кто-то предложить способ проверить это?

+0

Сколько строк есть для курсора для обработки? Кроме того, вы не должны использовать курсор с настройками по умолчанию, локальные, read_only и forward_only должны всегда использоваться, если это возможно. –

+0

Хороший вопрос. Проверка ... 188 SP, 45 проектов. –

+0

Это звучит не так. Являются ли процедуры, возвращающие наборы результатов? Возможно, использование результата для текста вместо сетки поможет. –

ответ

2

При запуске всех процедур в SQL Server Studio загружается и пытается отобразить все результирующие наборы. ADO в Excel этого не делает. Это объясняет разницу во времени: SQL Server Studio извлекает все строки, возвращаемые хранимыми процедурами.

Я буду запускать то же самое из SQL Server Studio, войдя в отдельную таблицу до и после каждого EXECUTE sp_executesql @SQL, и после сбоя проанализирует этот конкретный результат процедуры.

Также может случиться так, что SQL Server Studio выйдет из строя из памяти, пытаясь загрузить все эти наборы результатов.

+0

ОК, учитывая, что фактические результаты не важны, есть ли способ полностью отключить их? –

+0

@MauryMarkowitz [Как отключить результаты запроса при выполнении хранимой процедуры из хранимой процедуры?] (Http://stackoverflow.com/questions/212657/how-do-i-disable-query-results-when-executing- a-stored-procedure-from-a-stored-p) –

+0

Бинго. Я использовал LOCAL FORWARD_ONLY STATIC READ_ONLY' в курсорах и отключил выход - 26 секунд. Спасибо, парни! –

0

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

https://www.simple-talk.com/sql/learn-sql-server/sql-server-index-basics/

https://www.simple-talk.com/sql/database-administration/brads-sure-guide-to-indexes/