2008-11-19 2 views
26

Я обнаружил, что хранимые процедуры SQL очень интересны и полезны. Я написал хранимые процедуры, но я хочу писать хорошо продуманные, хорошо подготовленные и сжатые SP для любых требований, а также хотел бы узнать о любых трюках или передовой практике хранимых процедур. Как перейти от новичка к продвинутому этапу при написании хранимых процедур?Каковы наилучшие методы написания хранимой процедуры sql

Обновление: Найдено из комментариев, что мой вопрос должен быть более конкретным. У каждого есть свои трюки на рукавах, и я ожидал таких трюков и практик для SP, которые они используют в своем коде, который отличает их от других и, что более важно, повышает производительность в письменной форме и работает с хранимыми процедурами.

+2

Это похоже на высказывание: «Я писал истории, но я хочу писать хорошо продуманные, бестселлеры и романы для всех типов читателей, а также хотел бы узнать о любых трюках или хороших практиках для написания историй». Могу быть более конкретным в том, что вы ищете ... –

+0

Согласованные, более конкретные вопросы были бы хорошими. – ahockley

ответ

17

Единственный трюк, который я всегда пытаюсь использовать: всегда включайте пример использования в комментарии в верхней части. Это также полезно для тестирования вашего SP. Мне нравится включать наиболее распространенные примеры - тогда вам даже не требуется SQL-запрос или отдельный файл .sql с вашим любимым вызовом, поскольку он хранится там прямо на сервере (это очень полезно, если вы сохранили procs, которые смотрят на sp_who для блоков или любого другого и взять кучу параметров).

Что-то вроде:

/* 
    Usage: 
    EXEC usp_ThisProc @Param1 = 1, @Param2 = 2 
*/ 

Затем, чтобы проверить или запустить SP, вы просто выделите этот раздел в сценарии и выполнить.

1

Это не вопрос, на который можно ответить напрямую без дополнительной информации, но на самом деле действуют несколько общих правил.

Хранимые процедуры - это просто T-SQL-запросы, которые хранятся. Поэтому, более знакомы с T-SQL, а различные функции и синтаксисы - это то, что вам нужно делать. И тем более с точки зрения производительности вам нужно будет обеспечить соответствие ваших запросов и базовых структур данных таким образом, чтобы обеспечить хорошую производительность. IE, убедитесь, что индексы, отношения, ограничения и т. Д. Реализуются там, где это необходимо.

Понимание того, как использовать настройки инструментов производительности, understaning как работают планы выполнения, и вещи такого рода являются, как вы получите, что «следующий уровень»

11

Это очень общий вопрос, но вот пара советы по использованию:

  • Назовите свои хранимые процедуры последовательно. Многие используют префикс для идентификации того, что это хранимая процедура, но не используют «sp_» в качестве префикса, как это указано для Master databae (в любом случае SQL Server).
  • Установите NOCOUNT, поскольку это уменьшает количество возможных возвращаемые значения
  • Запросы, основанные на настройках, часто работают лучше, чем курсоры. This question вникает в это гораздо более подробно.
  • Если вы являетесь переменными DECLARE для вашей хранимой процедуры, используйте хорошие соглашения об именах так же, как и вы, в любом другом программировании.
  • Позвоните в SP с использованием своего полностью квалифицированного имени, чтобы устранить путаницу в отношении того, какой SP должен быть вызван, а также для повышения производительности SQL Server; это облегчает поиск рассматриваемого СП.

Есть намного больше, конечно.Вот ссылка на более: SQL Server Stored Procedures Optimization Tips

3

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

 
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'usp') AND type in (N'P', N'PC')) 
DROP PROCEDURE usp 
+2

Вы можете упростить это с: IF OBJECT_ID (N'dbo.usp ') IS NOT NULL ПРОЦЕДУРА DROP dbo.usp GO CREATE PROCEDURE dbo.usp ... – Tom

+0

это не то, что ALTER для. .. – dotjoe

+3

yes alter может сделать то же самое, но если вы напишете его как alter и перейдите, чтобы поместить его на сервер в первый раз, он потерпит неудачу. Этот процесс будет работать независимо от того, существует ли провал или нет. – HLGEM

0

Основной материал:

Have обработки ошибок политики в и перехватывать ошибки на всех операторов SQL.
Определите политику использования управления исходным кодом для хранимых процедур.
Включите заголовок с комментариями пользователя, дату/время и назначение sp.
Явно возвращать 0 (успех) для успешного выполнения, что-то еще в противном случае.
Для нетривиальных процедур включают тестовый пример (или случаи) и описание ожидаемого результата.
Получите привычку к тестированию производительности. Для текстовых случаев запишите время выполнения записи как минимум.
Понимать явные транзакции и использовать их.
Почти никогда не вызывайте SP из SP. Повторное использование - это другая игра с SQL.

+0

Почему бы не вызвать SP из SP? Я делаю это все время по необходимости; если я не нарушаю принцип СУХОЙ ...? –

+0

DRY применяется к процедурному коду, а не декларативному коду. Если это процедурная логика в sp, я предлагаю вам переместить ее на другой уровень, где это, безусловно, имеет смысл. – dkretz

