Поиск  
Always will be ready notify the world about expectations as easy as possible: job change page
24 марта

Три способа отладки T-SQL кода

Три способа отладки T-SQL кода
Автор:
Olesia Dudareva
Источник:
Просмотров:
1855

Написание нового кода = ошибки. С этим всё просто.

Избавится от ошибок – вот это сложная задача.

Программисты привыкли, что в их средствах разработки есть встроенные инструменты, показывающие, какая строка кода сейчас работает, отображают текущее содержимое переменных, выводят сообщения о процессе выполнения и т. д. Какое-то время в SQL Server Management Studio тоже был отладчик кода, но, начиная с версии SSMS v18, он был удален. Хотя даже когда отладчик был, я не фанател от него: SQL Server буквально мог прекратить обработку других запросов, пока выполнял ваш запрос. Это была катастрофа, особенно когда ваш запрос блокировал других пользователей, и всё это происходило на рабочей базе.

Мне бы хотелось, чтобы у нас был простой способ отладки T-SQL на рабочей базе без блокировок, но отладка T-SQL отличается от отладки в C#. Так что если ваш T-SQL код делает не то, что вы ожидали, вот несколько хороших способов для его отладки.

Вариант 1: Использовать PRINT

С незапамятных времен разработчики вставляли в код такие строки:

BEGIN TRAN
    PRINT 'Starting access date changes'

    UPDATE dbo.Users
        SET LastAccessDate = GETDATE()
        WHERE DisplayName = N'Brent Ozar';

    PRINT 'Done with access date, starting reputation changes'

    UPDATE dbo.Users
        SET Reputation = Reputation / 0
        WHERE DisplayName = N'jorriss';

    PRINT 'Done with reputation changes'
COMMIT

Чтобы видеть в какой части кода возникла ошибка, когда он упадет:

Отладка SQL

У этого подхода есть пара проблем:

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

Давайте попробуем улучшить нашу отладку с помощью RAISERROR.

Вариант 2: Использовать RAISERROR, произносится как raise-roar

Что? Вы не знали, что это слово произносится по-другому? Ладно, открою секрет, я тоже не знал, как оно произносится – Грег Лоу (Greg Low) из SQLDownUnder рассказал мне об этом. Давайте усложним наш код:

DECLARE @Debug BIT = 1;

BEGIN TRAN
    IF @Debug = 1
        RAISERROR (N'Starting access date changes', 0, 1) WITH NOWAIT

    UPDATE dbo.Users
        SET LastAccessDate = GETDATE()
        WHERE DisplayName = N'Brent Ozar';

    IF @Debug = 1
        RAISERROR (N'Done with access date, starting reputation changes', 0, 1) WITH NOWAIT

    UPDATE dbo.Users
        SET Reputation = Reputation / 0
        WHERE DisplayName = N'jorriss';

    IF @Debug = 1
        RAISERROR (N'Done with reputation changes', 0, 1) WITH NOWAIT

COMMIT

Я добавил переменную @Debug, и мои статусные сообщения теперь выводятся только тогда, когда @Debug = 1. Конкретно в этом примере мне не нужен параметр – но в ваших рабочих хранимых процедурах и функциях вам точно он будет нужен, только не забудьте указать значение этого параметра по умолчанию равным 0, как в примере ниже:

CREATE OR ALTER PROC dbo.DoStuff
    @MyParam VARCHAR,
    @Debug BIT = 0 AS
...

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

Я тоже переключился на RAISERROR с PRINT, потому что у RAISERROR есть полезный параметр WITH NOWAIT, который дает команду SQL Server на отправку статусного сообщения на клиента немедленно, не дожидаясь заполнения буфера.

Когда вы отлаживаете долгий или сложный процесс, возможно, вам захочется динамически управлять статусами сообщений. Предположим, у вас есть хранимая процедура, которая работает часами, и вы хотите понять, какая из ее частей работает дольше всего. Вы не собираетесь там сидеть с секундомером, и вы не собираетесь подойти попозже в надежде, что ваши запросы еще находятся в кэше планов запросов. Вместо этого вам хочется добавить дату/время в сообщение RAISERROR.

К сожалению, RAISERROR не поддерживает объединение строк. Поэтому вы должны передать в RAISERROR только одну строку, которая будет содержать всю нужную вам информация, как показано на примере ниже:

DECLARE @Now NVARCHAR(50);

SET @Now = CONVERT(NVARCHAR(50), GETDATE(), 26);
    RAISERROR (N'Done with reputation changes at %s', 0, 1, @Now) WITH NOWAIT

И это позволит вам получить дату и время на выходе:

Отладка SQL

Вы можете даже передавать несколько аргументов – тут можно найти больше информации о том, как работает RAISERROR.

Вариант 3: Использовать табличные переменные

Возможно, вы слышали от меня или других разработчиков, что использование табличных переменных понижает производительность. В большинстве своем это правда – но иногда они работают очень быстро, как раз об этом мы говорили в этом курсе Fundamentals of TempDB. Тем не менее, у табличных переменных есть одна особенность: они игнорируют транзакции.

BEGIN TRAN
    DECLARE @Progress TABLE (StatusDate DATETIME2, StatusMessage NVARCHAR(4000));

    INSERT INTO @Progress VALUES (GETDATE(), N'A one');
    INSERT INTO @Progress VALUES (GETDATE(), N'And a two');

ROLLBACK

SELECT * FROM @Progress ORDER BY StatusDate;

Даже в случае отката транзакции, я все равно получу значения табличных переменных:

Отладка SQL

Это полезно, когда вам нужно:

  • Отладить долго работающий процесс.
  • В процессе участвуют try/catch, begin/commit, в рамках которых что-то может упасть или откатиться.
  • Получить результат в табличной форме, возможно даже с несколькими колонками, XML, JSON, и т. д.

Так что вот они – 3 способа отладки без использования SSMS Debugger. Я обычно использую RAISERROR – это достаточно легко реализовать и этим механизмом будут пользоваться вечно. Конечно же, вариантов отладки гораздо больше.

Похожее
May 27
Author: SQL Fundamentals
Mastering SQL with practical examples SQL is a powerful tool for managing and manipulating data in relational databases. While basic SQL queries are essential, mastering advanced SQL queries empowers data professionals to extract complex insights and perform sophisticated data transformations....
May 14, 2023
Author: Edwin Klesman
In this article, I’ll show you what the basic steps are for converting a SQL query into LINQ. You’ll learn the basic steps needed while we convert an example query. In this article, it's assumed that you have a basic...
Jul 10, 2021
Author: Sam Walpole
I've recently gotten into using Docker in my development cycle and I'm really enjoying how much of a wonderful tool it is. One thing that always used to be a pain was setting up a development server to run SQL...
Jun 14
Author: Sithi Asma Basheer
The Top 15 Advanced SQL commands for Data Analysis and Data Engineering. Table of index Window functions Common Table Expressions (CTEs) Recursive queries Pivot tables Analytic functions Unpivot Conditional aggregation Date functions Merge statements Case statements String functions Grouping sets...
Написать сообщение
Тип
Почта
Имя
*Сообщение