非常全面的SQL Server巡检脚本来自sqlskills团队的Glenn Berry

Glenn Berry 曾承诺对这个脚本持续更新

  1. -- SQL Server 2012 Diagnostic Information Queries
  2. -- Glenn Berry
  3. -- April 2015
  4. -- Last Modified: April 27, 2015
  5. -- http://sqlserverperformance.wordpress.com/
  6. -- http://sqlskills.com/blogs/glenn/
  7. -- Twitter: GlennAlanBerry
  8.  
  9. -- Please listen to my Pluralsight courses
  10. -- http://www.pluralsight.com/author/glenn-berry
  11.  
  12. -- Many of these queries will not work if you have databases in 80 compatibility mode
  13. -- Please make sure you are using the correct version of these diagnostic queries for your version of SQL Server
  14.  
  15. --******************************************************************************
  16. --* Copyright (C) 2015 Glenn Berry, SQLskills.com
  17. --* All rights reserved.
  18. --*
  19. --* For more scripts and sample code, check out
  20. --* http://sqlskills.com/blogs/glenn
  21. --*
  22. --* You may alter this code for your own *non-commercial* purposes. You may
  23. --* republish altered code as long as you include this copyright and give due credit.
  24. --*
  25. --*
  26. --* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
  27. --* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  28. --* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  29. --* PARTICULAR PURPOSE.
  30. --*
  31. --******************************************************************************
  32.  
  33. -- Check the major product version to see if it is SQL Server 2012
  34. IF NOT EXISTS (SELECT * WHERE CONVERT(varchar(128), SERVERPROPERTY('ProductVersion')) LIKE '11%')
  35. BEGIN
  36. DECLARE @ProductVersion varchar(128) = CONVERT(varchar(128), SERVERPROPERTY('ProductVersion'));
  37. RAISERROR ('Script does not match the ProductVersion [%s] of this instance. Many of these queries may not work on this version.' , 18 , 16 , @ProductVersion);
  38. END
  39. ELSE
  40. PRINT N'You have the correct major version of SQL Server for this diagnostic information script';
  41.  
  42. -- Instance level queries *******************************
  43.  
  44. -- SQL and OS Version information for current instance (Query 1) (Version Info)
  45. SELECT @@SERVERNAME AS [Server Name], @@VERSION AS [SQL Server and OS Version Info];
  46.  
  47. -- SQL Server 2012 RTM Branch Builds SQL Server 2012 SP1 Branch Builds SQL Server 2012 SP2 Branch Builds
  48. -- Build Description Release Date Build Description Release Date Build Description Release Date
  49. -- 11.0.2100 RTM 3/6/2012
  50. -- 11.0.2316 RTM CU1 4/12/2012
  51. -- 11.0.2325 RTM CU2 6/18/2012 --> 11.0.3000 SP1 RTM 11/7/2012
  52. -- 11.0.2332 RTM CU3 8/31/2012
  53. -- 11.0.2376 RTM CU3 + QFE 10/9/2012
  54. -- 11.0.2383 RTM CU4 10/15/2012 --> 11.0.3321 SP1 CU1 11/20/2012
  55. -- 11.0.2395 RTM CU5 12/17/2012 --> 11.0.3339 SP1 CU2 1/21/2013
  56. -- 11.0.2401 RTM CU6 2/18/2013 --> 11.0.3349 SP1 CU3 3/18/2013
  57. -- 11.0.2405 RTM CU7 4/15/2013 --> 11.0 3368 SP1 CU4 5/30/2013
  58. -- 11.0.2410 RTM CU8 6/17/2013 --> 11.0.3373 SP1 CU5 7/15/2013
  59. -- 11.0.2419 RTM CU9 8/20/2013 --> 11.0.3381 SP1 CU6 9/16/2013
  60. -- 11.0.2420 RTM CU10 10/21/2013 --> 11.0.3393 SP1 CU7 11/18/2013
  61. -- 11.0.2424 RTM CU11 12/16/2003 --> 11.0.3401 SP1 CU8 1/20/2014
  62. -- 11.0.3412 SP1 CU9 3/17/2014 --> 11.0.5058 SP2 RTM 6/10/2014
  63. -- 11.0.3431 SP1 CU10 5/19/2014
  64. -- 11.0.3449 SP1 CU11 7/21/2014 --> 11.0.5532 SP2 CU1 7/23/2014
  65. -- 11.0.3470 SP1 CU12 9/15/2014 --> 11.0.5548 SP2 CU2 9/15/2014
  66. -- 11.0.3482 SP1 CU13 11/17/2014--> 11.0.5556 SP2 CU3 11/17/2014
  67. -- 11.0.3486 SP1 CU14 1/19/2015 --> 11.0.5569 SP2 CU4 1/19/2015
  68. -- 11.0.5571 SP2 CU4 + COD HF 2/4/2015 (this includes the AlwaysOn AG hotfix that is in SP2 CU5)
  69. -- 11.0.3487 SP1 CU15 3/16/2015 11.0.5582 SP2 CU5 3/16/2015
  70.  
  71. -- The SQL Server 2012 builds that were released after SQL Server 2012 was released
  72. -- http://support.microsoft.com/kb/2692828
  73.  
  74. -- The SQL Server 2012 builds that were released after SQL Server 2012 Service Pack 1 was released
  75. -- http://support.microsoft.com/kb/2772858
  76.  
  77. -- SQL Server 2012 SP2 build versions (new format for the build list KB article)
  78. -- http://support.microsoft.com/kb/2983249
  79.  
  80. -- Recommended updates and configuration options for SQL Server 2012 and SQL Server 2014 used with high-performance workloads
  81. -- http://support.microsoft.com/kb/2964518/EN-US
  82.  
  83. -- Performance and Stability Related Fixes in Post-SQL Server 2012 SP2 Builds
  84. -- http://www.sqlskills.com/blogs/glenn/performance-and-stability-related-fixes-in-post-sql-server-2012-sp2-builds/
  85.  
  86. -- When was SQL Server installed (Query 2) (SQL Server Install Date)
  87. SELECT @@SERVERNAME AS [Server Name], create_date AS [SQL Server Install Date]
  88. FROM sys.server_principals WITH (NOLOCK)
  89. WHERE name = N'NT AUTHORITY\SYSTEM'
  90. OR name = N'NT AUTHORITY\NETWORK SERVICE' OPTION (RECOMPILE);
  91.  
  92. -- Tells you the date and time that SQL Server was installed
  93. -- It is a good idea to know how old your instance is
  94.  
  95. -- Get selected server properties (SQL Server 2012) (Query 3) (Server Properties)
  96. SELECT SERVERPROPERTY('MachineName') AS [MachineName], SERVERPROPERTY('ServerName') AS [ServerName],
  97. SERVERPROPERTY('InstanceName') AS [Instance], SERVERPROPERTY('IsClustered') AS [IsClustered],
  98. SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS [ComputerNamePhysicalNetBIOS],
  99. SERVERPROPERTY('Edition') AS [Edition], SERVERPROPERTY('ProductLevel') AS [ProductLevel],
  100. SERVERPROPERTY('ProductVersion') AS [ProductVersion], SERVERPROPERTY('ProcessID') AS [ProcessID],
  101. SERVERPROPERTY('Collation') AS [Collation], SERVERPROPERTY('IsFullTextInstalled') AS [IsFullTextInstalled],
  102. SERVERPROPERTY('IsIntegratedSecurityOnly') AS [IsIntegratedSecurityOnly],
  103. SERVERPROPERTY('IsHadrEnabled') AS [IsHadrEnabled], SERVERPROPERTY('HadrManagerStatus') AS [HadrManagerStatus];
  104.  
  105. -- This gives you a lot of useful information about your instance of SQL Server,
  106. -- such as the ProcessID for SQL Server and your collation
  107. -- The last two columns are new for SQL Server 2012
  108.  
  109. -- Get SQL Server Agent jobs and Category information (Query 4) (SQL Server Agent Jobs)
  110. SELECT sj.name AS [JobName], sj.[description] AS [JobDescription], SUSER_SNAME(sj.owner_sid) AS [JobOwner],
  111. sj.date_created, sj.[enabled], sj.notify_email_operator_id, sj.notify_level_email, sc.name AS [CategoryName],
  112. js.next_run_date, js.next_run_time
  113. FROM msdb.dbo.sysjobs AS sj WITH (NOLOCK)
  114. INNER JOIN msdb.dbo.syscategories AS sc WITH (NOLOCK)
  115. ON sj.category_id = sc.category_id
  116. LEFT OUTER JOIN msdb.dbo.sysjobschedules AS js WITH (NOLOCK)
  117. ON sj.job_id = js.job_id
  118. ORDER BY sj.name OPTION (RECOMPILE);
  119.  
  120. -- Gives you some basic information about your SQL Server Agent jobs, who owns them and how they are configured
  121. -- Look for Agent jobs that are not owned by sa
  122. -- Look for jobs that have a notify_email_operator_id set to 0 (meaning no operator)
  123. -- Look for jobs that have a notify_level_email set to 0 (meaning no e-mail is ever sent)
  124. --
  125. -- MSDN sysjobs documentation
  126. -- http://msdn.microsoft.com/en-us/library/ms189817.aspx
  127.  
  128. -- Get SQL Server Agent Alert Information (Query 5) (SQL Server Agent Alerts)
  129. SELECT name, event_source, message_id, severity, [enabled], has_notification,
  130. delay_between_responses, occurrence_count, last_occurrence_date, last_occurrence_time
  131. FROM msdb.dbo.sysalerts WITH (NOLOCK)
  132. ORDER BY name OPTION (RECOMPILE);
  133.  
  134. -- Gives you some basic information about your SQL Server Agent Alerts (which are different from SQL Server Agent jobs)
  135. -- Read more about Agent Alerts here: http://www.sqlskills.com/blogs/glenn/creating-sql-server-agent-alerts-for-critical-errors/
  136.  
  137. -- Returns a list of all global trace flags that are enabled (Query 6) (Global Trace Flags)
  138. DBCC TRACESTATUS (-1);
  139.  
  140. -- If no global trace flags are enabled, no results will be returned.
  141. -- It is very useful to know what global trace flags are currently enabled as part of the diagnostic process.
  142.  
  143. -- Common trace flags that should be enabled in most cases
  144. -- TF 3226 - Supresses logging of successful database backup messages to the SQL Server Error Log
  145. -- TF 1118 - Helps alleviate allocation contention in tempdb, SQL Server allocates full extents to each database object,
  146. -- thereby eliminating the contention on SGAM pages (more important with older versions of SQL Server)
  147. -- Recommendations to reduce allocation contention in SQL Server tempdb database
  148. -- http://support2.microsoft.com/kb/2154845
  149.  
  150. -- Windows information (SQL Server 2012) (Query 7) (Windows Info)
  151. SELECT windows_release, windows_service_pack_level,
  152. windows_sku, os_language_version
  153. FROM sys.dm_os_windows_info WITH (NOLOCK) OPTION (RECOMPILE);
  154.  
  155. -- Gives you major OS version, Service Pack, Edition, and language info for the operating system
  156. -- 6.3 is either Windows 8.1 or Windows Server 2012 R2
  157. -- 6.2 is either Windows 8 or Windows Server 2012
  158. -- 6.1 is either Windows 7 or Windows Server 2008 R2
  159. -- 6.0 is either Windows Vista or Windows Server 2008
  160.  
  161. -- Windows SKU codes
  162. -- 4 is Enterprise Edition
  163. -- 7 is Standard Server Edition
  164. -- 8 is Datacenter Server Edition
  165. -- 10 is Enterprise Server Edition
  166. -- 48 is Professional Edition
  167.  
  168. -- 1033 for os_language_version is US-English
  169.  
  170. -- SQL Server 2012 requires Windows Server 2008 SP2 or newer
  171.  
  172. -- Hardware and Software Requirements for Installing SQL Server 2012
  173. -- http://msdn.microsoft.com/en-us/library/ms143506.aspx
  174.  
  175. -- Using SQL Server in Windows 8, Windows 8.1, Windows Server 2012 and Windows Server 2012 R2 environments
  176. -- http://support.microsoft.com/kb/2681562
  177.  
  178. -- SQL Server Services information (SQL Server 2012) (Query 8) (SQL Server Services Info)
  179. SELECT servicename, process_id, startup_type_desc, status_desc,
  180. last_startup_time, service_account, is_clustered, cluster_nodename, [filename]
  181. FROM sys.dm_server_services WITH (NOLOCK) OPTION (RECOMPILE);
  182.  
  183. -- Tells you the account being used for the SQL Server Service and the SQL Agent Service
  184. -- Shows the processid, when they were last started, and their current status
  185. -- Shows whether you are running on a failover cluster instance
  186.  
  187. -- SQL Server NUMA Node information (Query 9) (SQL Server NUMA Info)
  188. SELECT node_id, node_state_desc, memory_node_id, processor_group, online_scheduler_count,
  189. active_worker_count, avg_load_balance, resource_monitor_state
  190. FROM sys.dm_os_nodes WITH (NOLOCK)
  191. WHERE node_state_desc <> N'ONLINE DAC' OPTION (RECOMPILE);
  192.  
  193. -- Gives you some useful information about the composition and relative load on your NUMA nodes
  194. -- You want to see an equal number of schedulers on each NUMA node
  195.  
  196. -- Hardware information from SQL Server 2012 (Query 10) (Hardware Info)
  197. -- (Cannot distinguish between HT and multi-core)
  198. SELECT cpu_count AS [Logical CPU Count], scheduler_count, hyperthread_ratio AS [Hyperthread Ratio],
  199. cpu_count/hyperthread_ratio AS [Physical CPU Count],
  200. physical_memory_kb/1024 AS [Physical Memory (MB)], committed_kb/1024 AS [Committed Memory (MB)],
  201. committed_target_kb/1024 AS [Committed Target Memory (MB)],
  202. max_workers_count AS [Max Workers Count], affinity_type_desc AS [Affinity Type],
  203. sqlserver_start_time AS [SQL Server Start Time], virtual_machine_type_desc AS [Virtual Machine Type]
  204. FROM sys.dm_os_sys_info WITH (NOLOCK) OPTION (RECOMPILE);
  205.  
  206. -- Gives you some good basic hardware information about your database server
  207. -- Note: virtual_machine_type_desc of HYPERVISOR does not automatically mean you are running SQL Server inside of a VM
  208. -- It merely indicates that you have a hypervisor running on your host
  209.  
  210. -- Get System Manufacturer and model number from (Query 11) (System Manufacturer)
  211. -- SQL Server Error log. This query might take a few seconds
  212. -- if you have not recycled your error log recently
  213. EXEC sys.xp_readerrorlog 0, 1, N'Manufacturer';
  214.  
  215. -- This can help you determine the capabilities
  216. -- and capacities of your database server
  217.  
  218. -- Get socket, physical core and logical core count from (Query 12) (Core Counts)
  219. -- SQL Server Error log. This query might take a few seconds
  220. -- if you have not recycled your error log recently
  221. EXEC sys.xp_readerrorlog 0, 1, N'detected', N'socket';
  222.  
  223. -- This can help you determine the exact core counts used by SQL Server and whether HT is enabled or not
  224. -- It can also help you confirm your SQL Server licensing model
  225. -- Be on the lookout for this message "using 20 logical processors based on SQL Server licensing" which means grandfathered Server/CAL licensing
  226. -- Note: If you recycle your error logs frequently and your instance has been running long enough,
  227. -- this query may not return any results, since the original startup information from the first error log
  228. -- when SQL Server was last started will have been overwritten
  229.  
  230. -- Get processor description from Windows Registry (Query 13) (Processor Description)
  231. EXEC sys.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'HARDWARE\DESCRIPTION\System\CentralProcessor\0', N'ProcessorNameString';
  232.  
  233. -- Gives you the model number and rated clock speed of your processor(s)
  234. -- Your processors may be running at less that the rated clock speed due
  235. -- to the Windows Power Plan or hardware power management
  236.  
  237. -- You can skip the next four queries if you know you don't
  238. -- have a clustered instance
  239.  
  240. -- Shows you where the SQL Server failover cluster diagnostic log is located and how it is configured (Query 14) (SQL Server Error Log)
  241. SELECT is_enabled, [path], max_size, max_files
  242. FROM sys.dm_os_server_diagnostics_log_configurations WITH (NOLOCK) OPTION (RECOMPILE);
  243.  
  244. -- Knowing this information is important for troubleshooting purposes
  245. -- Also shows you the location of other error and diagnostic log files
  246.  
  247. -- Get information about your OS cluster (if your database server is in a cluster) (Query 15) (Cluster Properties)
  248. SELECT VerboseLogging, SqlDumperDumpFlags, SqlDumperDumpPath,
  249. SqlDumperDumpTimeOut, FailureConditionLevel, HealthCheckTimeout
  250. FROM sys.dm_os_cluster_properties WITH (NOLOCK) OPTION (RECOMPILE);
  251.  
  252. -- You will see no results if your instance is not clustered
  253.  
  254. -- Get information about your cluster nodes and their status (Query 16) (Cluster Node Properties)
  255. -- (if your database server is in a failover cluster)
  256. SELECT NodeName, status_description, is_current_owner
  257. FROM sys.dm_os_cluster_nodes WITH (NOLOCK) OPTION (RECOMPILE);
  258.  
  259. -- Knowing which node owns the cluster resources is critical
  260. -- Especially when you are installing Windows or SQL Server updates
  261. -- You will see no results if your instance is not clustered
  262.  
  263. -- Get information about any AlwaysOn AG cluster this instance is a part of (Query 17) (AlwaysOn AG Cluster)
  264. SELECT cluster_name, quorum_type_desc, quorum_state_desc
  265. FROM sys.dm_hadr_cluster WITH (NOLOCK) OPTION (RECOMPILE);
  266.  
  267. -- You will see no results if your instance is not using AlwaysOn AGs
  268.  
  269. -- Recommended hotfixes and updates for Windows Server 2012 R2-based failover clusters
  270. -- http://support.microsoft.com/kb/2920151
  271.  
  272. -- Get configuration values for instance (Query 18) (Configuration Values)
  273. SELECT name, value, value_in_use, minimum, maximum, [description], is_dynamic, is_advanced
  274. FROM sys.configurations WITH (NOLOCK)
  275. ORDER BY name OPTION (RECOMPILE);
  276.  
  277. -- Focus on these settings:
  278. -- backup compression default (should be 1 in most cases)
  279. -- clr enabled (only enable if it is needed)
  280. -- cost threshold for parallelism (depends on your workload)
  281. -- lightweight pooling (should be zero)
  282. -- max degree of parallelism (depends on your workload)
  283. -- max server memory (MB) (set to an appropriate value, not the default)
  284. -- optimize for ad hoc workloads (should be 1)
  285. -- priority boost (should be zero)
  286. -- remote admin connections (should be 1)
  287.  
  288. -- Get information about TCP Listener for SQL Server (Query 19) (TCP Listener States)
  289. SELECT listener_id, ip_address, is_ipv4, port, type_desc, state_desc, start_time
  290. FROM sys.dm_tcp_listener_states WITH (NOLOCK)
  291. ORDER BY listener_id OPTION (RECOMPILE);
  292.  
  293. -- Helpful for network and connectivity troubleshooting
  294.  
  295. -- Get information on location, time and size of any memory dumps from SQL Server (Query 20) (Memory Dump Info)
  296. SELECT [filename], creation_time, size_in_bytes/1048576.0 AS [Size (MB)]
  297. FROM sys.dm_server_memory_dumps WITH (NOLOCK)
  298. ORDER BY creation_time DESC OPTION (RECOMPILE);
  299.  
  300. -- This will not return any rows if you have
  301. -- not had any memory dumps (which is a good thing)
  302.  
  303. -- File names and paths for TempDB and all user databases in instance (Query 21) (Database Filenames and Paths)
  304. SELECT DB_NAME([database_id]) AS [Database Name],
  305. [file_id], name, physical_name, type_desc, state_desc,
  306. is_percent_growth, growth,
  307. CONVERT(bigint, growth/128.0) AS [Growth in MB],
  308. CONVERT(bigint, size/128.0) AS [Total Size in MB]
  309. FROM sys.master_files WITH (NOLOCK)
  310. WHERE [database_id] > 4
  311. AND [database_id] <> 32767
  312. OR [database_id] = 2
  313. ORDER BY DB_NAME([database_id]) OPTION (RECOMPILE);
  314.  
  315. -- Things to look at:
  316. -- Are data files and log files on different drives?
  317. -- Is everything on the C: drive?
  318. -- Is TempDB on dedicated drives?
  319. -- Is there only one TempDB data file?
  320. -- Are all of the TempDB data files the same size?
  321. -- Are there multiple data files for user databases?
  322. -- Is percent growth enabled for any files (which is bad)?
  323.  
  324. -- Volume info for all LUNS that have database files on the current instance (Query 22) (Volume Info)
  325. SELECT DISTINCT vs.volume_mount_point, vs.file_system_type,
  326. vs.logical_volume_name, CONVERT(DECIMAL(18,2),vs.total_bytes/1073741824.0) AS [Total Size (GB)],
  327. CONVERT(DECIMAL(18,2),vs.available_bytes/1073741824.0) AS [Available Size (GB)],
  328. CAST(CAST(vs.available_bytes AS FLOAT)/ CAST(vs.total_bytes AS FLOAT) AS DECIMAL(18,2)) * 100 AS [Space Free %]
  329. FROM sys.master_files AS f WITH (NOLOCK)
  330. CROSS APPLY sys.dm_os_volume_stats(f.database_id, f.[file_id]) AS vs OPTION (RECOMPILE);
  331.  
  332. --Shows you the total and free space on the LUNs where you have database files
  333.  
  334. -- Look for I/O requests taking longer than 15 seconds in the five most recent SQL Server Error Logs (Query 23) (IO Warnings)
  335. CREATE TABLE #IOWarningResults(LogDate datetime, ProcessInfo sysname, LogText nvarchar(1000));
  336.  
  337. INSERT INTO #IOWarningResults
  338. EXEC xp_readerrorlog 0, 1, N'taking longer than 15 seconds';
  339.  
  340. INSERT INTO #IOWarningResults
  341. EXEC xp_readerrorlog 1, 1, N'taking longer than 15 seconds';
  342.  
  343. INSERT INTO #IOWarningResults
  344. EXEC xp_readerrorlog 2, 1, N'taking longer than 15 seconds';
  345.  
  346. INSERT INTO #IOWarningResults
  347. EXEC xp_readerrorlog 3, 1, N'taking longer than 15 seconds';
  348.  
  349. INSERT INTO #IOWarningResults
  350. EXEC xp_readerrorlog 4, 1, N'taking longer than 15 seconds';
  351.  
  352. SELECT LogDate, ProcessInfo, LogText
  353. FROM #IOWarningResults
  354. ORDER BY LogDate DESC;
  355.  
  356. DROP TABLE #IOWarningResults;
  357.  
  358. -- Finding 15 second I/O warnings in the SQL Server Error Log is useful evidence of
  359. -- poor I/O performance (which might have many different causes)
  360.  
  361. -- Drive level latency information (Query 24) (Drive Level Latency)
  362. -- Based on code from Jimmy May
  363. SELECT tab.[Drive], tab.volume_mount_point AS [Volume Mount Point],
  364. CASE
  365. WHEN num_of_reads = 0 THEN 0
  366. ELSE (io_stall_read_ms/num_of_reads)
  367. END AS [Read Latency],
  368. CASE
  369. WHEN io_stall_write_ms = 0 THEN 0
  370. ELSE (io_stall_write_ms/num_of_writes)
  371. END AS [Write Latency],
  372. CASE
  373. WHEN (num_of_reads = 0 AND num_of_writes = 0) THEN 0
  374. ELSE (io_stall/(num_of_reads + num_of_writes))
  375. END AS [Overall Latency],
  376. CASE
  377. WHEN num_of_reads = 0 THEN 0
  378. ELSE (num_of_bytes_read/num_of_reads)
  379. END AS [Avg Bytes/Read],
  380. CASE
  381. WHEN io_stall_write_ms = 0 THEN 0
  382. ELSE (num_of_bytes_written/num_of_writes)
  383. END AS [Avg Bytes/Write],
  384. CASE
  385. WHEN (num_of_reads = 0 AND num_of_writes = 0) THEN 0
  386. ELSE ((num_of_bytes_read + num_of_bytes_written)/(num_of_reads + num_of_writes))
  387. END AS [Avg Bytes/Transfer]
  388. FROM (SELECT LEFT(UPPER(mf.physical_name), 2) AS Drive, SUM(num_of_reads) AS num_of_reads,
  389. SUM(io_stall_read_ms) AS io_stall_read_ms, SUM(num_of_writes) AS num_of_writes,
  390. SUM(io_stall_write_ms) AS io_stall_write_ms, SUM(num_of_bytes_read) AS num_of_bytes_read,
  391. SUM(num_of_bytes_written) AS num_of_bytes_written, SUM(io_stall) AS io_stall, vs.volume_mount_point
  392. FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS vfs
  393. INNER JOIN sys.master_files AS mf WITH (NOLOCK)
  394. ON vfs.database_id = mf.database_id AND vfs.file_id = mf.file_id
  395. CROSS APPLY sys.dm_os_volume_stats(mf.database_id, mf.[file_id]) AS vs
  396. GROUP BY LEFT(UPPER(mf.physical_name), 2), vs.volume_mount_point) AS tab
  397. ORDER BY [Overall Latency] OPTION (RECOMPILE);
  398.  
  399. -- Shows you the drive-level latency for reads and writes, in milliseconds
  400. -- Latency above 20-25ms is usually a problem
  401.  
  402. -- Calculates average stalls per read, per write, and per total input/output for each database file (Query 25) (IO Stalls by File)
  403. SELECT DB_NAME(fs.database_id) AS [Database Name], CAST(fs.io_stall_read_ms/(1.0 + fs.num_of_reads) AS NUMERIC(10,1)) AS [avg_read_stall_ms],
  404. CAST(fs.io_stall_write_ms/(1.0 + fs.num_of_writes) AS NUMERIC(10,1)) AS [avg_write_stall_ms],
  405. CAST((fs.io_stall_read_ms + fs.io_stall_write_ms)/(1.0 + fs.num_of_reads + fs.num_of_writes) AS NUMERIC(10,1)) AS [avg_io_stall_ms],
  406. CONVERT(DECIMAL(18,2), mf.size/128.0) AS [File Size (MB)], mf.physical_name, mf.type_desc, fs.io_stall_read_ms, fs.num_of_reads,
  407. fs.io_stall_write_ms, fs.num_of_writes, fs.io_stall_read_ms + fs.io_stall_write_ms AS [io_stalls], fs.num_of_reads + fs.num_of_writes AS [total_io]
  408. FROM sys.dm_io_virtual_file_stats(null,null) AS fs
  409. INNER JOIN sys.master_files AS mf WITH (NOLOCK)
  410. ON fs.database_id = mf.database_id
  411. AND fs.[file_id] = mf.[file_id]
  412. ORDER BY avg_io_stall_ms DESC OPTION (RECOMPILE);
  413.  
  414. -- Helps determine which database files on the entire instance have the most I/O bottlenecks
  415. -- This can help you decide whether certain LUNs are overloaded and whether you might
  416. -- want to move some files to a different location or perhaps improve your I/O performance
  417.  
  418. -- Recovery model, log reuse wait description, log file size, log usage size (Query 26) (Database Properties)
  419. -- and compatibility level for all databases on instance
  420. SELECT db.[name] AS [Database Name], db.recovery_model_desc AS [Recovery Model], db.state_desc,
  421. db.log_reuse_wait_desc AS [Log Reuse Wait Description],
  422. CONVERT(DECIMAL(18,2), ls.cntr_value/1024.0) AS [Log Size (MB)], CONVERT(DECIMAL(18,2), lu.cntr_value/1024.0) AS [Log Used (MB)],
  423. CAST(CAST(lu.cntr_value AS FLOAT) / CAST(ls.cntr_value AS FLOAT)AS DECIMAL(18,2)) * 100 AS [Log Used %],
  424. db.[compatibility_level] AS [DB Compatibility Level],
  425. db.page_verify_option_desc AS [Page Verify Option], db.is_auto_create_stats_on, db.is_auto_update_stats_on,
  426. db.is_auto_update_stats_async_on, db.is_parameterization_forced,
  427. db.snapshot_isolation_state_desc, db.is_read_committed_snapshot_on,
  428. db.is_auto_close_on, db.is_auto_shrink_on, db.target_recovery_time_in_seconds, db.is_cdc_enabled
  429. FROM sys.databases AS db WITH (NOLOCK)
  430. INNER JOIN sys.dm_os_performance_counters AS lu WITH (NOLOCK)
  431. ON db.name = lu.instance_name
  432. INNER JOIN sys.dm_os_performance_counters AS ls WITH (NOLOCK)
  433. ON db.name = ls.instance_name
  434. WHERE lu.counter_name LIKE N'Log File(s) Used Size (KB)%'
  435. AND ls.counter_name LIKE N'Log File(s) Size (KB)%'
  436. AND ls.cntr_value > 0 OPTION (RECOMPILE);
  437.  
  438. -- Things to look at:
  439. -- How many databases are on the instance?
  440. -- What recovery models are they using?
  441. -- What is the log reuse wait description?
  442. -- How full are the transaction logs ?
  443. -- What compatibility level are the databases on?
  444. -- What is the Page Verify Option? (should be CHECKSUM)
  445. -- Is Auto Update Statistics Asynchronously enabled?
  446. -- Make sure auto_shrink and auto_close are not enabled!
  447.  
  448. -- Missing Indexes for all databases by Index Advantage (Query 27) (Missing Indexes All Databases)
  449. SELECT CONVERT(decimal(18,2), user_seeks * avg_total_user_cost * (avg_user_impact * 0.01)) AS [index_advantage],
  450. migs.last_user_seek, mid.[statement] AS [Database.Schema.Table],
  451. mid.equality_columns, mid.inequality_columns, mid.included_columns,
  452. migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact
  453. FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK)
  454. INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK)
  455. ON migs.group_handle = mig.index_group_handle
  456. INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK)
  457. ON mig.index_handle = mid.index_handle
  458. ORDER BY index_advantage DESC OPTION (RECOMPILE);
  459.  
  460. -- Getting missing index information for all of the databases on the instance is very useful
  461. -- Look at last user seek time, number of user seeks to help determine source and importance
  462. -- Also look at avg_user_impact and avg_total_user_cost to help determine importance
  463. -- SQL Server is overly eager to add included columns, so beware
  464. -- Do not just blindly add indexes that show up from this query!!!
  465.  
  466. -- Get VLF Counts for all databases on the instance (Query 28) (VLF Counts)
  467. -- (adapted from Michelle Ufford)
  468. CREATE TABLE #VLFInfo (RecoveryUnitID int, FileID int,
  469. FileSize bigint, StartOffset bigint,
  470. FSeqNo bigint, [Status] bigint,
  471. Parity bigint, CreateLSN numeric(38));
  472.  
  473. CREATE TABLE #VLFCountResults(DatabaseName sysname, VLFCount int);
  474.  
  475. EXEC sp_MSforeachdb N'Use [?];
  476.  
  477. INSERT INTO #VLFInfo
  478. EXEC sp_executesql N''DBCC LOGINFO([?])'';
  479.  
  480. INSERT INTO #VLFCountResults
  481. SELECT DB_NAME(), COUNT(*)
  482. FROM #VLFInfo;
  483.  
  484. TRUNCATE TABLE #VLFInfo;'
  485.  
  486. SELECT DatabaseName, VLFCount
  487. FROM #VLFCountResults
  488. ORDER BY VLFCount DESC;
  489.  
  490. DROP TABLE #VLFInfo;
  491. DROP TABLE #VLFCountResults;
  492.  
  493. -- High VLF counts can affect write performance
  494. -- and they can make database restores and recovery take much longer
  495. -- Try to keep your VLF counts under 200 in most cases
  496.  
  497. -- Get CPU utilization by database (Query 29) (CPU Usage by Database)
  498. WITH DB_CPU_Stats
  499. AS
  500. (SELECT pa.DatabaseID, DB_Name(pa.DatabaseID) AS [Database Name], SUM(qs.total_worker_time/1000) AS [CPU_Time_Ms]
  501. FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK)
  502. CROSS APPLY (SELECT CONVERT(int, value) AS [DatabaseID]
  503. FROM sys.dm_exec_plan_attributes(qs.plan_handle)
  504. WHERE attribute = N'dbid') AS pa
  505. GROUP BY DatabaseID)
  506. SELECT ROW_NUMBER() OVER(ORDER BY [CPU_Time_Ms] DESC) AS [CPU Rank],
  507. [Database Name], [CPU_Time_Ms] AS [CPU Time (ms)],
  508. CAST([CPU_Time_Ms] * 1.0 / SUM([CPU_Time_Ms]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CPU Percent]
  509. FROM DB_CPU_Stats
  510. WHERE DatabaseID <> 32767 -- ResourceDB
  511. ORDER BY [CPU Rank] OPTION (RECOMPILE);
  512.  
  513. -- Helps determine which database is using the most CPU resources on the instance
  514.  
  515. -- Get I/O utilization by database (Query 30) (IO Usage By Database)
  516. WITH Aggregate_IO_Statistics
  517. AS
  518. (SELECT DB_NAME(database_id) AS [Database Name],
  519. CAST(SUM(num_of_bytes_read + num_of_bytes_written)/1048576 AS DECIMAL(12, 2)) AS io_in_mb
  520. FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS [DM_IO_STATS]
  521. GROUP BY database_id)
  522. SELECT ROW_NUMBER() OVER(ORDER BY io_in_mb DESC) AS [I/O Rank], [Database Name], io_in_mb AS [Total I/O (MB)],
  523. CAST(io_in_mb/ SUM(io_in_mb) OVER() * 100.0 AS DECIMAL(5,2)) AS [I/O Percent]
  524. FROM Aggregate_IO_Statistics
  525. ORDER BY [I/O Rank] OPTION (RECOMPILE);
  526.  
  527. -- Helps determine which database is using the most I/O resources on the instance
  528.  
  529. -- Get total buffer usage by database for current instance (Query 31) (Total Buffer Usage by Database)
  530. -- This make take some time to run on a busy instance
  531. WITH AggregateBufferPoolUsage
  532. AS
  533. (SELECT DB_NAME(database_id) AS [Database Name],
  534. CAST(COUNT(*) * 8/1024.0 AS DECIMAL (10,2)) AS [CachedSize]
  535. FROM sys.dm_os_buffer_descriptors WITH (NOLOCK)
  536. WHERE database_id <> 32767 -- ResourceDB
  537. GROUP BY DB_NAME(database_id))
  538. SELECT ROW_NUMBER() OVER(ORDER BY CachedSize DESC) AS [Buffer Pool Rank], [Database Name], CachedSize AS [Cached Size (MB)],
  539. CAST(CachedSize / SUM(CachedSize) OVER() * 100.0 AS DECIMAL(5,2)) AS [Buffer Pool Percent]
  540. FROM AggregateBufferPoolUsage
  541. ORDER BY [Buffer Pool Rank] OPTION (RECOMPILE);
  542.  
  543. -- Tells you how much memory (in the buffer pool)
  544. -- is being used by each database on the instance
  545.  
  546. -- Clear Wait Stats with this command
  547. -- DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR);
  548.  
  549. -- Isolate top waits for server instance since last restart or wait statistics clear (Query 32) (Top Waits)
  550. WITH [Waits]
  551. AS (SELECT wait_type, wait_time_ms/ 1000.0 AS [WaitS],
  552. (wait_time_ms - signal_wait_time_ms) / 1000.0 AS [ResourceS],
  553. signal_wait_time_ms / 1000.0 AS [SignalS],
  554. waiting_tasks_count AS [WaitCount],
  555. 100.0 * wait_time_ms / SUM (wait_time_ms) OVER() AS [Percentage],
  556. ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS [RowNum]
  557. FROM sys.dm_os_wait_stats WITH (NOLOCK)
  558. WHERE [wait_type] NOT IN (
  559. N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR', N'BROKER_TASK_STOP',
  560. N'BROKER_TO_FLUSH', N'BROKER_TRANSMITTER', N'CHECKPOINT_QUEUE',
  561. N'CHKPT', N'CLR_AUTO_EVENT', N'CLR_MANUAL_EVENT', N'CLR_SEMAPHORE',
  562. N'DBMIRROR_DBM_EVENT', N'DBMIRROR_EVENTS_QUEUE', N'DBMIRROR_WORKER_QUEUE',
  563. N'DBMIRRORING_CMD', N'DIRTY_PAGE_POLL', N'DISPATCHER_QUEUE_SEMAPHORE',
  564. N'EXECSYNC', N'FSAGENT', N'FT_IFTS_SCHEDULER_IDLE_WAIT', N'FT_IFTSHC_MUTEX',
  565. N'HADR_CLUSAPI_CALL', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', N'HADR_LOGCAPTURE_WAIT',
  566. N'HADR_NOTIFICATION_DEQUEUE', N'HADR_TIMER_TASK', N'HADR_WORK_QUEUE',
  567. N'KSOURCE_WAKEUP', N'LAZYWRITER_SLEEP', N'LOGMGR_QUEUE', N'ONDEMAND_TASK_QUEUE',
  568. N'PWAIT_ALL_COMPONENTS_INITIALIZED', N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP',
  569. N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', N'REQUEST_FOR_DEADLOCK_SEARCH',
  570. N'RESOURCE_QUEUE', N'SERVER_IDLE_CHECK', N'SLEEP_BPOOL_FLUSH', N'SLEEP_DBSTARTUP',
  571. N'SLEEP_DCOMSTARTUP', N'SLEEP_MASTERDBREADY', N'SLEEP_MASTERMDREADY',
  572. N'SLEEP_MASTERUPGRADED', N'SLEEP_MSDBSTARTUP', N'SLEEP_SYSTEMTASK', N'SLEEP_TASK',
  573. N'SLEEP_TEMPDBSTARTUP', N'SNI_HTTP_ACCEPT', N'SP_SERVER_DIAGNOSTICS_SLEEP',
  574. N'SQLTRACE_BUFFER_FLUSH', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', N'SQLTRACE_WAIT_ENTRIES',
  575. N'WAIT_FOR_RESULTS', N'WAITFOR', N'WAITFOR_TASKSHUTDOWN', N'WAIT_XTP_HOST_WAIT',
  576. N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', N'WAIT_XTP_CKPT_CLOSE', N'XE_DISPATCHER_JOIN',
  577. N'XE_DISPATCHER_WAIT', N'XE_TIMER_EVENT')
  578. AND waiting_tasks_count > 0)
  579. SELECT
  580. MAX (W1.wait_type) AS [WaitType],
  581. CAST (MAX (W1.WaitS) AS DECIMAL (16,2)) AS [Wait_Sec],
  582. CAST (MAX (W1.ResourceS) AS DECIMAL (16,2)) AS [Resource_Sec],
  583. CAST (MAX (W1.SignalS) AS DECIMAL (16,2)) AS [Signal_Sec],
  584. MAX (W1.WaitCount) AS [Wait Count],
  585. CAST (MAX (W1.Percentage) AS DECIMAL (5,2)) AS [Wait Percentage],
  586. CAST ((MAX (W1.WaitS) / MAX (W1.WaitCount)) AS DECIMAL (16,4)) AS [AvgWait_Sec],
  587. CAST ((MAX (W1.ResourceS) / MAX (W1.WaitCount)) AS DECIMAL (16,4)) AS [AvgRes_Sec],
  588. CAST ((MAX (W1.SignalS) / MAX (W1.WaitCount)) AS DECIMAL (16,4)) AS [AvgSig_Sec]
  589. FROM Waits AS W1
  590. INNER JOIN Waits AS W2
  591. ON W2.RowNum <= W1.RowNum
  592. GROUP BY W1.RowNum
  593. HAVING SUM (W2.Percentage) - MAX (W1.Percentage) < 99 -- percentage threshold
  594. OPTION (RECOMPILE);
  595.  
  596. -- Cumulative wait stats are not as useful on an idle instance that is not under load or performance pressure
  597.  
  598. -- The SQL Server Wait Type Repository
  599. -- http://blogs.msdn.com/b/psssql/archive/2009/11/03/the-sql-server-wait-type-repository.aspx
  600.  
  601. -- Wait statistics, or please tell me where it hurts
  602. -- http://www.sqlskills.com/blogs/paul/wait-statistics-or-please-tell-me-where-it-hurts/
  603.  
  604. -- SQL Server 2005 Performance Tuning using the Waits and Queues
  605. -- http://technet.microsoft.com/en-us/library/cc966413.aspx
  606.  
  607. -- sys.dm_os_wait_stats (Transact-SQL)
  608. -- http://msdn.microsoft.com/en-us/library/ms179984(v=sql.120).aspx
  609.  
  610. -- Signal Waits for instance (Query 33) (Signal Waits)
  611. SELECT CAST(100.0 * SUM(signal_wait_time_ms) / SUM (wait_time_ms) AS NUMERIC(20,2)) AS [% Signal (CPU) Waits],
  612. CAST(100.0 * SUM(wait_time_ms - signal_wait_time_ms) / SUM (wait_time_ms) AS NUMERIC(20,2)) AS [% Resource Waits]
  613. FROM sys.dm_os_wait_stats WITH (NOLOCK)
  614. WHERE wait_type NOT IN (
  615. N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR', N'BROKER_TASK_STOP',
  616. N'BROKER_TO_FLUSH', N'BROKER_TRANSMITTER', N'CHECKPOINT_QUEUE',
  617. N'CHKPT', N'CLR_AUTO_EVENT', N'CLR_MANUAL_EVENT', N'CLR_SEMAPHORE',
  618. N'DBMIRROR_DBM_EVENT', N'DBMIRROR_EVENTS_QUEUE', N'DBMIRROR_WORKER_QUEUE',
  619. N'DBMIRRORING_CMD', N'DIRTY_PAGE_POLL', N'DISPATCHER_QUEUE_SEMAPHORE',
  620. N'EXECSYNC', N'FSAGENT', N'FT_IFTS_SCHEDULER_IDLE_WAIT', N'FT_IFTSHC_MUTEX',
  621. N'HADR_CLUSAPI_CALL', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', N'HADR_LOGCAPTURE_WAIT',
  622. N'HADR_NOTIFICATION_DEQUEUE', N'HADR_TIMER_TASK', N'HADR_WORK_QUEUE',
  623. N'KSOURCE_WAKEUP', N'LAZYWRITER_SLEEP', N'LOGMGR_QUEUE', N'ONDEMAND_TASK_QUEUE',
  624. N'PWAIT_ALL_COMPONENTS_INITIALIZED', N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP',
  625. N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', N'REQUEST_FOR_DEADLOCK_SEARCH',
  626. N'RESOURCE_QUEUE', N'SERVER_IDLE_CHECK', N'SLEEP_BPOOL_FLUSH', N'SLEEP_DBSTARTUP',
  627. N'SLEEP_DCOMSTARTUP', N'SLEEP_MASTERDBREADY', N'SLEEP_MASTERMDREADY',
  628. N'SLEEP_MASTERUPGRADED', N'SLEEP_MSDBSTARTUP', N'SLEEP_SYSTEMTASK', N'SLEEP_TASK',
  629. N'SLEEP_TEMPDBSTARTUP', N'SNI_HTTP_ACCEPT', N'SP_SERVER_DIAGNOSTICS_SLEEP',
  630. N'SQLTRACE_BUFFER_FLUSH', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', N'SQLTRACE_WAIT_ENTRIES',
  631. N'WAIT_FOR_RESULTS', N'WAITFOR', N'WAITFOR_TASKSHUTDOWN', N'WAIT_XTP_HOST_WAIT',
  632. N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', N'WAIT_XTP_CKPT_CLOSE', N'XE_DISPATCHER_JOIN',
  633. N'XE_DISPATCHER_WAIT', N'XE_TIMER_EVENT') OPTION (RECOMPILE);
  634.  
  635. -- Signal Waits above 10-15% is usually a confirming sign of CPU pressure
  636. -- Cumulative wait stats are not as useful on an idle instance that is not under load or performance pressure
  637. -- Resource waits are non-CPU related waits
  638.  
  639. -- Get logins that are connected and how many sessions they have (Query 34) (Connection Counts)
  640. SELECT login_name, [program_name], COUNT(session_id) AS [session_count]
  641. FROM sys.dm_exec_sessions WITH (NOLOCK)
  642. GROUP BY login_name, [program_name]
  643. ORDER BY COUNT(session_id) DESC OPTION (RECOMPILE);
  644.  
  645. -- This can help characterize your workload and
  646. -- determine whether you are seeing a normal level of activity
  647.  
  648. -- Get a count of SQL connections by IP address (Query 35) (Connection Counts by IP Address)
  649. SELECT ec.client_net_address, es.[program_name], es.[host_name], es.login_name,
  650. COUNT(ec.session_id) AS [connection count]
  651. FROM sys.dm_exec_sessions AS es WITH (NOLOCK)
  652. INNER JOIN sys.dm_exec_connections AS ec WITH (NOLOCK)
  653. ON es.session_id = ec.session_id
  654. GROUP BY ec.client_net_address, es.[program_name], es.[host_name], es.login_name
  655. ORDER BY ec.client_net_address, es.[program_name] OPTION (RECOMPILE);
  656.  
  657. -- This helps you figure where your database load is coming from
  658. -- and verifies connectivity from other machines
  659.  
  660. -- Get Average Task Counts (run multiple times) (Query 36) (Avg Task Counts)
  661. SELECT AVG(current_tasks_count) AS [Avg Task Count],
  662. AVG(runnable_tasks_count) AS [Avg Runnable Task Count],
  663. AVG(pending_disk_io_count) AS [Avg Pending DiskIO Count]
  664. FROM sys.dm_os_schedulers WITH (NOLOCK)
  665. WHERE scheduler_id < 255 OPTION (RECOMPILE);
  666.  
  667. -- Sustained values above 10 suggest further investigation in that area
  668. -- High Avg Task Counts are often caused by blocking/deadlocking or other resource contention
  669.  
  670. -- Sustained values above 1 suggest further investigation in that area
  671. -- High Avg Runnable Task Counts are a good sign of CPU pressure
  672. -- High Avg Pending DiskIO Counts are a sign of disk pressure
  673.  
  674. -- Get CPU Utilization History for last 256 minutes (in one minute intervals) (Query 37) (CPU Utilization History)
  675. -- This version works with SQL Server 2012
  676. DECLARE @ts_now bigint = (SELECT cpu_ticks/(cpu_ticks/ms_ticks) FROM sys.dm_os_sys_info WITH (NOLOCK));
  677.  
  678. SELECT TOP(256) SQLProcessUtilization AS [SQL Server Process CPU Utilization],
  679. SystemIdle AS [System Idle Process],
  680. 100 - SystemIdle - SQLProcessUtilization AS [Other Process CPU Utilization],
  681. DATEADD(ms, -1 * (@ts_now - [timestamp]), GETDATE()) AS [Event Time]
  682. FROM (SELECT record.value('(./Record/@id)[1]', 'int') AS record_id,
  683. record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int')
  684. AS [SystemIdle],
  685. record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]', 'int')
  686. AS [SQLProcessUtilization], [timestamp]
  687. FROM (SELECT [timestamp], CONVERT(xml, record) AS [record]
  688. FROM sys.dm_os_ring_buffers WITH (NOLOCK)
  689. WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
  690. AND record LIKE N'%<SystemHealth>%') AS x) AS y
  691. ORDER BY record_id DESC OPTION (RECOMPILE);
  692.  
  693. -- Look at the trend over the entire period.
  694. -- Also look at high sustained Other Process CPU Utilization values
  695.  
  696. -- Get top total worker time queries for entire instance (Query 38) (Top Worker Time Queries)
  697. SELECT TOP(50) DB_NAME(t.[dbid]) AS [Database Name], LEFT(t.[text], 255) AS [Short Query Text],
  698. qs.total_worker_time AS [Total Worker Time], qs.min_worker_time AS [Min Worker Time],
  699. qs.total_worker_time/qs.execution_count AS [Avg Worker Time],
  700. qs.max_worker_time AS [Max Worker Time], qs.execution_count AS [Execution Count],
  701. qs.total_elapsed_time/qs.execution_count AS [Avg Elapsed Time],
  702. qs.total_logical_reads/qs.execution_count AS [Avg Logical Reads],
  703. qs.total_physical_reads/qs.execution_count AS [Avg Physical Reads], qs.creation_time AS [Creation Time]
  704. --, t.[text] AS [Query Text], qp.query_plan AS [Query Plan] -- uncomment out these columns if not copying results to Excel
  705. FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK)
  706. CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t
  707. CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp
  708. ORDER BY qs.total_worker_time DESC OPTION (RECOMPILE);
  709.  
  710. -- Helps you find the most expensive queries from a CPU perspective across the entire instance
  711.  
  712. -- Good basic information about OS memory amounts and state (Query 39) (System Memory)
  713. SELECT total_physical_memory_kb/1024 AS [Physical Memory (MB)],
  714. available_physical_memory_kb/1024 AS [Available Memory (MB)],
  715. total_page_file_kb/1024 AS [Total Page File (MB)],
  716. available_page_file_kb/1024 AS [Available Page File (MB)],
  717. system_cache_kb/1024 AS [System Cache (MB)],
  718. system_memory_state_desc AS [System Memory State]
  719. FROM sys.dm_os_sys_memory WITH (NOLOCK) OPTION (RECOMPILE);
  720.  
  721. -- You want to see "Available physical memory is high"
  722. -- This indicates that you are not under external memory pressure
  723.  
  724. -- SQL Server Process Address space info (Query 40) (Process Memory)
  725. -- (shows whether locked pages is enabled, among other things)
  726. SELECT physical_memory_in_use_kb/1024 AS [SQL Server Memory Usage (MB)],
  727. large_page_allocations_kb, locked_page_allocations_kb, page_fault_count,
  728. memory_utilization_percentage, available_commit_limit_kb,
  729. process_physical_memory_low, process_virtual_memory_low
  730. FROM sys.dm_os_process_memory WITH (NOLOCK) OPTION (RECOMPILE);
  731.  
  732. -- You want to see 0 for process_physical_memory_low
  733. -- You want to see 0 for process_virtual_memory_low
  734. -- This indicates that you are not under internal memory pressure
  735.  
  736. -- Page Life Expectancy (PLE) value for each NUMA node in current instance (Query 41) (PLE by NUMA Node)
  737. SELECT @@SERVERNAME AS [Server Name], [object_name], instance_name, cntr_value AS [Page Life Expectancy]
  738. FROM sys.dm_os_performance_counters WITH (NOLOCK)
  739. WHERE [object_name] LIKE N'%Buffer Node%' -- Handles named instances
  740. AND counter_name = N'Page life expectancy' OPTION (RECOMPILE);
  741.  
  742. -- PLE is a good measurement of memory pressure.
  743. -- Higher PLE is better. Watch the trend over time, not the absolute value.
  744. -- This will only return one row for non-NUMA systems.
  745.  
  746. -- Memory Grants Pending value for current instance (Query 42) (Memory Grants Pending)
  747. SELECT @@SERVERNAME AS [Server Name], [object_name], cntr_value AS [Memory Grants Pending]
  748. FROM sys.dm_os_performance_counters WITH (NOLOCK)
  749. WHERE [object_name] LIKE N'%Memory Manager%' -- Handles named instances
  750. AND counter_name = N'Memory Grants Pending' OPTION (RECOMPILE);
  751.  
  752. -- Memory Grants Pending above zero for a sustained period is a very strong indicator of memory pressure
  753.  
  754. -- Memory Clerk Usage for instance (Query 43) (Memory Clerk Usage)
  755. -- Look for high value for CACHESTORE_SQLCP (Ad-hoc query plans)
  756. SELECT TOP(10) mc.[type] AS [Memory Clerk Type],
  757. CAST((SUM(mc.pages_kb)/1024.0) AS DECIMAL (15,2)) AS [Memory Usage (MB)]
  758. FROM sys.dm_os_memory_clerks AS mc WITH (NOLOCK)
  759. GROUP BY mc.[type]
  760. ORDER BY SUM(mc.pages_kb) DESC OPTION (RECOMPILE);
  761.  
  762. -- MEMORYCLERK_SQLBUFFERPOOL is new for SQL Server 2012. It should be your highest consumer of memory
  763.  
  764. -- CACHESTORE_SQLCP SQL Plans
  765. -- These are cached SQL statements or batches that aren't in stored procedures, functions and triggers
  766. -- Watch out for high values for CACHESTORE_SQLCP
  767.  
  768. -- CACHESTORE_OBJCP Object Plans
  769. -- These are compiled plans for stored procedures, functions and triggers
  770.  
  771. -- Find single-use, ad-hoc and prepared queries that are bloating the plan cache (Query 44) (Ad hoc Queries)
  772. SELECT TOP(50) [text] AS [QueryText], cp.cacheobjtype, cp.objtype, cp.size_in_bytes/1024 AS [Plan Size in KB]
  773. FROM sys.dm_exec_cached_plans AS cp WITH (NOLOCK)
  774. CROSS APPLY sys.dm_exec_sql_text(plan_handle)
  775. WHERE cp.cacheobjtype = N'Compiled Plan'
  776. AND cp.objtype IN (N'Adhoc', N'Prepared')
  777. AND cp.usecounts = 1
  778. ORDER BY cp.size_in_bytes DESC OPTION (RECOMPILE);
  779.  
  780. -- Gives you the text, type and size of single-use ad-hoc and prepared queries that waste space in the plan cache
  781. -- Enabling 'optimize for ad hoc workloads' for the instance can help (SQL Server 2008 and above only)
  782. -- Running DBCC FREESYSTEMCACHE ('SQL Plans') periodically may be required to better control this.
  783. -- Enabling forced parameterization for the database can help, but test first!
  784.  
  785. -- Database specific queries *****************************************************************
  786.  
  787. -- **** Switch to a user database *****
  788. USE YourDatabaseName; -- make sure to change to an actual database on your instance
  789. GO
  790.  
  791. -- Individual File Sizes and space available for current database (Query 45) (File Sizes and Space)
  792. SELECT f.name AS [File Name] , f.physical_name AS [Physical Name],
  793. CAST((f.size/128.0) AS DECIMAL(15,2)) AS [Total Size in MB],
  794. CAST(f.size/128.0 - CAST(FILEPROPERTY(f.name, 'SpaceUsed') AS int)/128.0 AS DECIMAL(15,2))
  795. AS [Available Space In MB], [file_id], fg.name AS [Filegroup Name]
  796. FROM sys.database_files AS f WITH (NOLOCK)
  797. LEFT OUTER JOIN sys.data_spaces AS fg WITH (NOLOCK)
  798. ON f.data_space_id = fg.data_space_id OPTION (RECOMPILE);
  799.  
  800. -- Look at how large and how full the files are and where they are located
  801. -- Make sure the transaction log is not full!!
  802.  
  803. -- I/O Statistics by file for the current database (Query 46) (IO Stats By File)
  804. SELECT DB_NAME(DB_ID()) AS [Database Name], df.name AS [Logical Name], vfs.[file_id],
  805. df.physical_name AS [Physical Name], vfs.num_of_reads, vfs.num_of_writes, vfs.io_stall_read_ms, vfs.io_stall_write_ms,
  806. CAST(100. * vfs.io_stall_read_ms/(vfs.io_stall_read_ms + vfs.io_stall_write_ms) AS DECIMAL(10,1)) AS [IO Stall Reads Pct],
  807. CAST(100. * vfs.io_stall_write_ms/(vfs.io_stall_write_ms + vfs.io_stall_read_ms) AS DECIMAL(10,1)) AS [IO Stall Writes Pct],
  808. (vfs.num_of_reads + vfs.num_of_writes) AS [Writes + Reads],
  809. CAST(vfs.num_of_bytes_read/1048576.0 AS DECIMAL(10, 2)) AS [MB Read],
  810. CAST(vfs.num_of_bytes_written/1048576.0 AS DECIMAL(10, 2)) AS [MB Written],
  811. CAST(100. * vfs.num_of_reads/(vfs.num_of_reads + vfs.num_of_writes) AS DECIMAL(10,1)) AS [# Reads Pct],
  812. CAST(100. * vfs.num_of_writes/(vfs.num_of_reads + vfs.num_of_writes) AS DECIMAL(10,1)) AS [# Write Pct],
  813. CAST(100. * vfs.num_of_bytes_read/(vfs.num_of_bytes_read + vfs.num_of_bytes_written) AS DECIMAL(10,1)) AS [Read Bytes Pct],
  814. CAST(100. * vfs.num_of_bytes_written/(vfs.num_of_bytes_read + vfs.num_of_bytes_written) AS DECIMAL(10,1)) AS [Written Bytes Pct]
  815. FROM sys.dm_io_virtual_file_stats(DB_ID(), NULL) AS vfs
  816. INNER JOIN sys.database_files AS df WITH (NOLOCK)
  817. ON vfs.[file_id]= df.[file_id] OPTION (RECOMPILE);
  818.  
  819. -- This helps you characterize your workload better from an I/O perspective for this database
  820. -- It helps you determine whether you has an OLTP or DW/DSS type of workload
  821.  
  822. -- Top cached queries by Execution Count (SQL Server 2012) (Query 47) (Query Execution Counts)
  823. SELECT TOP (100) qs.execution_count, qs.total_rows, qs.last_rows, qs.min_rows, qs.max_rows,
  824. qs.last_elapsed_time, qs.min_elapsed_time, qs.max_elapsed_time,
  825. total_worker_time, total_logical_reads,
  826. SUBSTRING(qt.TEXT,qs.statement_start_offset/2 +1,
  827. (CASE WHEN qs.statement_end_offset = -1
  828. THEN LEN(CONVERT(NVARCHAR(MAX), qt.TEXT)) * 2
  829. ELSE qs.statement_end_offset END - qs.statement_start_offset)/2) AS query_text
  830. FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK)
  831. CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
  832. WHERE qt.dbid = DB_ID()
  833. ORDER BY qs.execution_count DESC OPTION (RECOMPILE);
  834.  
  835. -- Uses several new rows returned columns to help troubleshoot performance problems
  836.  
  837. -- Top Cached SPs By Execution Count (SQL Server 2012) (Query 48) (SP Execution Counts)
  838. SELECT TOP(100) p.name AS [SP Name], qs.execution_count,
  839. ISNULL(qs.execution_count/DATEDIFF(Minute, qs.cached_time, GETDATE()), 0) AS [Calls/Minute],
  840. qs.total_worker_time/qs.execution_count AS [AvgWorkerTime], qs.total_worker_time AS [TotalWorkerTime],
  841. qs.total_elapsed_time, qs.total_elapsed_time/qs.execution_count AS [avg_elapsed_time],
  842. qs.cached_time
  843. FROM sys.procedures AS p WITH (NOLOCK)
  844. INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK)
  845. ON p.[object_id] = qs.[object_id]
  846. WHERE qs.database_id = DB_ID()
  847. ORDER BY qs.execution_count DESC OPTION (RECOMPILE);
  848.  
  849. -- Tells you which cached stored procedures are called the most often
  850. -- This helps you characterize and baseline your workload
  851.  
  852. -- Top Cached SPs By Avg Elapsed Time (SQL Server 2012) (Query 49) (SP Avg Elapsed Time)
  853. SELECT TOP(25) p.name AS [SP Name], qs.total_elapsed_time/qs.execution_count AS [avg_elapsed_time],
  854. qs.total_elapsed_time, qs.execution_count, ISNULL(qs.execution_count/DATEDIFF(Minute, qs.cached_time,
  855. GETDATE()), 0) AS [Calls/Minute], qs.total_worker_time/qs.execution_count AS [AvgWorkerTime],
  856. qs.total_worker_time AS [TotalWorkerTime], qs.cached_time
  857. FROM sys.procedures AS p WITH (NOLOCK)
  858. INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK)
  859. ON p.[object_id] = qs.[object_id]
  860. WHERE qs.database_id = DB_ID()
  861. ORDER BY avg_elapsed_time DESC OPTION (RECOMPILE);
  862.  
  863. -- This helps you find long-running cached stored procedures that
  864. -- may be easy to optimize with standard query tuning techniques
  865.  
  866. -- Top Cached SPs By Avg Elapsed Time with execution time variability (SQL Server 2012) (Query 50) (SP Avg Elapsed Variable Time)
  867. SELECT TOP(25) p.name AS [SP Name], qs.execution_count, qs.min_elapsed_time,
  868. qs.total_elapsed_time/qs.execution_count AS [avg_elapsed_time],
  869. qs.max_elapsed_time, qs.last_elapsed_time, qs.cached_time
  870. FROM sys.procedures AS p WITH (NOLOCK)
  871. INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK)
  872. ON p.[object_id] = qs.[object_id]
  873. WHERE qs.database_id = DB_ID()
  874. ORDER BY avg_elapsed_time DESC OPTION (RECOMPILE);
  875.  
  876. -- This gives you some interesting information about the variability in the
  877. -- execution time of your cached stored procedures, which is useful for tuning
  878.  
  879. -- Top Cached SPs By Total Worker time (SQL Server 2012). Worker time relates to CPU cost (Query 51) (SP Worker Time)
  880. SELECT TOP(25) p.name AS [SP Name], qs.total_worker_time AS [TotalWorkerTime],
  881. qs.total_worker_time/qs.execution_count AS [AvgWorkerTime], qs.execution_count,
  882. ISNULL(qs.execution_count/DATEDIFF(Minute, qs.cached_time, GETDATE()), 0) AS [Calls/Minute],
  883. qs.total_elapsed_time, qs.total_elapsed_time/qs.execution_count
  884. AS [avg_elapsed_time], qs.cached_time
  885. FROM sys.procedures AS p WITH (NOLOCK)
  886. INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK)
  887. ON p.[object_id] = qs.[object_id]
  888. WHERE qs.database_id = DB_ID()
  889. ORDER BY qs.total_worker_time DESC OPTION (RECOMPILE);
  890.  
  891. -- This helps you find the most expensive cached stored procedures from a CPU perspective
  892. -- You should look at this if you see signs of CPU pressure
  893.  
  894. -- Top Cached SPs By Total Logical Reads (SQL Server 2012). Logical reads relate to memory pressure (Query 52) (SP Logical Reads)
  895. SELECT TOP(25) p.name AS [SP Name], qs.total_logical_reads AS [TotalLogicalReads],
  896. qs.total_logical_reads/qs.execution_count AS [AvgLogicalReads],qs.execution_count,
  897. ISNULL(qs.execution_count/DATEDIFF(Minute, qs.cached_time, GETDATE()), 0) AS [Calls/Minute],
  898. qs.total_elapsed_time, qs.total_elapsed_time/qs.execution_count
  899. AS [avg_elapsed_time], qs.cached_time
  900. FROM sys.procedures AS p WITH (NOLOCK)
  901. INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK)
  902. ON p.[object_id] = qs.[object_id]
  903. WHERE qs.database_id = DB_ID()
  904. ORDER BY qs.total_logical_reads DESC OPTION (RECOMPILE);
  905.  
  906. -- This helps you find the most expensive cached stored procedures from a memory perspective
  907. -- You should look at this if you see signs of memory pressure
  908.  
  909. -- Top Cached SPs By Total Physical Reads (SQL Server 2012). Physical reads relate to disk I/O pressure (Query 53) (SP Physical Reads)
  910. SELECT TOP(25) p.name AS [SP Name],qs.total_physical_reads AS [TotalPhysicalReads],
  911. qs.total_physical_reads/qs.execution_count AS [AvgPhysicalReads], qs.execution_count,
  912. qs.total_logical_reads,qs.total_elapsed_time, qs.total_elapsed_time/qs.execution_count
  913. AS [avg_elapsed_time], qs.cached_time
  914. FROM sys.procedures AS p WITH (NOLOCK)
  915. INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK)
  916. ON p.[object_id] = qs.[object_id]
  917. WHERE qs.database_id = DB_ID()
  918. AND qs.total_physical_reads > 0
  919. ORDER BY qs.total_physical_reads DESC, qs.total_logical_reads DESC OPTION (RECOMPILE);
  920.  
  921. -- This helps you find the most expensive cached stored procedures from a read I/O perspective
  922. -- You should look at this if you see signs of I/O pressure or of memory pressure
  923.  
  924. -- Top Cached SPs By Total Logical Writes (SQL Server 2012) (Query 54) (SP Logical Writes)
  925. -- Logical writes relate to both memory and disk I/O pressure
  926. SELECT TOP(25) p.name AS [SP Name], qs.total_logical_writes AS [TotalLogicalWrites],
  927. qs.total_logical_writes/qs.execution_count AS [AvgLogicalWrites], qs.execution_count,
  928. ISNULL(qs.execution_count/DATEDIFF(Minute, qs.cached_time, GETDATE()), 0) AS [Calls/Minute],
  929. qs.total_elapsed_time, qs.total_elapsed_time/qs.execution_count AS [avg_elapsed_time],
  930. qs.cached_time
  931. FROM sys.procedures AS p WITH (NOLOCK)
  932. INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK)
  933. ON p.[object_id] = qs.[object_id]
  934. WHERE qs.database_id = DB_ID()
  935. AND qs.total_logical_writes > 0
  936. ORDER BY qs.total_logical_writes DESC OPTION (RECOMPILE);
  937.  
  938. -- This helps you find the most expensive cached stored procedures from a write I/O perspective
  939. -- You should look at this if you see signs of I/O pressure or of memory pressure
  940.  
  941. -- Lists the top statements by average input/output usage for the current database (Query 55) (Top IO Statements)
  942. SELECT TOP(50) OBJECT_NAME(qt.objectid, dbid) AS [SP Name],
  943. (qs.total_logical_reads + qs.total_logical_writes) /qs.execution_count AS [Avg IO], qs.execution_count AS [Execution Count],
  944. SUBSTRING(qt.[text],qs.statement_start_offset/2,
  945. (CASE
  946. WHEN qs.statement_end_offset = -1
  947. THEN LEN(CONVERT(nvarchar(max), qt.[text])) * 2
  948. ELSE qs.statement_end_offset
  949. END - qs.statement_start_offset)/2) AS [Query Text]
  950. FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK)
  951. CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
  952. WHERE qt.[dbid] = DB_ID()
  953. ORDER BY [Avg IO] DESC OPTION (RECOMPILE);
  954.  
  955. -- Helps you find the most expensive statements for I/O by SP
  956.  
  957. -- Possible Bad NC Indexes (writes > reads) (Query 56) (Bad NC Indexes)
  958. SELECT OBJECT_NAME(s.[object_id]) AS [Table Name], i.name AS [Index Name], i.index_id,
  959. i.is_disabled, i.is_hypothetical, i.has_filter, i.fill_factor,
  960. user_updates AS [Total Writes], user_seeks + user_scans + user_lookups AS [Total Reads],
  961. user_updates - (user_seeks + user_scans + user_lookups) AS [Difference]
  962. FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK)
  963. INNER JOIN sys.indexes AS i WITH (NOLOCK)
  964. ON s.[object_id] = i.[object_id]
  965. AND i.index_id = s.index_id
  966. WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1
  967. AND s.database_id = DB_ID()
  968. AND user_updates > (user_seeks + user_scans + user_lookups)
  969. AND i.index_id > 1
  970. ORDER BY [Difference] DESC, [Total Writes] DESC, [Total Reads] ASC OPTION (RECOMPILE);
  971.  
  972. -- Look for indexes with high numbers of writes and zero or very low numbers of reads
  973. -- Consider your complete workload, and how long your instance has been running
  974. -- Investigate further before dropping an index!
  975.  
  976. -- Missing Indexes for current database by Index Advantage (Query 57) (Missing Indexes)
  977. SELECT DISTINCT CONVERT(decimal(18,2), user_seeks * avg_total_user_cost * (avg_user_impact * 0.01)) AS [index_advantage],
  978. migs.last_user_seek, mid.[statement] AS [Database.Schema.Table],
  979. mid.equality_columns, mid.inequality_columns, mid.included_columns,
  980. migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact,
  981. OBJECT_NAME(mid.[object_id]) AS [Table Name], p.rows AS [Table Rows]
  982. FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK)
  983. INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK)
  984. ON migs.group_handle = mig.index_group_handle
  985. INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK)
  986. ON mig.index_handle = mid.index_handle
  987. INNER JOIN sys.partitions AS p WITH (NOLOCK)
  988. ON p.[object_id] = mid.[object_id]
  989. WHERE mid.database_id = DB_ID()
  990. ORDER BY index_advantage DESC OPTION (RECOMPILE);
  991.  
  992. -- Look at index advantage, last user seek time, number of user seeks to help determine source and importance
  993. -- SQL Server is overly eager to add included columns, so beware
  994. -- Do not just blindly add indexes that show up from this query!!!
  995.  
  996. -- Find missing index warnings for cached plans in the current database (Query 58) (Missing Index Warnings)
  997. -- Note: This query could take some time on a busy instance
  998. SELECT TOP(25) OBJECT_NAME(objectid) AS [ObjectName],
  999. query_plan, cp.objtype, cp.usecounts
  1000. FROM sys.dm_exec_cached_plans AS cp WITH (NOLOCK)
  1001. CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp
  1002. WHERE CAST(query_plan AS NVARCHAR(MAX)) LIKE N'%MissingIndex%'
  1003. AND dbid = DB_ID()
  1004. ORDER BY cp.usecounts DESC OPTION (RECOMPILE);
  1005.  
  1006. -- Helps you connect missing indexes to specific stored procedures or queries
  1007. -- This can help you decide whether to add them or not
  1008.  
  1009. -- Breaks down buffers used by current database by object (table, index) in the buffer cache (Query 59) (Buffer Usage)
  1010. -- Note: This query could take some time on a busy instance
  1011. SELECT OBJECT_NAME(p.[object_id]) AS [Object Name], p.index_id,
  1012. CAST(COUNT(*)/128.0 AS DECIMAL(10, 2)) AS [Buffer size(MB)],
  1013. COUNT(*) AS [BufferCount], p.Rows AS [Row Count],
  1014. p.data_compression_desc AS [Compression Type]
  1015. FROM sys.allocation_units AS a WITH (NOLOCK)
  1016. INNER JOIN sys.dm_os_buffer_descriptors AS b WITH (NOLOCK)
  1017. ON a.allocation_unit_id = b.allocation_unit_id
  1018. INNER JOIN sys.partitions AS p WITH (NOLOCK)
  1019. ON a.container_id = p.hobt_id
  1020. WHERE b.database_id = CONVERT(int,DB_ID())
  1021. AND p.[object_id] > 100
  1022. GROUP BY p.[object_id], p.index_id, p.data_compression_desc, p.[Rows]
  1023. ORDER BY [BufferCount] DESC OPTION (RECOMPILE);
  1024.  
  1025. -- Tells you what tables and indexes are using the most memory in the buffer cache
  1026. -- It can help identify possible candidates for data compression
  1027.  
  1028. -- Get Table names, row counts, and compression status for clustered index or heap (Query 60) (Table Sizes)
  1029. SELECT OBJECT_NAME(object_id) AS [ObjectName],
  1030. SUM(Rows) AS [RowCount], data_compression_desc AS [CompressionType]
  1031. FROM sys.partitions WITH (NOLOCK)
  1032. WHERE index_id < 2 --ignore the partitions from the non-clustered index if any
  1033. AND OBJECT_NAME(object_id) NOT LIKE N'sys%'
  1034. AND OBJECT_NAME(object_id) NOT LIKE N'queue_%'
  1035. AND OBJECT_NAME(object_id) NOT LIKE N'filestream_tombstone%'
  1036. AND OBJECT_NAME(object_id) NOT LIKE N'fulltext%'
  1037. AND OBJECT_NAME(object_id) NOT LIKE N'ifts_comp_fragment%'
  1038. AND OBJECT_NAME(object_id) NOT LIKE N'filetable_updates%'
  1039. AND OBJECT_NAME(object_id) NOT LIKE N'xml_index_nodes%'
  1040. GROUP BY object_id, data_compression_desc
  1041. ORDER BY SUM(Rows) DESC OPTION (RECOMPILE);
  1042.  
  1043. -- Gives you an idea of table sizes, and possible data compression opportunities
  1044.  
  1045. -- Get some key table properties (Query 61) (Table Properties)
  1046. SELECT [name], create_date, lock_on_bulk_load, is_replicated, has_replication_filter,
  1047. is_tracked_by_cdc, lock_escalation_desc
  1048. FROM sys.tables WITH (NOLOCK)
  1049. ORDER BY [name] OPTION (RECOMPILE);
  1050.  
  1051. -- Gives you some good information about your tables
  1052.  
  1053. -- Detect blocking (run multiple times) (Query 62) (Detect Blocking)
  1054. SELECT t1.resource_type AS [lock type], DB_NAME(resource_database_id) AS [database],
  1055. t1.resource_associated_entity_id AS [blk object],t1.request_mode AS [lock req], --- lock requested
  1056. t1.request_session_id AS [waiter sid], t2.wait_duration_ms AS [wait time], -- spid of waiter
  1057. (SELECT [text] FROM sys.dm_exec_requests AS r WITH (NOLOCK) -- get sql for waiter
  1058. CROSS APPLY sys.dm_exec_sql_text(r.[sql_handle])
  1059. WHERE r.session_id = t1.request_session_id) AS [waiter_batch],
  1060. (SELECT SUBSTRING(qt.[text],r.statement_start_offset/2,
  1061. (CASE WHEN r.statement_end_offset = -1
  1062. THEN LEN(CONVERT(nvarchar(max), qt.[text])) * 2
  1063. ELSE r.statement_end_offset END - r.statement_start_offset)/2)
  1064. FROM sys.dm_exec_requests AS r WITH (NOLOCK)
  1065. CROSS APPLY sys.dm_exec_sql_text(r.[sql_handle]) AS qt
  1066. WHERE r.session_id = t1.request_session_id) AS [waiter_stmt], -- statement blocked
  1067. t2.blocking_session_id AS [blocker sid], -- spid of blocker
  1068. (SELECT [text] FROM sys.sysprocesses AS p -- get sql for blocker
  1069. CROSS APPLY sys.dm_exec_sql_text(p.[sql_handle])
  1070. WHERE p.spid = t2.blocking_session_id) AS [blocker_stmt]
  1071. FROM sys.dm_tran_locks AS t1 WITH (NOLOCK)
  1072. INNER JOIN sys.dm_os_waiting_tasks AS t2 WITH (NOLOCK)
  1073. ON t1.lock_owner_address = t2.resource_address OPTION (RECOMPILE);
  1074.  
  1075. -- Helps troubleshoot blocking and deadlocking issues
  1076. -- The results will change from second to second on a busy system
  1077. -- You should run this query multiple times when you see signs of blocking
  1078.  
  1079. -- When were Statistics last updated on all indexes? (Query 63) (Statistics Update)
  1080. SELECT SCHEMA_NAME(o.Schema_ID) + N'.' + o.NAME AS [Object Name], o.type_desc AS [Object Type],
  1081. i.name AS [Index Name], STATS_DATE(i.[object_id], i.index_id) AS [Statistics Date],
  1082. s.auto_created, s.no_recompute, s.user_created, s.is_temporary,
  1083. st.row_count, st.used_page_count
  1084. FROM sys.objects AS o WITH (NOLOCK)
  1085. INNER JOIN sys.indexes AS i WITH (NOLOCK)
  1086. ON o.[object_id] = i.[object_id]
  1087. INNER JOIN sys.stats AS s WITH (NOLOCK)
  1088. ON i.[object_id] = s.[object_id]
  1089. AND i.index_id = s.stats_id
  1090. INNER JOIN sys.dm_db_partition_stats AS st WITH (NOLOCK)
  1091. ON o.[object_id] = st.[object_id]
  1092. AND i.[index_id] = st.[index_id]
  1093. WHERE o.[type] IN ('U', 'V')
  1094. AND st.row_count > 0
  1095. ORDER BY STATS_DATE(i.[object_id], i.index_id) DESC OPTION (RECOMPILE);
  1096.  
  1097. -- Helps discover possible problems with out-of-date statistics
  1098. -- Also gives you an idea which indexes are the most active
  1099.  
  1100. -- Look at most frequently modified indexes and statistics (Query 64) (Volatile Indexes)
  1101. SELECT o.name AS [Object Name], o.[object_id], o.type_desc, s.name AS [Statistics Name],
  1102. s.stats_id, s.no_recompute, s.auto_created,
  1103. sp.modification_counter, sp.rows, sp.rows_sampled, sp.last_updated
  1104. FROM sys.objects AS o WITH (NOLOCK)
  1105. INNER JOIN sys.stats AS s WITH (NOLOCK)
  1106. ON s.object_id = o.object_id
  1107. CROSS APPLY sys.dm_db_stats_properties(s.object_id, s.stats_id) AS sp
  1108. WHERE o.type_desc NOT IN (N'SYSTEM_TABLE', N'INTERNAL_TABLE')
  1109. AND sp.modification_counter > 0
  1110. ORDER BY sp.modification_counter DESC, o.name OPTION (RECOMPILE);
  1111.  
  1112. -- Get fragmentation info for all indexes above a certain size in the current database (Query 65) (Index Fragmentation)
  1113. -- Note: This query could take some time on a very large database
  1114. SELECT DB_NAME(ps.database_id) AS [Database Name], OBJECT_NAME(ps.OBJECT_ID) AS [Object Name],
  1115. i.name AS [Index Name], ps.index_id, ps.index_type_desc, ps.avg_fragmentation_in_percent,
  1116. ps.fragment_count, ps.page_count, i.fill_factor, i.has_filter, i.filter_definition
  1117. FROM sys.dm_db_index_physical_stats(DB_ID(),NULL, NULL, NULL , N'LIMITED') AS ps
  1118. INNER JOIN sys.indexes AS i WITH (NOLOCK)
  1119. ON ps.[object_id] = i.[object_id]
  1120. AND ps.index_id = i.index_id
  1121. WHERE ps.database_id = DB_ID()
  1122. AND ps.page_count > 2500
  1123. ORDER BY ps.avg_fragmentation_in_percent DESC OPTION (RECOMPILE);
  1124.  
  1125. -- Helps determine whether you have framentation in your relational indexes
  1126. -- and how effective your index maintenance strategy is
  1127.  
  1128. --- Index Read/Write stats (all tables in current DB) ordered by Reads (Query 66) (Overall Index Usage - Reads)
  1129. SELECT OBJECT_NAME(s.[object_id]) AS [ObjectName], i.name AS [IndexName], i.index_id,
  1130. user_seeks + user_scans + user_lookups AS [Reads], s.user_updates AS [Writes],
  1131. i.type_desc AS [IndexType], i.fill_factor AS [FillFactor], i.has_filter, i.filter_definition,
  1132. s.last_user_scan, s.last_user_lookup, s.last_user_seek
  1133. FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK)
  1134. INNER JOIN sys.indexes AS i WITH (NOLOCK)
  1135. ON s.[object_id] = i.[object_id]
  1136. WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1
  1137. AND i.index_id = s.index_id
  1138. AND s.database_id = DB_ID()
  1139. ORDER BY user_seeks + user_scans + user_lookups DESC OPTION (RECOMPILE); -- Order by reads
  1140.  
  1141. -- Show which indexes in the current database are most active for Reads
  1142.  
  1143. --- Index Read/Write stats (all tables in current DB) ordered by Writes (Query 67) (Overall Index Usage - Writes)
  1144. SELECT OBJECT_NAME(s.[object_id]) AS [ObjectName], i.name AS [IndexName], i.index_id,
  1145. s.user_updates AS [Writes], user_seeks + user_scans + user_lookups AS [Reads],
  1146. i.type_desc AS [IndexType], i.fill_factor AS [FillFactor], i.has_filter, i.filter_definition,
  1147. s.last_system_update, s.last_user_update
  1148. FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK)
  1149. INNER JOIN sys.indexes AS i WITH (NOLOCK)
  1150. ON s.[object_id] = i.[object_id]
  1151. WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1
  1152. AND i.index_id = s.index_id
  1153. AND s.database_id = DB_ID()
  1154. ORDER BY s.user_updates DESC OPTION (RECOMPILE); -- Order by writes
  1155.  
  1156. -- Show which indexes in the current database are most active for Writes
  1157.  
  1158. -- Get lock waits for current database (Query 68) (Lock Waits)
  1159. SELECT o.name AS [table_name], i.name AS [index_name], ios.index_id, ios.partition_number,
  1160. SUM(ios.row_lock_wait_count) AS [total_row_lock_waits],
  1161. SUM(ios.row_lock_wait_in_ms) AS [total_row_lock_wait_in_ms],
  1162. SUM(ios.page_lock_wait_count) AS [total_page_lock_waits],
  1163. SUM(ios.page_lock_wait_in_ms) AS [total_page_lock_wait_in_ms],
  1164. SUM(ios.page_lock_wait_in_ms)+ SUM(row_lock_wait_in_ms) AS [total_lock_wait_in_ms]
  1165. FROM sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) AS ios
  1166. INNER JOIN sys.objects AS o WITH (NOLOCK)
  1167. ON ios.[object_id] = o.[object_id]
  1168. INNER JOIN sys.indexes AS i WITH (NOLOCK)
  1169. ON ios.[object_id] = i.[object_id]
  1170. AND ios.index_id = i.index_id
  1171. WHERE o.[object_id] > 100
  1172. GROUP BY o.name, i.name, ios.index_id, ios.partition_number
  1173. HAVING SUM(ios.page_lock_wait_in_ms)+ SUM(row_lock_wait_in_ms) > 0
  1174. ORDER BY total_lock_wait_in_ms DESC OPTION (RECOMPILE);
  1175.  
  1176. -- This query is helpful for troubleshooting blocking and deadlocking issues
  1177.  
  1178. -- Look at recent Full backups for the current database (Query 69) (Recent Full Backups)
  1179. SELECT TOP (30) bs.machine_name, bs.server_name, bs.database_name AS [Database Name], bs.recovery_model,
  1180. CONVERT (BIGINT, bs.backup_size / 1048576 ) AS [Uncompressed Backup Size (MB)],
  1181. CONVERT (BIGINT, bs.compressed_backup_size / 1048576 ) AS [Compressed Backup Size (MB)],
  1182. CONVERT (NUMERIC (20,2), (CONVERT (FLOAT, bs.backup_size) /
  1183. CONVERT (FLOAT, bs.compressed_backup_size))) AS [Compression Ratio],
  1184. DATEDIFF (SECOND, bs.backup_start_date, bs.backup_finish_date) AS [Backup Elapsed Time (sec)],
  1185. bs.backup_finish_date AS [Backup Finish Date]
  1186. FROM msdb.dbo.backupset AS bs WITH (NOLOCK)
  1187. WHERE DATEDIFF (SECOND, bs.backup_start_date, bs.backup_finish_date) > 0
  1188. AND bs.backup_size > 0
  1189. AND bs.[type] = 'D' -- Change to L if you want Log backups
  1190. AND database_name = DB_NAME(DB_ID())
  1191. ORDER BY bs.backup_finish_date DESC OPTION (RECOMPILE);
  1192.  
  1193. -- Are your backup sizes and times changing over time?
  1194. -- Are you using backup compression?
  1195.  
  1196. -- These three Pluralsight Courses go into more detail about how to run these queries and interpret the results
  1197.  
  1198. -- SQL Server 2014 DMV Diagnostic Queries � Part 1
  1199. -- http://www.pluralsight.com/courses/sql-server-2014-dmv-diagnostic-queries-part1
  1200.  
  1201. -- SQL Server 2014 DMV Diagnostic Queries � Part 2
  1202. -- http://www.pluralsight.com/courses/sql-server-2014-dmv-diagnostic-queries-part2
  1203.  
  1204. -- SQL Server 2014 DMV Diagnostic Queries � Part 3
  1205. -- http://www.pluralsight.com/courses/sql-server-2014-dmv-diagnostic-queries-part3

