С миру по нитке... (ru-RU)
В этой статье я рассмотрю несколько разных полезностей.
Логирование выполнения хранимых процедур
Для решения задачи логирования выполнения хранимых процедур следуйте следующему алгоритму.
Шаг 1: Создайте таблицу, в которую вы будете вести логирование
USE <DBName> -- This is the database where the SP and table will reside
GO
CREATE TABLE [dbo].[tbl_errlog]
( [Logdate] [datetime] NULL,
[ProcessInfo] [varchar](100) NULL,
[Text] [varchar](1000) NULL
) ON [PRIMARY]
GO
Шаг 2: Создайте хранимую процедуру в <DBName>
create proc sp_logger
as
begin
declare @counter int
select @counter = COUNT(*) from dbo.tbl_errlog
if @counter = 0
begin
INSERT tbl_errlog
EXEC sp_readerrorlog
end
else
begin
CREATE TABLE #tmp_errlog
( Logdate datetime,
ProcessInfo varchar (100),
Text varchar (1000)
)
INSERT #tmp_errlog
EXEC sp_readerrorlog
declare @lastlog datetime
select @lastlog= MAX(Logdate) from tbl_errlog
INSERT INTO tbl_errlog (Logdate, ProcessInfo,Text)
SELECT Logdate, ProcessInfo,Text
FROM #tmp_errlog
WHERE Logdate > @lastlog
drop table #tmp_errlog
end
end
Шаг 3: Запустите выполнение хранимой процедуры как задание по расписанию. Однако ваша целевая таблица tbl_errlog может быстро вырасти, поэтому подумайте о стратегии архивирования и поддержки.
В какой строке произошла ошибка?
Иногда вы можете получить ошибку вида
Msg 50000, Level 16, State 1, Procedure TestToSeeWhatTheErrorLineNumberRefersTo, Line 14
Some Error
Сразу же возникает вопрос, а где именно произошла ошибка?
Давайте промоделируем эту ситуацию. Выполните код.
go
create procedure TestToSeeWhatTheErrorLineNumberRefersTo
as
raiserror ('Some Error',16,1)
go
exec TestToSeeWhatTheErrorLineNumberRefersTo
тут всё нормально, но ситуация будет интересной интересней, если вы используете динамический SQL. Измените хранимую процедуру следующим образом
alter procedure TestToSeeWhatTheErrorLineNumberRefersTo
as
execute ('raiserror (''Some Error'',16,1)')
go
Вы получите сообщение об ошибке.
Msg 50000, Level 16, State 1, Line 1
Some Error
Отметьте две вещи: изменился номер строки, в которой произошла ошибка и вы находитесь не в области действия хранимой процедуры.
Поэтому, когда использую динамический SQL, я добавляю режим отладчика и выведу какой код будет выполняться.
alter procedure TestToSeeWhatTheErrorLineNumberRefersTo
@debug int =0
as
declare @sql nvarchar(1000)
set @sql = '/* some comment or other code
more comments
*/
raiserror (''Some Error'',16,1)'
if @debug > 0
print @sql
exec sp_executesql @sql
Это позволяет получить инструкцию SQL, которая была выполнена и выяснить, какая строка относится к ошибке.
Быстрый способ получить количество строк в таблице
Вы конечно знаете как узнать сколько строк в таблице. Это вызов команды
SELECT COUNT(*) FROM TABLE
Но эта команда может выполняться очень долго
Начиная с версии SQL 2005 года системный каталог поддерживает (хранит) количество строк для таблицы и в отличие от в предыдущих версий поддерживает это значение в режиме реального времен. Таким образом мы получаем интересный подход к решению задачи.
select top 1 rows
from sys.partitions
whereobject_id =object_id(@tablename)
Для секционированной таблицы следует применить следующий код
select sum(rows) as row_count
from sys.partitions
where index_id in (0,1)
and object_id =object_id(@table)
Но этот способ с обращением к системному каталогу не транзакционен. Давайте рассмотрим пример. Выполните код.
create table fred (col1 int)
go
begin transaction
set nocount on
declare @i int = 0
while @i < 100000
begin
insert into fred values (@i)
set @i = @i + 1
end
А теперь запустите в другом процессе
select * from sys.partitions
where object_id = object_id ('fred')
Вы увидите, что есть 100000 строк. Но транзакция в первом процессе ещё не завершена
Вы готовы к SQL Server 2012?
SQL Server 2012 уже вышел. Я хочу остановиться на том функционале, который отменён в SQL Server 2012.
DATABASEPROPERTY()
Вы теперь должны использовать DATABASEPROPERTYEX(), или ещё лучше, получать информацию о вашей базе данных из представления системного каталога sys.databases
80 (SQL Server 2000) compatibility
Вы не сможете теперь использовать режим совместимости SQL Server 2000 (80). Это также означает что вы не сможете напрямую подключить или восстановить базу данных в формате SQL Server 2000. Вам нужно будет сперва присоединить или восстановить базу в SQL Server 2005/2008/2008R2. Можно даже использовать пробные версии.
osql
используйте sqlcmd или PowerShell. Нет причин использовать антикварное утилиту командной строки
SQLMail
Вы теперь должны использовать только Database Mail.
sqlmaint.exe
Больше вы не сможете управлять планами обслуживания с помощью этой утилиты командной строки.
SQL-DMO
используйте SMO.
SET FMTONLY
В настоящее время код (и возможно драйверы, которые вы используете для подключения к SQL Server) могут использовать SET FMTONLY ON для инспектирования результирующего набора команды. Эта функция в настоящее время заменена. Следует проверить ваш код, особенно если вы используете старые поставщиков для подключения к SQL Server.
SET ROWCOUNT для DML
Если вы в настоящее время опираетесь на использование SET ROWCOUNT для ограничения количества строк, затронутых командой UPDATE или DELETE, вы можете захотеть использовать вместо этого TOP.
DBCC LOGINFO
Могут возникнуть проблемы при использовании этой команды. Например, в таком варианте
CREATE TABLE #LI
(
[FileId] INT,
[FileSize] BIGINT,
[StartOffset] BIGINT,
[FSeqNo] INT,
[Status] INT,
[Parity] INT,
[CreateLSN] DECIMAL(25, 0)
);
INSERT #LI EXEC('DBCC LOGINFO(''msdb'');');
Этот код будет работать в SQL Server 2008 R2 и ниже, но не будет работать в SQL Server 2012.
Msg 213, Level 16, State 7, Line 1
Column name or number of supplied values does not match table definition
Это получается из-за того, что добавлен ещё один столбец в данных, возвращаемых этой командой. Что бы исправить ситуацию нужно внести изменения
CREATE TABLE #LI
(
[RecoveryUnitId] INT,
[FileId] INT,
[FileSize] BIGINT,
[StartOffset] BIGINT,
[FSeqNo] INT,
[Status] INT,
[Parity] INT,
[CreateLSN] DECIMAL(25, 0)
);
Правда теперь ваш код не будет универсальным и не сможет работать на всех версиях SQL Server.