+1

Еще одно сильное препятствие. Многоуровневые ROLLBACK TRANs * так * прикручены. – dkretz

1

Это зависит от того, что вы делаете в хранимых процедурах. Тем не менее, рекомендуется использовать транзакции, если вы делаете несколько вложений/обновлений или удалений в одном proc. Таким образом, если одна часть не удалась, остальные части откатываются назад, оставив вашу базу данных в согласованном состоянии.

Две наиболее важные вещи, которые следует учитывать при записи в базу данных (и, следовательно, при использовании хранимой процедуры, которая выполняет действие, отличное от выбора), - это целостность и производительность данных. Без целостности данных у вас просто есть база данных, содержащая мусор и бесполезная. Без performacne у вас не будет пользователей (если они находятся за пределами клиентов) или недовольных пользователей (если им поручено использовать ваш продукт, обычно это внутренние пользователи, у которых нет другого выбора в другом месте). Ни один из них не подходит для вашей карьеры. Поэтому при написании хранимой процедуры убедитесь, что вы сначала убедитесь, что данные будут правильно введены в базу данных и что они не сработают, если есть проблема в одной части действия.

Если необходимо выполнить проверку записи в proc, чтобы гарантировать, что ваш конечный результат будет правильным. Я специалист по ETL, и я всегда пишу свои procs, чтобы очистить и нормализовать данные, прежде чем пытаться импортировать их в свои таблицы. Если вы делаете что-то из пользовательского интерфейса, это может быть не так важно делать в proc, хотя я бы хотел, чтобы пользовательский интерфейс выполнял проверку перед тем, как даже запустить proc, чтобы данные были хорошими для вставки (например, проверка, чтобы убедиться поле даты содержит реальную дату, что все обязательные поля имеют значения и т. д.)

Если вы пишете procs для размещения больших объемов данных в таблицах, лучше всего иметь способ проверить эти результаты до их окончательной настройки , Вы будете поражены нежелательным результатом, который вы получите от клиентов и поставщиков для импорта данных. Мы пишем все наши процессы импорта с помощью тестового флага. Таким образом, вы можете вернуть выбранные данные, а не выполнять действие, чтобы вы могли видеть заранее, что именно вы повлияли.

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

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

Если вы используете операторы case или if, убедитесь, что вы сделали тестирование, которое ударит по каждой возможной ветке. Тот, который вы не тестируете, тот, который не пройдет.

35

Вот мои правила обращения с ошибками в хранимой процедуре.

  • Вызовите каждую хранимую процедуру с использованием ее полного имени для повышения производительности: это имя сервера, имя базы данных, имя схемы (владельца) и имя процедуры.
  • В скрипте, который создает каждую хранимую процедуру, явно указывается, какие роли разрешены для выполнения процедуры, например, публичной или любой другой.
  • Используйте sysmessage, sp_addmessage и заполнители, а не жестко закодированные сообщения об ошибках.
  • При использовании sp_addmessage и sysmessages всегда используйте номер сообщения об ошибке 50001 или выше.
  • С RAISERROR всегда указывайте уровень серьезности < = 10 для предупреждающих сообщений.
  • С RAISERROR всегда указывайте уровень серьезности между 11 и 16 для сообщений об ошибках.
  • Помните, что использование RAISERROR не всегда прерывает выполнение какой-либо партии, даже в контексте триггера.
  • Сохраните @@error локальной переменной перед ее использованием или опросом.
  • Сохраните @@ rowcount до локальной переменной перед ее использованием или опросом.
  • Для хранимой процедуры используйте возвращаемое значение, чтобы указать только успех/отказ, а не любую другую/дополнительную информацию.
  • Возвращаемое значение для хранимой процедуры должно быть установлено в 0, чтобы указать успех, отличное от нуля, чтобы указать отказ.
  • Set ANSI_WARNINGS ON - это определение нулевых значений в любом присвоении агрегата и любое присвоение, которое превышает максимальную длину символа или двоичного столбца.
  • Комплект NOCOUNT ON, по многим причинам.
  • Подумайте о том, хотите ли вы XACT_ABORT ON or OFF. Каким бы способом вы ни пошли, будьте последовательны.
  • Выход на первую ошибку - это реализует модель KISS.
  • При выполнении хранимой процедуры всегда проверяйте как ошибку @@, так и возвращаемое значение. Например:

    EXEC @err = AnyStoredProc @value 
    SET @save_error = @@error 
    -- NULLIF says that if @err is 0, this is the same as null 
    -- COALESCE returns the first non-null value in its arguments 
    SELECT @err = COALESCE(NULLIF(@err, 0), @save_error) 
    IF @err <> 0 BEGIN 
        -- Because stored proc may have started a tran it didn't commit 
        ROLLBACK TRANSACTION 
        RETURN @err 
    END 
    
  • При выполнении локальной хранимой процедуры, которая приводит к ошибке, сделать откат, потому что это возможно процедура начала транзакцию, он не совершал или отката.
  • Не предполагайте, что только потому, что вы еще не начали транзакцию, нет активной транзакции - возможно, ее активировал абонент.
  • В идеале избегайте выполнения отката по транзакции, которая была запущена вашим абонентом - поэтому проверьте @@ trancount.
  • Но в триггере всегда выполняйте откат, так как вы не знаете, инициировал ли вызывающий актив активную транзакцию (потому что @@ trancount всегда> = 1).
  • Всегда магазин и проверить @@ ошибка после следующих утверждений:

    INSERT, DELETE, UPDATE 
    SELECT INTO 
    Invocation of stored procedures 
    invocation of dynamic SQL 
    COMMIT TRANSACTION 
    DECLARE and OPEN CURSOR 
    FETCH from cursor 
    WRITETEXT and UPDATETEXT 
    
  • Если DECLARE CURSOR терпит неудачу на процесс глобального курсора (по умолчанию), вопрос с заявлением для освобождения курсора.
  • Будьте осторожны с ошибкой в ​​UDF. Когда в UDF возникает ошибка, выполнение функции прерывается немедленно, и поэтому запрос, вызывающий ошибку UDF, но @@, равен 0! Вы можете запустить с SET XACT_ABORT ON в этих обстоятельствах.
  • Если вы хотите использовать динамический SQL, попробуйте иметь только один SELECT в каждой партии, потому что ошибка @@ содержит только статус последней выполненной команды. Наиболее вероятными ошибками из пакета динамического SQL являются синтаксические ошибки, и они не учитываются SET XACT_ABORT ON.
