Andraptor's SQL Blog


Справочник Wait Types и Latches

В начале мая Paul Randal анонсировал в своем блоге завершение работы над созданием справочника Wait Types и Latches.
Отличная работа!
Вот и они:
https://www.sqlskills.com/help/latches/
https://www.sqlskills.com/help/waits/
добавлено: 02 июн 16 просмотры: 760, комментарии: 0



Накатывание нескольких резервных копий Transaction Log подряд

Недавно в MS SQL 2012 необходимо было восстановить базу на определенный момент времени. В базе настроен Log Shipping на очень удаленный сервер, поэтому файлов .trn после последнего дифференциального бэкапа оказалось дох..., вообщем много. В связи с этим написал небольшой скрипт, который сортирует .trn файлы по дате и накатывает их подряд, так же указывается каким файлом начинать восстановление, а каким заканчивать.

читать дальше...
добавлено: 19 окт 13 просмотры: 880, комментарии: 0



Создание Snapshot базы данных

Когда-то уже выкладывал на форуме. Но пусть все будет в одном месте, к тому же немного подправил.
--создается SNAPSHOT для указанной базы данных в формате: ИмяБазыДанных+_SS+ГодМесяцДень+ЧасМинута
--файлы SNAPSHOT создаются в тех же местах, что и исходные файлы, если явно не указан другой путь
USE DB1

DECLARE @FilePath VARCHAR(2000) = ''
	,@SnapDBName VARCHAR(200) = db_name() + '_SS' + convert(VARCHAR(10), getdate(), 112) + '_' + right('0' + Datename(hh, getdate()), 2) + right('0' + Datename(mi, getdate()), 2)
	,@result VARCHAR(max) = ''

IF db_id(@SnapDBName) IS NULL
BEGIN
	SET @result = 'CREATE DATABASE [' + @SnapDBName + '] ON 