非常全面的SQL Server巡检脚本来自sqlskills团队的Glenn Berry 大牛的更多相关文章

  1. 非常全面的SQL Server巡检脚本来自sqlskills团队的Glenn Berry

    非常全面的SQL Server巡检脚本来自sqlskills团队的Glenn Berry Glenn Berry 曾承诺对这个脚本持续更新 -- SQL Server 2012 Diagnostic ...

  2. 一行导出所有任意微软SQL server数据脚本-基于Python的微软官方mssql-scripter工具使用全讲解

    文章标题: 一行导出所有任意微软SQL serer数据脚本-基于Python的微软官方mssql-scripter工具使用全讲解 关键字 : mssql-scripter,SQL Server 文章分 ...

  3. 全废话SQL Server统计信息(1)——统计信息简介

    当心空无一物,它便无边无涯.树在.山在.大地在.岁月在.我在.你还要怎样更好的世界?--张晓风<我在> 为什么要写这个内容? 随着工作经历的积累,越来越感觉到,大量的关系型数据库的性能问题 ...

  4. ola.hallengren的SQL Server维护脚本

    ola.hallengren的SQL Server维护脚本 下载地址 http://files.cnblogs.com/files/lyhabc/ola.hallengrenMaintenanceSo ...

  5. sql server 用脚本管理作业

    转自:https://blog.csdn.net/yunye114105/article/details/6594826 摘要: 在SQL SERVER中用脚本管理作业,在绝大部分场景下,脚本都比UI ...

  6. sql server通过脚本进行数据库压缩全备份的方法

    问题:生产环境的数据库可能比较大,如果直接进行全备而不压缩的话,备份集就会占用了大量磁盘空间.给备份文件的存放管理带来不便. 解决方案:通过with compression显式启用备份压缩,指定对此备 ...

  7. 全废话SQL Server统计信息(2)——统计信息基础

    接上文:http://blog.csdn.net/dba_huangzj/article/details/52835958 我想在大地上画满窗子,让所有习惯黑暗的眼睛都习惯光明--顾城<我是一个 ...

  8. PowerDesigner 生成SQL Server 注释脚本

    --生成数据表的注释EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=[%R%?[N]]%.q:COMMENT% , @l ...

  9. sql server 常用脚本(日常查询所需)

    1:查看sql server代理中作业的运行状况的脚本 -- descr : a simple sql script to view sql server jobs run status -- las ...