+0

Хороший длинный список. Спасибо за руководство. – Shiham

+0

С SQL 2012 вместо проверки ошибки @@, чтобы решить, нужен ли откат, вы можете использовать XACT_STATE() http://technet.microsoft.com/en-us/library/ms189797.aspx – nojetlag

10
  1. Всегда используйте SET NOCOUNT ON
  2. Если вы собираетесь выполнять две или более вставки/обновления/удаления, пожалуйста, используйте транзакцию.
  3. Никогда не назовите ваш procs 'sp_'. Сначала SQL Server будет искать в основной базе данных, а не искать ее, а затем искать в своей базе данных вторую. Если вы будете называть свои procs по-разному, SQL Server будет сначала искать в вашей базе данных.

Bad:

SET NOCOUNT ON 
BEGIN TRAN 
    INSERT... 
    UPDATE... 
COMMIT 

Лучше, но выглядит неаккуратно и основных боль код:

SET NOCOUNT ON 
BEGIN TRAN 
    INSERT... 
    IF @ErrorVar <> 0 
    BEGIN 
     RAISERROR(N'Message', 16, 1) 
     GOTO QuitWithRollback 
    END 

    UPDATE... 
    IF @ErrorVar <> 0 
    BEGIN 
     RAISERROR(N'Message', 16, 1) 
     GOTO QuitWithRollback 
    END 

    EXECUTE @ReturnCode = some_proc @some_param = 123 
    IF (@@ERROR <> 0 OR @ReturnCode <> 0) 
     GOTO QuitWithRollback 
COMMIT 
GOTO EndSave    
QuitWithRollback: 
    IF (@@TRANCOUNT > 0) 
     ROLLBACK TRANSACTION 
EndSave: 

Хорошо:

SET NOCOUNT ON 
SET XACT_ABORT ON 
BEGIN TRY 
    BEGIN TRAN 
    INSERT... 
    UPDATE... 
    COMMIT 
END TRY 
BEGIN CATCH 
    IF (XACT_STATE()) <> 0 
     ROLLBACK 
END CATCH 

Лучшие:

SET NOCOUNT ON 
SET XACT_ABORT ON 
BEGIN TRAN 
    INSERT... 
    UPDATE... 
COMMIT 

Так где же обработка ошибок в «Лучшем» решении? Вам не нужны. См. SET XACT_ABORT ON, что означает автоматический откат при возникновении ошибок. Код чище и проще в чтении, проще писать и менее багги. Меньше багги, потому что нет возможности упустить ошибку, поскольку SQL Server теперь делает это за вас.

+0

Уважаемый Саймон Хьюз пожалуйста. Приведите пример с заявлением о демонстрационной вставке от начала и до конца написания процедуры – sidhewsar

1

С SQL Server 2008 используйте конструкцию TRY ... CATCH, которую вы можете использовать в своих хранимых процедурах T-SQL, чтобы обеспечить более изящный механизм обработки исключений, чем это было в предыдущих версиях SQL Server, путем проверки @@ ERROR (и часто использование операторов GOTO) после каждой инструкции SQL.

  BEGIN TRY 
      one_or_more_sql_statements 
     END TRY 
     BEGIN CATCH 
      one_or_more_sql_statements 
     END CATCH 

Когда в CATCH блоке, можно использовать следующие функции ошибок для сбора информации об ошибке, вызвавшей блок CATCH,

  ERROR_NUMBER() 
     ERROR_MESSAGE() 
     ERROR_SEVERITY() 
     ERROR_STATE() 
     ERROR_LINE() 
     ERROR_PROCEDURE() 

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

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