User Tools

Site Tools


mssql

MSSQL

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

-------------------------------------------
-- НАСТРАИВАЕМЫЕ ПЕРЕМЕННЫЕ
-- База данных для анализа
USE WorkBase 
 
-------------------------------------------
-- ТЕЛО СКРИПТА
 
-- Отбираем объекты, которые:
--	являются индексами (index_id > 0)
--	фрагментация которых более 5% 
--	количество страниц в индексе более 128
SELECT
	OBJECT_NAME(object_id) AS TableName, 
	object_id,
	index_id,
	partition_number,
	page_count, 
	partition_number, 
	index_type_desc,
	avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED')
WHERE index_id > 0 
	AND avg_fragmentation_in_percent > 5.0
	AND page_count > 128
ORDER BY avg_fragmentation_in_percent DESC
 
GO

Скрипт для обслуживания индексов указанной базы данных. Скрипт подходит лоя версий MS SQL 2008, 2012, 2016:

-------------------------------------------
-- НАСТРАИВАЕМЫЕ ПАРАМЕТРЫ
-- База данных для анализа
USE WorkBase
 
-------------------------------------------
-- СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ 
DECLARE @object_id int; -- ID объекта
DECLARE @index_id int; -- ID индекса
DECLARE @partition_number bigint; -- количество секций если индекс секционирован
DECLARE @schemaname nvarchar(130); -- имя схемы в которой находится таблица
DECLARE @objectname nvarchar(130); -- имя таблицы 
DECLARE @indexname nvarchar(130); -- имя индекса
DECLARE @partitionnum bigint; -- номер секции
DECLARE @fragmentation_in_percent float; -- процент фрагментации индекса
DECLARE @command nvarchar(4000); -- инструкция T-SQL для дефрагментации либо ренидексации
 
-------------------------------------------
-- ТЕЛО СКРИПТА
 
-- Отключаем вывод количества возвращаемых строк, это несколько ускорит обработку
SET NOCOUNT ON;
 
-- Удалим временные таблицы, если вдруг они есть
IF OBJECT_ID('tempdb.dbo.#work_to_do') IS NOT NULL DROP TABLE #work_to_do
 
-- Отбор таблиц и индексов с помощью системного представления sys.dm_db_index_physical_stats
-- Отбор только тех объектов которые:
--	являются индексами (index_id > 0)
--	фрагментация которых более 5% 
--	количество страниц в индексе более 128 
SELECT
    object_id,
    index_id,
    partition_number,
    avg_fragmentation_in_percent AS fragmentation_in_percent
INTO #work_to_do
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED')
WHERE index_id > 0 
	AND avg_fragmentation_in_percent > 5.0
	AND page_count > 128;
 
-- Объявление Открытие курсора курсора для чтения секций
DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do;
OPEN partitions;
 
-- Цикл по секциям
FETCH NEXT FROM partitions INTO @object_id, @index_id, @partition_number, @fragmentation_in_percent;
WHILE @@FETCH_STATUS = 0
    BEGIN		
 
	-- Собираем имена объектов по ID		
        SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name)
        FROM sys.objects AS o
		JOIN sys.schemas as s ON s.schema_id = o.schema_id
        WHERE o.object_id = @object_id;
 
	SELECT @indexname = QUOTENAME(name)
        FROM sys.indexes
        WHERE  object_id = @object_id AND index_id = @index_id;
 
	SELECT @partition_number = count (*)
        FROM sys.partitions
        WHERE object_id = @object_id AND index_id = @index_id;
 
	-- Если фрагментация менее или равна 30% тогда дефрагментация, иначе реиндексация
        IF @fragmentation_in_percent < 30.0
            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';
        IF @fragmentation_in_percent >= 30.0
            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';
        IF @partition_number > 1
            SET @command = @command + N' PARTITION=' + CAST(@partition_number AS nvarchar(10));
 
	-- Выполняем команду				
        EXEC (@command);
	PRINT N'Index: object_id=' + STR(@object_id) + ', index_id=' + STR(@index_id) + ', fragmentation_in_percent=' + STR(@fragmentation_in_percent);
        PRINT N'Executed: ' + @command;
 
	-- Следующий элемент цикла
	FETCH NEXT FROM partitions INTO @object_id, @index_id, @partition_number, @fragmentation_in_percent;
 
	END;
 