随机推荐

  1. ubuntu系统怎么分区

    首先科普下windows和linux的文件系统和主分区: 1.电脑的主分最多只有只能由四个.如果是win7和linux双系统,则windows系统可能会占到1-2个主分区,那linux最多只能有两个主 ...

  2. APP产品交互设计资源汇总(不断更新中...)

    Axure RP 7 元件库 http://www.iaxure.com/tag/axure7-0%E5%85%83%E4%BB%B6%E5%BA%93 ios8组合元件库V1.2版 http://w ...

  3. .Net缓存管理框架CacheManager(转)

    转载地址:http://www.cnblogs.com/JustRun1983/p/CacheManager.html Cache缓存在计算机领域是一个被普遍使用的概念.硬件中CPU有一级缓存,二级缓 ...

  4. hellocharts包的使用心得

    首先将jar包导入Libs里面然后add进入于activity中调用 xml中加入布局 <lecho.lib.hellocharts.view.LineChartView android:id= ...

  5. Trigger和ViewStateManager的具体比较

    ViewStateManager的好处  拥有 GeneratedDuration ,可以很方便的进行几个状态之间的切换过渡动画. 坏处是,在界面加载时只能显示默认效果,通过GoToStateActi ...

  6. Objective-C开发编码规范【转载】

    概要 Objective-C是一门面向对象的动态编程语言,主要用于编写iOS和Mac应用程序.关于Objective-C的编码规范,苹果和谷歌都已经有很好的总结: Apple Coding Guide ...

  7. java try(){}catch(){}自动资源释放

    从 Java 7 build 105 版本开始,Java 7 的编译器和运行环境支持新的 try-with-resources 语句,称为 ARM 块(Automatic Resource Manag ...

  8. unity3D脚本中,update ,fixupdate 和lateupdate的区别

    1.MonoBehaviour.Update 更新 当MonoBehaviour启用时,其Update在每一帧被调用. 2.MonoBehaviour.FixedUpdate 固定更新 当MonoBe ...

  9. TDD测试驱动开发

    TDD测试驱动开发 一.概念 TDD故名思意就是用测试的方法驱动开发,简单说就是先写测试代码,再写开发代码.传统的方式是先写代码,再测试,它的开发方式与之正好相反. TDD是极限编程的一个最重要的设计 ...

  10. iPhone开发基础教程_第二章

    1.各个子文件夹的作用        Classes:                    编写的大多代码都保存在这里,其中包括所有的Objective-C类,可以在Classes文件夹下创建一些子 ...