Download Essentials-DMVs_tsql_dba

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
-- Essentials:
DMV's and T-SQL for the DBA
-- Physical environment information
-- Base info from SQL Server 2008
SELECT cpu_count AS 'logical_cpu', hyperthread_ratio, cpu_count/hyperthread_ratio As
'pysical_cpu',
physical_memory_in_bytes/1048576 AS 'physical_memory_MB', sqlserver_start_time
FROM sys.dm_os_sys_info
-- Base info from SQL Server 2005
SELECT cpu_count AS 'logical_cpu', hyperthread_ratio, cpu_count/hyperthread_ratio As
'pysical_cpu',
physical_memory_in_bytes/1048576 AS 'physical_memory_MB'
FROM sys.dm_os_sys_info
-- SQL Server 2008 Backup History
SELECT s.server_name,s.database_name, m.physical_device_name, cast(s.backup_size/1000000 as
varchar(14))+' '+'MB' as Size,
CAST(s.Compressed_backup_size/1000000 as varchar(14))+' '+'MB' as Compressed_Size,
CAST (DATEDIFF(MINUTE,s.backup_start_date , s.backup_finish_date)AS VARCHAR(4)) as
BackupDuration_Minutes, s.backup_start_date,
CASE s.[type]
WHEN 'D' THEN 'Full'
WHEN 'I' THEN 'Differential'
WHEN 'L' THEN 'Transaction Log'
END as BackupType, s.expiration_date, s.recovery_model
FROM msdb.dbo.backupset s
inner join msdb.dbo.backupmediafamily m
ON s.media_set_id = m.media_set_id where server_name = @@SERVERNAME
-- Memory
Specific to 2008
SELECT
physical_memory_in_use_kb / 1024.0 as Mem_MB_in_Use,
case process_physical_memory_low when 0 then 'NO' else 'YES' end as
Process_Mem_Physical_Low ,
case process_Virtual_memory_low when 0 then 'NO' else 'YES' end as
Process_Mem_Virtual_Low,
memory_utilization_percentage, locked_page_allocations_kb / 1024.0 as
Mem_LockedPage_alloc,
virtual_address_space_reserved_kb / 1024.0 / 1024.0 as Mem_GB_Virtual_Reserved,
virtual_address_space_committed_kb / 1024.0 as Mem_MB_Virtual_Committed,
page_fault_count,
available_commit_limit_kb / 1024.0 as Mem_MB_available
FROM
sys.dm_os_process_memory
SELECT SUM (pages_allocated_count * page_size_in_bytes) as 'Bytes Used', type
FROM sys.dm_os_memory_objects
GROUP BY type
ORDER BY 1 DESC;
-- SP_Who2 +++ For SQL Server 2005 / 2008
sp_who2
SELECT session_id as SPID, status, command, DB_NAME(database_id) as DatabaseName,
blocking_session_id, wait_resource, open_transaction_count,
cpu_time, reads, writes, logical_reads, row_count,
transaction_isolation_level, granted_query_memory, Percent_complete, reads, writes, text
from sys.dm_exec_requests CROSS APPLY
sys.dm_exec_sql_text(sql_handle)
order by logical_reads desc
-- New Window
--begin
--waitfor delay '00:99:50'
--select 1
--end
SELECT session_id as SPID, status, command, DB_NAME(database_id) as DatabaseName,
blocking_session_id, wait_resource, open_transaction_count,
cpu_time, reads, writes, logical_reads, row_count,
transaction_isolation_level, granted_query_memory, text
from sys.dm_exec_requests CROSS APPLY
sys.dm_exec_sql_text(sql_handle)
order by logical_reads desc
-- All columns available in the sys.dm_exec_requests table.
select TEXT, *
from sys.dm_exec_requests CROSS APPLY
sys.dm_exec_sql_text(sql_handle)
select * from sys.dm_exec_requests
-- Index Usage in SQL Server 2008
select db_name(database_id), * from Sys.dm_db_index_usage_stats
-- Index Usage.
Good or Bad?
-- Possible bad Indexes (writes > reads)
USE Performance_Data_Warehouse
GO
DECLARE @dbid int
SELECT @dbid = db_id()
SELECT 'Table Name' = object_name(s.object_id), 'Index Name' =i.name, i.index_id,
'Total Writes' = user_updates, 'Total Reads' = user_seeks + user_scans + user_lookups,
'Difference' = user_updates - (user_seeks + user_scans + user_lookups)
FROM sys.dm_db_index_usage_stats AS s INNER JOIN
sys.indexes AS i ON s.object_id = i.object_id AND i.index_id = s.index_id
WHERE objectproperty(s.object_id,'IsUserTable') = 1 and i.is_primary_key = 0
AND s.database_id = @dbid
AND user_updates > (user_seeks + user_scans + user_lookups)
-- commented out due to laptop environment
-AND s.user_seeks + user_scans + user_lookups < 150 and s.user_updates > 150
ORDER BY 'Difference' DESC, 'Total Writes' DESC, 'Total Reads' ASC;
-- Missing indexes for all tables
SELECT user_seeks * avg_total_user_cost * (avg_user_impact * 0.01) AS index_advantage,
migs.last_user_seek, mid.statement as 'Database.Schema.Table',
mid.equality_columns, mid.inequality_columns, mid.included_columns,
migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact
FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK)
INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK)
ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK)
ON mig.index_handle = mid.index_handle
-- commented out because I want to see all tables in all databases
-- WHERE statement = '[databasename].[dbo].[tablename]' -- Specify one table
-- commented out due to laptop environment
-- WHERE migs.user_seeks >= 20
ORDER BY index_advantage DESC;
-- Dynamically create those missing indexes
-- Dynamically Create Missing indexes for all tables -SELECT distinct ' CREATE NONCLUSTERED INDEX [' + 'nci_MissingIndex_' +
cast(mid.index_handle as varchar(22)) + '] ON ' + mid.statement +
'(' +
mid.equality_columns + ',' + ISNULL (mid.inequality_columns,'') +
')' +
' WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB =
ON, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = ON, MAXDOP = 2, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) -- ON [FileGroupName]'
FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK)
INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK)
ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK)
ON mig.index_handle = mid.index_handle
--WHERE statement = '[databasename].[dbo].[tablename]' -- Specify one table
WHERE --migs.user_seeks >= 50 and migs.avg_user_impact >= 50 and
included_columns is null
UNION
SELECT distinct ' CREATE NONCLUSTERED INDEX [' + 'nci_MissingIndex_' +
cast(mid.index_handle as varchar(22)) + '] ON ' + mid.statement +
'(' +
mid.equality_columns + ',' + ISNULL (mid.inequality_columns,'') +
')' +
'INCLUDE (' + mid.included_columns + ')' +
' WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB =
ON, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = ON, MAXDOP = 2, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) -- ON [FileGroupName]'
FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK)
INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK)
ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK)
ON mig.index_handle = mid.index_handle
-WHERE statement = '[databasename].[dbo].[tablename]' -- Specify one table
WHERE --migs.user_seeks >= 50 and migs.avg_user_impact >= 50 and
included_columns is NOT null
-- T-sql; good, bad? Let's find out
-- Cache
-- By Cache Object type and Object Type
SELECT cacheobjtype,objtype, sum(refcounts) as TotalRefcounts, sum(usecounts) as TotalUseCounts
FROM sys.dm_Exec_Cached_plans
GROUP BY cacheobjtype,objtype
-- UseCounts by Cache Object Type, Ojbect Type and specific SQL
SELECT SUM(cp.usecounts) AS TotalUseCounts, SUM(cp.refcounts) AS TotalReferencingOjbects,
cp.cacheobjtype, cp.objtype, st.text
FROM sys.dm_exec_cached_plans cp cross apply
sys.dm_exec_sql_text(cp.plan_handle) st
GROUP BY cacheobjtype, objtype, text
order by TotalUseCounts desc
--Cache
--Things to look for :
--Determine if the adhoc or dynamic statements are generating plans that are re-used, or in this
case, not being re-used.
-- Modify the left(text,50) -- essentially a way to "GROUP BY"
SELECT Count (*) as Count, refcounts, usecounts, objtype, left(text,50)
FROM sys.dm_Exec_cached_plans cross apply
sys.dm_exec_sql_text(plan_handle)
WHERE cacheobjtype = 'Compiled Plan' and objtype = 'Adhoc' --and usecounts = 1
GROUP BY refcounts, usecounts, objtype, left(text,50)
ORDER BY Count DESC
--Memory breakdown of all cached complied plans
SELECT pages_allocated_count, type, page_size_in_bytes, text,
plan_handle, ecp.memory_object_address AS CompiledPlan_MemoryObject,
omo.memory_object_address
FROM sys.dm_exec_cached_plans AS ecp cross apply
sys.dm_exec_sql_text(plan_handle) JOIN
sys.dm_os_memory_objects AS omo
ON ecp.memory_object_address = omo.memory_object_address
OR ecp.memory_object_address = omo.parent_address
WHERE cacheobjtype = 'Compiled Plan' order by page_size_in_bytes desc
-- SET Options
SELECT distinct pvt.set_options, pvt.sql_handle
FROM
( SELECT plan_handle, epa.attribute, epa.value
FROM sys.dm_exec_cached_plans OUTER APPLY
sys.dm_exec_plan_attributes(plan_handle) AS epa
WHERE cacheobjtype = 'Compiled Plan' ) AS ecpa
PIVOT (MAX(ecpa.value) FOR ecpa.attribute IN ("set_options", "sql_handle")) AS pvt;
-- Curious as to which set_options exist for a specific object or object type?
-- Based on plans in Cache
SELECT distinct epa.attribute, EPA.value, refcounts, usecounts, size_in_bytes, cacheobjtype,
objtype, left(text,75)
FROM sys.dm_exec_cached_plans
cross apply sys.dm_exec_sql_text(plan_handle)
OUTER APPLY
sys.dm_exec_plan_attributes(plan_handle) as EPA
WHERE attribute = 'set_options'
order by value desc
--
http://technet.microsoft.com/en-us/library/ms189472.aspx
-- TOP 50 Logical Reads
SELECT top 50 max_logical_reads, min_logical_reads, last_logical_reads, total_logical_reads,
execution_count,
substring(st.text, (qs.statement_start_offset/2) + 1,
((case statement_end_offset when -1 then datalength(st.text)
else qs.statement_end_offset end - qs.statement_start_offset)/2) + 1) as
statement_text , *
FROM sys.dm_exec_query_stats qs cross apply
sys.dm_exec_sql_text(qs.sql_handle) st
WHERE execution_count > 1 -- and dbid = 5
ORDER BY 1 desc
-- performance counters
select * from sys.dm_os_performance_counters where counter_name like 'cpu%'
-- Demo Data Collection Reports
-Run this ONCE on each server.
-Once it has been run on a server then run JUST the create trigger portion on EACH
database
-EXCEPT the ddlchangelog database.
USE [master]
GO
/****** Object: Database [DDL_ChangeLog]
Script Date: 07/15/2008 15:00:49 ******/
CREATE DATABASE [DDL_ChangeLog]
GO
use ddl_changelog
GO
create table DDLChangeLog (
DDLChangeLogID [int] IDENTITY(1,1) NOT NULL,
eventtype nvarchar(100),
objectname nvarchar(100),
objecttype nvarchar(100),
databasename nvarchar(100),
schemaname nvarchar(100),
SystemUser nvarchar(255),
AppName nvarchar(255),
HostName nvarchar(255),
tsql nvarchar(MAX),
createddate datetime,
CONSTRAINT [PK_DDL_Changelog] PRIMARY KEY CLUSTERED
(
DDLChangeLogID ASC
))
GO
/****** Object: DdlTrigger [trgLogDDLEvent]
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Script Date: 06/10/2008 09:50:57 ******/
CREATE TRIGGER [trgLogDDLEvent] ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
DECLARE @data XML
SET @data = EVENTDATA()
IF @data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)')
<> 'CREATE_STATISTICS'
INSERT INTO ddl_changelog..DDLChangeLog
(
EventType,
ObjectName,
ObjectType,
DatabaseName,
SchemaName,
SystemUser,
AppName,
HostName,
tsql ,
createddate
)
VALUES (
@data.value('(/EVENT_INSTANCE/EventType)[1]',
'nvarchar(100)'),
@data.value('(/EVENT_INSTANCE/ObjectName)[1]',
'nvarchar(100)'),
@data.value('(/EVENT_INSTANCE/ObjectType)[1]',
'nvarchar(100)'),
@data.value('(/EVENT_INSTANCE/DatabaseName)[1]',
'nvarchar(100)'),
@data.value('(/EVENT_INSTANCE/SchemaName)[1]',
'nvarchar(100)'),
system_user , app_name (),host_name(),
@data.value('(/EVENT_INSTANCE/TSQLCommand)[1]',
'nvarchar(max)') ,
getdate()
) ;
GO
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
ENABLE TRIGGER [trgLogDDLEvent] ON DATABASE
SELECT eventtype, objectname, objecttype, databasename, SystemUser,
HostName, tsql, createddate, AppName, schemaname
FROM DDL_ChangeLog..DDLChangeLog
------Plan Guides
use AdventureWorks;
go
-- Object Plan Guide
-- drop procedure Sales.GetSalesOrderByCountry
CREATE PROCEDURE Sales.GetSalesOrderByCountry (@Country_region nvarchar(60))
AS
BEGIN
SELECT *
FROM Sales.SalesOrderHeader AS h, Sales.Customer AS c,
Sales.SalesTerritory AS t
WHERE h.CustomerID = c.CustomerID
AND c.TerritoryID = t.TerritoryID
AND CountryRegionCode = @Country_region
END;
GO
-- Create an OBJECT plan guide
-- HINT - Optimize for Country_Region 'US'
sp_create_plan_guide
@name = N'Guide1',
@stmt = N'SELECT *FROM Sales.SalesOrderHeader AS h,
Sales.Customer AS c,
Sales.SalesTerritory AS t
WHERE h.CustomerID = c.CustomerID
AND c.TerritoryID = t.TerritoryID
AND CountryRegionCode = @Country_region',
@type = N'OBJECT',
@module_or_batch = N'Sales.GetSalesOrderByCountry',
@params = NULL,
@hints = N'OPTION (OPTIMIZE FOR (@Country_region = N''US''))'
-- @hints || base this on selectivity of the data "US" is good because it will be representative
of rougly 2/3rds
-of the depth in the index / heap
--- Where do the created plans exist?
select * from sys.plan_guides -- (notice the HINTS column)
GO
--Disable the plan guide.
EXEC sp_control_plan_guide N'DISABLE', N'Guide1';
GO
select * from sys.plan_guides
-- Now shows as disabled
--Enable the plan guide.
EXEC sp_control_plan_guide N'ENABLE', N'Guide1';
GO
select * from sys.plan_guides
-- Now shows as enabled
--Drop the plan guide.
EXEC sp_control_plan_guide N'DROP', N'Guide8';
GO
select * from sys.plan_guides
-- Now it's gone
-- Disable ALL plan guides.
EXEC sp_control_plan_guide N'DISABLE ALL';
GO
-- SQL Plan Guide
-- Example: Set the Maxdop (Degree of parallelism = 1
EXEC sp_create_plan_guide
@name = N'Guide1',
@stmt = N'SELECT TOP 1 *
FROM Sales.SalesOrderHeader
ORDER BY OrderDate DESC',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (MAXDOP 1)';
GO
-- NOTE ** any Option clause in a select statement will work with the @hints parameter.
-- Template Plan Guide
-- Let's Force the parameterization on this statement.
DECLARE @stmt nvarchar(max);
DECLARE @params nvarchar(max);
EXEC sp_get_query_template
N'SELECT * FROM AdventureWorks2008.Sales.SalesOrderHeader AS h
INNER JOIN AdventureWorks2008.Sales.SalesOrderDetail AS d
ON h.SalesOrderID = d.SalesOrderID
WHERE h.SalesOrderID = 45639;',
@stmt OUTPUT,
@params OUTPUT
EXEC sp_create_plan_guide N'TemplateGuide1',
@stmt,
N'TEMPLATE',
NULL,
@params,
N'OPTION(PARAMETERIZATION FORCED)';
GO
-- NOTE: This forces the query to be parameterized and then a guide can be created against it.
-- Create a plan guide for the query by specifying the query plan in the plan cache via the plan
handle.
USE AdventureWorks;
GO
SELECT WorkOrderID, p.Name, OrderQty, DueDate
FROM Production.WorkOrder AS w
JOIN Production.Product AS p ON w.ProductID = p.ProductID
WHERE p.ProductSubcategoryID > 4
ORDER BY p.Name, DueDate;
GO
-- Inspect the query plan by using dynamic management views.
SELECT * FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(sql_handle)
CROSS APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset,
qs.statement_end_offset) AS qp
WHERE text LIKE N'SELECT WorkOrderID, p.Name, OrderQty, DueDate%';
GO -- Create a plan guide for the query by specifying the query plan in the plan cache via the
plan handle.
DECLARE @plan_handle varbinary(64);
DECLARE @offset int;
SELECT @plan_handle = plan_handle, @offset = qs.statement_start_offset
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS st
CROSS APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset,
qs.statement_end_offset) AS qp
WHERE text LIKE N'SELECT WorkOrderID, p.Name, OrderQty, DueDate%';
EXECUTE sp_create_plan_guide_from_handle
@name = N'Guide8',
@plan_handle = @plan_handle,
@statement_start_offset = @offset;
GO
-- Reference the previous example of ..... "Means that there are 4811 plans for three nearly
identical statements"
-- With this, a plan can be created against that string....
'SELECT WorkOrderID, p.Name,
OrderQty, DueDate%'
-- This is HUGE!!!
c.o.t.s implementations, dynamically built sql etc...
-- Checks the Validity of the plan guides in the system.
-- An empty result set means that all plan guides are valid.
USE AdventureWorks;
GO
SELECT plan_guide_id, msgnum, severity, state, message
FROM sys.plan_guides
CROSS APPLY fn_validate_plan_guide(plan_guide_id);
GO
-- Select statement taken from SQL Profiler
-- show execution plan.
SELECT COUNT(*) AS c
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d
ON h.SalesOrderID = d.SalesOrderID
WHERE h.OrderDate BETWEEN '20000101' and '20050101';
-GO
-- Show execution plan
-- ** Note the Hash Match Inner Join
-- Let's make it a Merge Join
EXEC sp_create_plan_guide
@name = N'MyGuideProfiler1',
@stmt = N' SELECT COUNT(*) AS c
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d
ON h.SalesOrderID = d.SalesOrderID
WHERE h.OrderDate BETWEEN ''20000101'' and ''20050101'';
',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (MERGE JOIN)';
-- Spacing is critical on this.
-- Check the statement to ensure that the planguide will force a merge join
SELECT COUNT(*) AS c
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d
ON h.SalesOrderID = d.SalesOrderID
WHERE h.OrderDate BETWEEN '20000101' and '20050101';
--Drop the plan guide. (if
EXEC sp_control_plan_guide
EXEC sp_control_plan_guide
EXEC sp_control_plan_guide
needed)
N'DROP', N'MyGuideProfiler1';
N'DROP', N'TemplateGuide1';
N'DROP', N'Guide1';
Related documents