-- Закрытие курсора
CLOSE partitions;
DEALLOCATE partitions;
 
-- Удаление временной таблицы
DROP TABLE #work_to_do;
 
GO

Скрипт для обслуживания индексов нескольких баз данных (по определенному условию):

---------------------------------------------
-- НАСТРАИВАЕМЫЕ ПАРАМЕТРЫ
-- Условие для выборки, '%' - все базы данных 
DECLARE @namelike VARCHAR(100) = 'WorkBase%'
-- Имя почтового профиля, для отправки электонной почты									
DECLARE @profilename AS nvarchar(100) = 'ОсновнойПрофиль'
-- Получатели сообщений электронной почты, разделенные знаком ";"				
DECLARE @recipients AS nvarchar(500) = 'admin@mydomen.com'
 
-------------------------------------------
-- СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ 
DECLARE @database_id VARCHAR(100) -- ID баз данных
DECLARE @database_name VARCHAR(100) -- Имена баз данных
DECLARE @command nvarchar(4000); -- инструкция T-SQL для дефрагментации либо ренидексации
DECLARE @subject AS NVARCHAR(1000) = '' -- тема сообщения
DECLARE @finalmassage AS NVARCHAR(4000) = '' -- текст сообщения
 
-------------------------------------------
-- ТЕЛО СКРИПТА
USE master
 
-- Отключаем вывод количества возвращаемых строк, это несколько ускорит обработку
SET NOCOUNT ON;
 
-- Выбираем базы данных
DECLARE DBcursor CURSOR FOR 
(
	SELECT 
		database_id AS database_id,
		name AS database_name
	FROM sys.databases d
	WHERE 
		d.name <> 'tempdb'
		AND d.name <> 'master'
		AND d.name <> 'model'
		AND d.name <> 'msdb'
		AND d.state_desc = 'ONLINE' -- база должна быть в сети 
		AND d.name LIKE @namelike -- база должна содержать указанное слово   
)
 