'

	--SET @FilePath = 'E:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\'
	IF @FilePath = ''
		SELECT @Result += ' ( NAME = ' + NAME + ', FILENAME = ''' + reverse(substring(reverse(physical_name), charindex('\', reverse(physical_name)), len(reverse(physical_name)))) + reverse(substring(reverse(physical_name), charindex('.', reverse(physical_name)) + 1, charindex('\', reverse(physical_name)) - charindex('.', reverse(physical_name)) - 1)) + '_SS' + convert(VARCHAR(10), getdate(), 112) + '_' + right('0' + Datename(hh, getdate()), 2) + right('0' + Datename(mi, getdate()), 2) + '.ss''),
'
		FROM sys.master_files
		WHERE database_id = db_id()
			AND [type] = 0
	ELSE
		SELECT @Result += ' ( NAME = ' + NAME + ', FILENAME = ''' + @FilePath + reverse(substring(reverse(physical_name), charindex('.', reverse(physical_name)) + 1, charindex('\', reverse(physical_name)) - charindex('.', reverse(physical_name)) - 1)) + '_SS' + convert(VARCHAR(10), getdate(), 112) + '_' + right('0' + Datename(hh, getdate()), 2) + right('0' + Datename(mi, getdate()), 2) + '.ss''),
'
		FROM sys.master_files
		WHERE database_id = db_id()
			AND [type] = 0

	SET @Result = stuff(@Result, len(@Result) - 2, 1, '') --обрезаем последнюю запятую
	SET @Result += 'AS SNAPSHOT OF ' + quotename(db_name())

	--PRINT (@result)
	EXEC (@result)
END
добавлено: 19 окт 13 просмотры: 1040, комментарии: 1



Различия между системными представлениями SQL Server версий 2005 - 2012

Попал на один буржуйский блог, где нашел таблицу различий между системными представлениями SQL Server версий 2005 - 2012 с описанием: http://pawjershauge.blogspot.dk/2012/12/microsoft-sql-system-view-version-map.html .
Так же там оказался довольно полезный справочник хранимых процедур в алфавитном порядке: http://pawjershauge.blogspot.dk/2012/04/ms-sql-stored-procedure-metadata.html
добавлено: 16 май 13 просмотры: 1263, комментарии: 1



Список секционированных объектов SQL Server

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

--Список секционированных объектов
SELECT OBJECT_SCHEMA_NAME(i.object_id)+'.'+OBJECT_NAME(i.object_id) as ObjectName
	  , i.name as IndexNname
	  , i.type_desc as IndexType
	  , pf.fanout as PartitionsCount
      , STUFF((SELECT CAST((SELECT (SELECT ','+c.name
							from sys.index_columns as ic 
							INNER JOIN sys.columns as c on c.object_id = ic.object_id and c.column_id = ic.column_id
							WHERE ic.object_id = i.object_id and ic.index_id = i.index_id
							AND ic.partition_ordinal > 0
							order by ic.partition_ordinal
                     FOR XML PATH (''), Type 
                    ) AS SchemeCol 
                   ) AS nvarchar(MAX) 
       )),1,1,'') as PartitionColumns
	  ,'CREATE PARTITION FUNCTION ['+pf.name+'] ('+t.name + CASE WHEN pp.system_type_id in (167,175,231,239,256) THEN '('+CONVERT(nvarchar(10),pp.max_length)+')) ' ELSE +') ' END 
	   + 'AS '+pf.type_desc COLLATE Cyrillic_General_CI_AS + CASE pf.boundary_value_on_right WHEN 1 THEN ' RIGHT ' ELSE ' LEFT ' END + 'FOR VALUES ('
      + STUFF((SELECT CAST((SELECT (SELECT CASE WHEN pp.system_type_id in (40,41,42,43,58,61,167,175,231,239,256) THEN ',N'''+CONVERT(nvarchar(100),prv.value,120) + ''''
										 ELSE ','+CONVERT(nvarchar(100),prv.value)
									END 
                     FROM sys.partition_range_values AS prv 
					 INNER JOIN sys.partition_parameters as pp on prv.function_id = pp.function_id
                     WHERE pf.function_id = prv.function_id   
                     FOR XML PATH (''), Type 
                    ) AS FunCol 
                   ) AS nvarchar(MAX) 
       )),1,1,'') + ')' as PartitionFunction  
	  ,'CREATE PARTITION SCHEME ['+ps.name+'] AS PARTITION ['+pf.name+'] TO ('
      + STUFF((SELECT CAST((SELECT (SELECT ','+ds.name
							from sys.destination_data_spaces as dds 
							INNER JOIN sys.data_spaces as ds on dds.data_space_id = ds.data_space_id
							WHERE ps.data_space_id =  dds.partition_scheme_id
							order by ps.data_space_id, dds.destination_id
                     FOR XML PATH (''), Type 
                    ) AS SchemeCol 
                   ) AS nvarchar(MAX) 
       )),1,1,'') + ')' as PartitionScheme
FROM sys.partition_functions AS pf 
INNER JOIN sys.partition_parameters as pp ON pf.function_id = pp.function_id
INNER JOIN sys.types as t ON pp.system_type_id = t.system_type_id
INNER JOIN sys.partition_schemes as ps ON pf.function_id = ps.function_id
INNER JOIN sys.indexes as i ON ps.data_space_id = i.data_space_id
ORDER BY ObjectName;
добавлено: 14 дек 12 просмотры: 1305, комментарии: 0



Парочка плакатов по SQL Server 2012

добавлено: 03 июл 12 просмотры: 1274, комментарии: 0



Являются ли более узкие индексы лишними... или нет?!

В догонку к предыдущей записи блога, где я выкладывал скрипт поиска перекрывающихся индексов http://www.sql.ru/blogs/andraptor/1218, мне хотелось бы порассуждать, почему я считаю такие индексы лишними.
Итак, для примера берем табличку Production.WorkOrder из базы AdventureWorks2008R2.
Эта таблица содержит некластерный индекс IX_WorkOrder_ProductID по полю ProductID
1. Создаем еще 2-а индекса, где первым полем будет ProductID
CREATE NONCLUSTERED INDEX IX_ProdID_StartDate
	ON Production.WorkOrder (ProductID,StartDate)
GO
CREATE NONCLUSTERED INDEX IX_ProdID_StartDate_EndDate
	ON Production.WorkOrder (ProductID,StartDate,EndDate)

читать дальше...
добавлено: 07 мар 12 просмотры: 1796, комментарии: 3



Поиск перекрывающихся (лишних) индексов в SQL Server 2005+

В некоторых приложениях из-за несогласованности работы программистов возникают ситуации, когда создаются индексы в которых нет необходимости. Т.е. запросы могут использовать уже существующие индексы. Из-за этого возникают дополнительные издержки на их обслуживание. Таким образом, если поля индекса перекрываются более широким индексом в том же порядке следования полей начиная с первого поля, то этот индекс считается лишним, так как запросы могут использовать более широкий индекс.
Данный сценарий как раз ищет эти перекрывающиеся (лишние) индексы.
Для поиска всех индексов в базе данных я позаимствовал запрос из блога http://www.jjcoder.com/2011/12/how-to-get-all-table-indexes-with.html

Работоспособность тестировалась на SQL Server 2005. Но на более поздних версиях, скорее всего, тоже будет работать.
читать дальше...
добавлено: 07 мар 12 просмотры: 2115, комментарии: 1