-- Цикл по всем базам, попавшим в выборку
OPEN DBcursor
FETCH NEXT FROM DBcursor INTO @database_id, @database_name
WHILE @@FETCH_STATUS = 0
	BEGIN
 
	-- База данных из цикла
	PRINT N'----------------------------------------------------------'
	PRINT N'USE [' + @database_name + N']'
	SET @command = 
	N'USE [' + @database_name + N']
 
	DECLARE @object_id int; -- ID объекта
	DECLARE @index_id int; -- ID индекса
	DECLARE @partition_number bigint; -- количество секций если индекс секционирован
	DECLARE @schemaname nvarchar(130); -- имя схемы в которой находится таблица
	DECLARE @objectname nvarchar(130); -- имя таблицы 
	DECLARE @indexname nvarchar(130); -- имя индекса
	DECLARE @partitionnum bigint; -- номер секции
	DECLARE @fragmentation_in_percent float; -- процент фрагментации индекса
	DECLARE @command nvarchar(4000); -- инструкция T-SQL для дефрагментации либо ренидексации
 
	-- Отбор таблиц и индексов с помощью системного представления sys.dm_db_index_physical_stats
	-- Отбор только тех объектов которые:
	--	 являются индексами (index_id > 0)
	--   фрагментация которых более 5% 
	--   количество страниц в индексе более 128 
	SELECT
		object_id,
		index_id,
		partition_number,
		avg_fragmentation_in_percent AS fragmentation_in_percent
	INTO #work_to_do
	FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, ''LIMITED'')
	WHERE index_id > 0 
		AND avg_fragmentation_in_percent > 5.0
		AND page_count > 128;
 
	-- Объявление Открытие курсора курсора для чтения секций
	DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do;
	OPEN partitions;
 
	-- Цикл по секциям
	FETCH NEXT FROM partitions INTO @object_id, @index_id, @partition_number, @fragmentation_in_percent;
	WHILE @@FETCH_STATUS = 0
		BEGIN
 
			-- Собираем имена объектов по ID		
			SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name)
			FROM sys.objects AS o
				JOIN sys.schemas as s ON s.schema_id = o.schema_id
			WHERE o.object_id = @object_id;
 
			SELECT @indexname = QUOTENAME(name)
			FROM sys.indexes
			WHERE object_id = @object_id AND index_id = @index_id;
 
			SELECT @partition_number = count (*)
			FROM sys.partitions
			WHERE object_id = @object_id AND index_id = @index_id;
 
			-- Если фрагментация менее или равна 30% тогда дефрагментация, иначе реиндексация
			IF @fragmentation_in_percent < 30.0
				SET @command = N''ALTER INDEX '' + @indexname + N'' ON '' + @schemaname + N''.'' + @objectname + N'' REORGANIZE'';
			IF @fragmentation_in_percent >= 30.0
				SET @command = N''ALTER INDEX '' + @indexname + N'' ON '' + @schemaname + N''.'' + @objectname + N'' REBUILD'';
			IF @partition_number > 1
				SET @command = @command + N'' PARTITION='' + CAST(@partition_number AS nvarchar(10));
 
			-- Выполняем команду				
			PRINT N''    Executed: '' + @command;
			EXEC sp_executesql @command			
 
			-- Следующий элемент цикла
			FETCH NEXT FROM partitions INTO @object_id, @index_id, @partition_number, @fragmentation_in_percent;
 
		END;
 
	-- Закрытие курсора
	CLOSE partitions;
	DEALLOCATE partitions;
 
	-- Удаление временной таблицы
	DROP TABLE #work_to_do;';
	BEGIN TRY
		EXEC sp_executesql @command	
		SET @finalmassage = @finalmassage + 'Успешное выполнение операций обслуживания индексов для базы данных ' + @database_name + CHAR(13) + CHAR(13)
	END TRY
	BEGIN CATCH  
		-- Ошбика выполнения операции
		SET @subject = 'БЫЛИ ОШИБКИ при выполнении операций обслуживания индексов '
		SET @finalmassage = @finalmassage + 'ОШИБКА обслуживания индекса для базы данных ' + @database_name + CHAR(13) + CHAR(13)
			+ 'Код ошибки: ' + CAST(ERROR_NUMBER() AS nvarchar(10)) + CHAR(13) + CHAR(13)
			+ 'Текст ошибки: ' + ERROR_MESSAGE()  + CHAR(13) + CHAR(13)
			+ 'Текст T-SQL: ' + CHAR(13) + @command + CHAR(13) + CHAR(13)  
	END CATCH;
 
	-- Следующая база данных
	FETCH NEXT FROM DBcursor INTO @database_id, @database_name
	END;
 
CLOSE DBcursor;
DEALLOCATE DBcursor;
 
-- Формируем сообщение об успешном или не успешном выполнении операций
IF @subject = ''
BEGIN
	-- Успешное выполнение всех операций
	SET @subject = 'Успешное выполнение операций обслуживания индексов '
END
 
-- Если задан профиль электронной почты, отправим сообщение
PRINT N'----------------------------------------------------------'
IF @profilename <> ''
EXEC msdb.dbo.sp_send_dbmail
    @profile_name = @profilename,
    @recipients = @recipients,
    @body = @finalmassage,
    @subject = @subject;
 
-- Выводим сообщение о результате
SELECT
	@subject AS subject, 
	@finalmassage AS finalmassage 
 
GO

Как найти самые большие таблицы в базе данных MS SQL

USE [databasename]
GO
CREATE TABLE #temp (
TABLE_NAME sysname ,
ROW_COUNT INT,
reserved_size VARCHAR(50),
data_size VARCHAR(50),
index_size VARCHAR(50),
unused_size VARCHAR(50))
SET NOCOUNT ON
INSERT #temp
EXEC sp_msforeachtable 'sp_spaceused ''?'''
SELECT a.table_name,
a.row_count,
COUNT(*) AS col_count,
a.data_size
FROM #temp a
INNER JOIN information_schema.columns b
ON a.table_name COLLATE database_default
= b.table_name COLLATE database_default
GROUP BY a.table_name, a.row_count, a.data_size
ORDER BY CAST(REPLACE(a.data_size, ' KB', '') AS INTEGER) DESC
DROP TABLE #temp
mssql.txt · Last modified: 2023/04/06 10:28 (external edit)