├── Always On Availability Groups └── README.md ├── Azure Data API Builder └── README.md ├── Azure SQL Database └── README.md ├── Backup Types & Recovery Models ├── Backup Percentage.sql ├── Database Properties.sql ├── Database Size History.sql ├── File Sizes and Space.sql ├── Getting VLF Counts.sql ├── README.md └── Recent Full Backups.sql ├── Change Data Capture └── README.md ├── Change Tracking └── README.md ├── Constraints └── README.md ├── Data Compression └── README.md ├── Data Encryption └── README.md ├── Deadlock Analysis ├── Get Deadlock Graph from Extended Events.sql └── README.md ├── Entity Framework Profiler └── README.md ├── Extended Events ├── Active Session DMVs.sql ├── Common Sessions │ ├── capture_delete_statements.sql │ ├── capture_execution_timeout.sql │ ├── capture_truncate_statements.sql │ ├── capture_update_statements.sql │ └── capture_users_queries.sql ├── Event Targets │ ├── event_file.sql │ └── ring_buffer.sql ├── Extended Events Objects │ ├── 01 Packages.sql │ ├── 02 Events.sql │ ├── 03 Predicates.sql │ ├── 04 Actions.sql │ ├── 05 Targets.sql │ └── 06 Types & Maps.sql ├── README.md └── Session Definition Views.sql ├── Fundamentals ├── CURSOR.md ├── Collations.md ├── Common Table Expression (CTE).md ├── JSON.md ├── Sequence.md ├── T-SQL Data Modification │ ├── MERGE.md │ └── README.md ├── T-SQL Data Retrieval │ ├── JOINS.md │ ├── Paging.md │ ├── Window Functions.md │ └── imgs │ │ ├── cross_join.png │ │ ├── full_join.gif │ │ ├── inner_join.gif │ │ ├── left_join.gif │ │ └── right_join.gif ├── T-SQL Error Handling.md └── Table-Valued Parameters.md ├── Glenn Berry's DMV Scripts ├── README.md └── SQL Server 2014 Diagnostic Information Queries (April 2014) │ ├── Query 01 - Getting the Product Version.sql │ ├── Query 02 - When Was SQL Server Installed.sql │ ├── Query 03 - Getting Useful Server Properties.sql │ ├── Query 04 - Getting SQL Server Agent Job Information.sql │ ├── Query 05 - Getting SQL Server Agent Alert Information.sql │ ├── Query 06 - Global Trace Flag Information.sql │ ├── Query 07 - Getting Information About Windows.sql │ ├── Query 08 - SQL Server Services Information.sql │ ├── Query 09 - SQL Server NUMA Node Information.sql │ ├── Query 10 - Getting Hardware Information.sql │ ├── Query 11 - Getting the Server Model Number.sql │ ├── Query 12 - Getting the Processor Description.sql │ ├── Query 13 - SQL Server Error Log Properties.sql │ ├── Query 14 - OS Cluster Properties.sql │ ├── Query 15 - Cluster Node Properties.sql │ ├── Query 16 - Failover Cluster Node with AlwaysOn AG.sql │ ├── Query 17 - Instance Configuration Properties.sql │ ├── Query 18 - Buffer Pool Extension Properties.sql │ ├── Query 19 - Buffer Pool Extension Usage.sql │ ├── Query 20 - TCP Listener States.sql │ ├── Query 21 - Memory Dump Information.sql │ ├── Query 22 - Database Filenames and Paths.sql │ ├── Query 23 - Volume Information.sql │ ├── Query 24 - IO Warnings.sql │ ├── Query 25 - Drive-Level Latency.sql │ ├── Query 26 - IO Latencies by Database File.sql │ ├── Query 27 - Database Properties.sql │ ├── Query 28 - Missing Indexes for All Databases.sql │ ├── Query 29 - Getting VLF Counts.sql │ ├── Query 30 - CPU Usage by Database.sql │ ├── Query 31 - IO Usage by Database.sql │ ├── Query 32 - Total Buffer Usage by Database.sql │ ├── Query 33 - Top Waits.sql │ ├── Query 34 - Signal Waits.sql │ ├── Query 35 - Connection Counts.sql │ ├── Query 36 - Connection Counts by IP Address.sql │ ├── Query 37 - Average Task Counts.sql │ ├── Query 38 - CPU Utilization History.sql │ ├── Query 39 - Top Work Time Queries.sql │ ├── Query 40 - System Memory.sql │ ├── Query 41 - Process Memory.sql │ ├── Query 42 - Page Life Expectancy by NUMA Node.sql │ ├── Query 43 - Memory Grants Pending.sql │ ├── Query 44 - Memory Clerk Usage.sql │ ├── Query 45 - Ad Hoc Queries.sql │ ├── Query 46 - File Sizes and Space.sql │ ├── Query 47 - IO Stats By File.sql │ ├── Query 48 - Query Execution Counts.sql │ ├── Query 49 - SP Execution Counts.sql │ ├── Query 50 - SP Avg Elapsed Time.sql │ ├── Query 51 - SP Avg Elapsed Variable Time.sql │ ├── Query 52 - SP Worker Time.sql │ ├── Query 53 - SP Logical Reads.sql │ ├── Query 54 - SP Physical Reads.sql │ ├── Query 55 - SP Logical Writes.sql │ ├── Query 56 - Top IO Statements.sql │ ├── Query 57 - Bad NC Indexes.sql │ ├── Query 58 - Missing Indexes.sql │ ├── Query 59 - Missing Index Warnings.sql │ ├── Query 60 - Buffer Usage.sql │ ├── Query 61 - Table Sizes.sql │ ├── Query 62 - Table Properties.sql │ ├── Query 63 - Statistics Update.sql │ ├── Query 64 - Index Fragmentation.sql │ ├── Query 65 - Overall Index Usage - Reads.sql │ ├── Query 66 - Overall Index Usage - Writes.sql │ ├── Query 67 - Recent Full Backups.sql │ └── Query 68 - Database Size History.sql ├── Hardware ├── CPU │ └── README.md ├── Memory │ ├── Query 18 - Buffer Pool Extension Properties.sql │ ├── Query 19 - Buffer Pool Extension Usage.sql │ ├── Query 21 - Memory Dump Information.sql │ ├── Query 32 - Total Buffer Usage by Database.sql │ ├── Query 40 - System Memory.sql │ ├── Query 41 - Process Memory.sql │ ├── Query 42 - Page Life Expectancy by NUMA Node.sql │ ├── Query 43 - Memory Grants Pending.sql │ ├── Query 44 - Memory Clerk Usage.sql │ ├── Query 60 - Buffer Usage.sql │ └── README.md ├── README.md └── Storage Subsystem │ ├── Module 3 - IO Related Counters.PerfmonCfg │ ├── Module 3 - Inadequate IO Paths.sql │ ├── Query 22 - Database Filenames and Paths.sql │ ├── Query 23 - Volume Information.sql │ ├── Query 24 - IO Warnings.sql │ ├── Query 25 - Drive-Level Latency.sql │ ├── Query 26 - IO Latencies by Database File.sql │ ├── Query 31 - IO Usage by Database.sql │ ├── Query 47 - IO Stats By File.sql │ ├── Query 61 - Table Sizes.sql │ ├── Query 67 - Recent Full Backups.sql │ ├── Query 68 - Database Size History.sql │ └── README.md ├── Hints └── README.md ├── Indexes ├── 20110715_sp_sqlskills_exposecolsinindexlevels_include_unordered.sql ├── 20110715_sp_sqlskills_sql2008_finddupes_helpindex.sql ├── 20110720_sp_sqlskills_sql2008_finddupes.sql ├── 20170228-sp_sqlskills_exposecolsinindexlevels.sql ├── 20170228-sp_sqlskills_helpindex.sql ├── Index Physical Stats.sql ├── Query 57 - Bad NC Indexes.sql ├── Query 58 - Missing Indexes.sql ├── Query 59 - Missing Index Warnings.sql ├── Query 64 - Index Fragmentation.sql ├── Query 65 - Overall Index Usage - Reads.sql ├── Query 66 - Overall Index Usage - Writes.sql ├── README.md ├── Rebuild or Reorganize Indexes.sql ├── Size of Indexes.sql └── Which Queries Use Which Indexes.sql ├── Locks └── README.md ├── Log Shipping └── README.md ├── Maintenance Plans ├── README.md ├── sp_Maintenance_DeleteOldBackupFiles.sql └── sp_Maintenance_Indexes.sql ├── Memory-Optimized Tables └── README.md ├── Query Plan Analysis ├── Currently Running Queries.sql ├── Examining Query Execution Plans.sql ├── README.md ├── Search Implicit Conversion in Plans.sql ├── Search Query Plans.sql ├── Search Stored Procedures Query Plans.sql ├── Testing Scripts │ └── Implicit Conversion Leading to Index, Table Scan.sql ├── Troubleshooting Scripts │ ├── Queries Execution Stats.sql │ ├── README.md │ ├── Stored Procedures Execution Stats.sql │ ├── Verifying Instance Workload Complexity.sql │ ├── estimated rows vs actual rows.sql │ └── optimize for ad hoc workloads.sql └── imgs │ ├── README.md │ ├── bitmap-32x.gif │ ├── bookmark-lookup-32x.gif │ ├── clustered-index-scan-32x.gif │ ├── clustered-index-seek-32x.gif │ ├── compute-scalar-32x.gif │ ├── concatenation-32x.gif │ ├── filter-32x.gif │ ├── hash-match-32x.gif │ ├── index-seek-32x.gif │ ├── merge-join-32x.gif │ ├── nested-loops-32x.gif │ ├── nonclustered-index-scan-32x.gif │ ├── parallelism-32x.gif │ ├── parallelism-distribute-stream.gif │ ├── parallelism-repartition-stream.gif │ ├── query-tree.png │ ├── rid-nonclust-locate-32x.gif │ ├── sort-32x.gif │ ├── spool-32x.gif │ ├── stream-aggregate-32x.gif │ └── table-scan-32x.gif ├── Query Store ├── 1 Creating Test DB.sql ├── 2 Enabling Query Store.sql ├── README.md └── imgs │ ├── query-store-process-2processor.png │ └── query-store-process-3.png ├── README.md ├── Statistics ├── Query 63 - Statistics Update.sql └── README.md ├── Temporal Tables └── README.md ├── Transaction Isolation Levels └── README.md ├── Transactional Replication ├── README.md ├── compare tables and rows count │ ├── check_last_update.bat │ ├── check_row_count_only.bat │ ├── script-nodate.sql │ └── script-withdate.sql ├── reinitialize.png ├── view-snapshot-agent-status.png └── view-synchronization-status.png ├── Utilities ├── Create Or Alter Stored Procedure.sql ├── Drop If Stored Procedure Exists.sql ├── Generate C# Class From Table.sql ├── Generate C# Classes From Tables.sql ├── Generate C# List of Table Names Constant.sql ├── Generate Sequential Ids.sql ├── Insert If Not Exists Avoid Duplicates.sql ├── Move Data to Archived Table.sql ├── Search Potential Unused Tables.sql ├── Search Text.sql └── Using tables as Queues.sql └── Wait Statistics ├── Blocking ├── Module 4 - Long Term Blocking.sql └── README.md ├── CPU ├── Module 7 - A Thousand Stings Discovery.sql ├── Module 7 - Compilations.PerfmonCfg ├── Module 7 - Observer Overhead.PerfmonCfg ├── Module 7 - Uninvited Parallelism Discovery.sql └── README.md ├── ExaminingLatches.sql ├── ExaminingSpinlocks.sql ├── ExaminingWaitingTasks.sql ├── ExaminingWaits.sql ├── IO ├── Module 3 - Inadequate IO Paths.sql └── README.md ├── Memory ├── Module 5 - Memory Pressure.sql ├── Module 5 - Memory Related Counters.PerfmonCfg ├── Module 5 - Query Execution Memory Issues.sql ├── Module 5 - Query Execution Memory.PerfmonCfg └── README.md ├── Network └── README.md ├── README.md ├── Transaction Log └── README.md ├── imgs ├── scheduler_components.png ├── schedulers.png └── wait_times_definition.png └── tempdb ├── Module 6 - Allocation Page Contention.sql ├── Module 6 - Row Versioning Overhead.sql ├── README.md ├── SQLskills_MonitorTempdbContention_1_CreateXEvent.sql └── SQLskills_MonitorTempdbContention_2_CheckResults.sql /Always On Availability Groups/README.md: -------------------------------------------------------------------------------- 1 | - [What is an Always On availability group? - SQL Server Always On | Microsoft Docs](https://docs.microsoft.com/en-us/sql/database-engine/availability-groups/windows/overview-of-always-on-availability-groups-sql-server?view=sql-server-ver15) 2 | - [What is SQL Server AlwaysOn?](https://www.mssqltips.com/sqlservertip/4717/what-is-sql-server-alwayson/) 3 | - [AlwaysOn Availability Groups, Listener, Named Instances, Port Numbers, etc. – Cloud Data Architect](http://www.dataarchitect.cloud/alwayson-availability-groups-listener-named-instances-port-numbers-etc/) 4 | - [An overview of distributed SQL Server Always On Availability Groups](https://www.sqlshack.com/an-overview-of-distributed-sql-server-always-on-availability-groups/) 5 | - [How to architect a hybrid Microsoft SQL Server solution using distributed availability groups | AWS Database Blog](https://aws.amazon.com/blogs/database/how-to-architect-a-hybrid-microsoft-sql-server-solution-using-distributed-availability-groups/) 6 | - [Multi-region SQL Server deployment using distributed availability groups | AWS Database Blog](https://aws.amazon.com/blogs/database/multi-region-sql-server-deployment-using-distributed-availability-groups/) 7 | -------------------------------------------------------------------------------- /Azure Data API Builder/README.md: -------------------------------------------------------------------------------- 1 | - [Quick API Endpoints Using Data API Builder - YouTube](https://www.youtube.com/watch?v=XQRO_uoGhp4) 2 | - [Build REST & GraphQL APIs in Seconds with VS Code & Data API Builder - YouTube](https://www.youtube.com/watch?v=KcFFRbITAAI) 3 | - [Deploy Data API builder in Azure Container Apps - YouTube](https://www.youtube.com/watch?v=RfyBT6maQd0) 4 | - [Unlocking Database Conversations: Semantic Kernel and Data API Builder in Action - YouTube](https://www.youtube.com/watch?v=UTl4JVE4sLE) 5 | - [Connect your Web App Directly to a Database - YouTube](https://www.youtube.com/watch?v=vNzLSH3VbDc) 6 | - [Secure APIs with Data API Builder, Keycloak, and SQL Server - Azure SQL Devs’ Corner](https://devblogs.microsoft.com/azure-sql/secure-apis-with-data-api-builder-keycloak-and-sql-server/) 7 | -------------------------------------------------------------------------------- /Azure SQL Database/README.md: -------------------------------------------------------------------------------- 1 | ## General Features: 2 | 3 | - How backups are handled 4 | - Improved security features 5 | + Dynamic Data Masking 6 | + Row-Level Security 7 | + Always Encrypted 8 | + Transparent Data Encryption 9 | - Geo-replication 10 | - Elastic database pools 11 | - In-memory support for Premium tier 12 | - Query Store 13 | - Index Advisor 14 | 15 | ## Unsupported Features: 16 | 17 | - SQL Server Agent 18 | - Database Mail 19 | - Events and notifications 20 | - SQL Server Trace / Profiler 21 | - Trace Flags and sp_configure 22 | - Unsupported SQL Server components 23 | + SQL Server Reporting Services (SSRS) 24 | + SQL Server Integration Services (SSIS) 25 | + SQL Server Analysis Services (SSAS) 26 | - Unsupported HA solutions 27 | + Log Shipping 28 | + Database Mirroring 29 | + Availability Groups 30 | 31 | ## Migrations: 32 | - Data Migration Assistant 33 | - SSMS: Export Data-tier Application 34 | - SSMS: Deploy Database to Microsoft Azure SQL Database 35 | 36 | ## Hybrid Solutions: 37 | - Backup to Url 38 | - Stretch Database 39 | - Azure VM 40 | - Managed Backups 41 | - Migrations: 42 | + Backup to Url/ Restore from Url 43 | + Log Shipping 44 | + Database Mirroring 45 | + Availability Groups 46 | + Transactional Replication 47 | 48 | -------------------------------------------------------------------------------- /Backup Types & Recovery Models/Backup Percentage.sql: -------------------------------------------------------------------------------- 1 | 2 | -- https://dba.stackexchange.com/questions/80734/can-i-stop-a-sql-database-backup-after-it-has-already-started 3 | SELECT command, 4 | s.text, 5 | start_time, 6 | percent_complete, 7 | CAST(((DATEDIFF(s,start_time,GetDate()))/3600) as varchar) + ' hour(s), ' 8 | + CAST((DATEDIFF(s,start_time,GetDate())%3600)/60 as varchar) + 'min, ' 9 | + CAST((DATEDIFF(s,start_time,GetDate())%60) as varchar) + ' sec' as running_time, 10 | CAST((estimated_completion_time/3600000) as varchar) + ' hour(s), ' 11 | + CAST((estimated_completion_time %3600000)/60000 as varchar) + 'min, ' 12 | + CAST((estimated_completion_time %60000)/1000 as varchar) + ' sec' as est_time_to_go, 13 | dateadd(second,estimated_completion_time/1000, getdate()) as est_completion_time 14 | FROM sys.dm_exec_requests r 15 | CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) s 16 | WHERE r.command in ('RESTORE DATABASE', 'BACKUP DATABASE', 'RESTORE LOG', 'BACKUP LOG') 17 | 18 | 19 | -------------------------------------------------------------------------------- /Backup Types & Recovery Models/Database Properties.sql: -------------------------------------------------------------------------------- 1 | -- Recovery model, log reuse wait description, log file size, log usage size (Query 27) (Database Properties) 2 | -- and compatibility level for all databases on instance 3 | SELECT db.[name] AS [Database Name], db.recovery_model_desc AS [Recovery Model], db.state_desc, 4 | db.log_reuse_wait_desc AS [Log Reuse Wait Description], 5 | 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)], 6 | CAST(CAST(lu.cntr_value AS FLOAT) / CAST(ls.cntr_value AS FLOAT)AS DECIMAL(18,2)) * 100 AS [Log Used %], 7 | db.[compatibility_level] AS [DB Compatibility Level], db.page_verify_option_desc AS [Page Verify Option], 8 | db.is_auto_create_stats_on, db.is_auto_update_stats_on, db.is_auto_update_stats_async_on, db.is_parameterization_forced, 9 | db.snapshot_isolation_state_desc, db.is_read_committed_snapshot_on, db.is_auto_close_on, db.is_auto_shrink_on, 10 | db.target_recovery_time_in_seconds, db.is_cdc_enabled, db.is_memory_optimized_elevate_to_snapshot_on, db.delayed_durability_desc, 11 | db.is_auto_create_stats_incremental_on 12 | FROM sys.databases AS db WITH (NOLOCK) 13 | INNER JOIN sys.dm_os_performance_counters AS lu WITH (NOLOCK) 14 | ON db.name = lu.instance_name 15 | INNER JOIN sys.dm_os_performance_counters AS ls WITH (NOLOCK) 16 | ON db.name = ls.instance_name 17 | WHERE lu.counter_name LIKE N'Log File(s) Used Size (KB)%' 18 | AND ls.counter_name LIKE N'Log File(s) Size (KB)%' 19 | AND ls.cntr_value > 0 20 | ORDER BY db.[name] OPTION (RECOMPILE); 21 | 22 | -- Things to look at: 23 | -- How many databases are on the instance? 24 | -- What recovery models are they using? 25 | -- What is the log reuse wait description? 26 | -- How full are the transaction logs ? 27 | -- What compatibility level are the databases on? 28 | -- What is the Page Verify Option? (should be CHECKSUM) 29 | -- Is Auto Update Statistics Asynchronously enabled? 30 | -- Make sure auto_shrink and auto_close are not enabled! -------------------------------------------------------------------------------- /Backup Types & Recovery Models/Database Size History.sql: -------------------------------------------------------------------------------- 1 | -- Get the average full backup size by month for the current database (SQL 2012) (Query 66) (Database Size History) 2 | -- This helps you understand your database growth over time 3 | -- Adapted from Erin Stellato 4 | SELECT [database_name] AS [Database], DATEPART(month,[backup_start_date]) AS [Month], 5 | CAST(AVG([backup_size]/1024/1024) AS DECIMAL(15,2)) AS [Backup Size (MB)], 6 | CAST(AVG([compressed_backup_size]/1024/1024) AS DECIMAL(15,2)) AS [Compressed Backup Size (MB)], 7 | CAST(AVG([backup_size]/[compressed_backup_size]) AS DECIMAL(15,2)) AS [Compression Ratio] 8 | FROM msdb.dbo.backupset WITH (NOLOCK) 9 | WHERE [database_name] = DB_NAME(DB_ID()) 10 | AND [type] = 'D' 11 | AND backup_start_date >= DATEADD(MONTH, -12, GETDATE()) 12 | GROUP BY [database_name],DATEPART(mm,[backup_start_date]) OPTION (RECOMPILE); 13 | 14 | -- The Backup Size (MB) (without backup compression) shows the true size of your database over time 15 | -- This helps you track and plan your data size growth 16 | -- It is possible that your data files may be larger on disk due to empty space within those files -------------------------------------------------------------------------------- /Backup Types & Recovery Models/File Sizes and Space.sql: -------------------------------------------------------------------------------- 1 | -- Individual File Sizes and space available for current database (Query 46) (File Sizes and Space) 2 | SELECT f.name AS [File Name] , f.physical_name AS [Physical Name], 3 | CAST((f.size/128.0) AS DECIMAL(15,2)) AS [Total Size in MB], 4 | CAST(f.size/128.0 - CAST(FILEPROPERTY(f.name, 'SpaceUsed') AS int)/128.0 AS DECIMAL(15,2)) 5 | AS [Available Space In MB], [file_id], fg.name AS [Filegroup Name], f.is_percent_growth 6 | FROM sys.database_files AS f WITH (NOLOCK) 7 | LEFT OUTER JOIN sys.data_spaces AS fg WITH (NOLOCK) 8 | ON f.data_space_id = fg.data_space_id OPTION (RECOMPILE); 9 | 10 | -- Look at how large and how full the files are and where they are located 11 | -- Make sure the transaction log is not full!! -------------------------------------------------------------------------------- /Backup Types & Recovery Models/Getting VLF Counts.sql: -------------------------------------------------------------------------------- 1 | -- Get VLF Counts for all databases on the instance (Query 29) (VLF Counts) 2 | -- (adapted from Michelle Ufford) 3 | CREATE TABLE #VLFInfo (RecoveryUnitID int, FileID int, 4 | FileSize bigint, StartOffset bigint, 5 | FSeqNo bigint, [Status] bigint, 6 | Parity bigint, CreateLSN numeric(38)); 7 | 8 | CREATE TABLE #VLFCountResults(DatabaseName sysname, VLFCount int); 9 | 10 | EXEC sp_MSforeachdb N'Use [?]; 11 | 12 | INSERT INTO #VLFInfo 13 | EXEC sp_executesql N''DBCC LOGINFO([?])''; 14 | 15 | INSERT INTO #VLFCountResults 16 | SELECT DB_NAME(), COUNT(*) 17 | FROM #VLFInfo; 18 | 19 | TRUNCATE TABLE #VLFInfo;' 20 | 21 | SELECT DatabaseName, VLFCount 22 | FROM #VLFCountResults 23 | ORDER BY VLFCount DESC; 24 | 25 | DROP TABLE #VLFInfo; 26 | DROP TABLE #VLFCountResults; 27 | 28 | -- High VLF counts can affect write performance 29 | -- and they can make database restores and recovery take much longer 30 | -- Try to keep your VLF counts under 200 in most cases -------------------------------------------------------------------------------- /Backup Types & Recovery Models/README.md: -------------------------------------------------------------------------------- 1 | ## Docs & Articles: 2 | 3 | [Recovery Models (SQL Server)](https://docs.microsoft.com/en-us/sql/relational-databases/backup-restore/recovery-models-sql-server?view=sql-server-2017) 4 | 5 | [Backup Types](https://www.easeus.com/backup-utility/sql-backup-types.html) 6 | 7 | [Why Does the Transaction Log Keep Growing or Run Out of Space?](https://dba.stackexchange.com/questions/29829/why-does-the-transaction-log-keep-growing-or-run-out-of-space) 8 | 9 | [Learn How SQL Server Large Transaction Log Affect Performance](https://alessandroalpi.blog/2017/04/04/learn-how-sql-server-large-transaction-log-affect-performance/) 10 | 11 | [Back Up Transaction Logs Every Minute. Yes, Really.](https://www.brentozar.com/archive/2014/02/back-transaction-logs-every-minute-yes-really/) 12 | 13 | 14 | ## Pluralsight: 15 | [SQL Server: Understanding and Performing Backups](https://www.pluralsight.com/courses/sqlserver-understanding-performing-backups) 16 | 17 | [SQL Server: Logging, Recovery, and the Transaction Log](https://www.pluralsight.com/courses/sqlserver-logging) 18 | 19 | ## Troubleshooting Scripts: 20 | [Backup Percentage](https://github.com/phongnguyend/sql-server-kit/blob/master/Backup%20Types%20%26%20Recovery%20Models/Backup%20Percentage.sql) 21 | 22 | [Database Properties](https://github.com/phongnguyend/sql-server-kit/blob/master/Backup%20Types%20%26%20Recovery%20Models/Database%20Properties.sql) 23 | 24 | [File Sizes and Space](https://github.com/phongnguyend/sql-server-kit/blob/master/Backup%20Types%20%26%20Recovery%20Models/File%20Sizes%20and%20Space.sql) 25 | 26 | [Getting VLF Counts](https://github.com/phongnguyend/sql-server-kit/blob/master/Backup%20Types%20%26%20Recovery%20Models/Getting%20VLF%20Counts.sql) 27 | 28 | [Database Size History](https://github.com/phongnguyend/sql-server-kit/blob/master/Backup%20Types%20%26%20Recovery%20Models/Database%20Size%20History.sql) 29 | 30 | [Recent Full Backups](https://github.com/phongnguyend/sql-server-kit/blob/master/Backup%20Types%20%26%20Recovery%20Models/Recent%20Full%20Backups.sql) 31 | 32 | -------------------------------------------------------------------------------- /Backup Types & Recovery Models/Recent Full Backups.sql: -------------------------------------------------------------------------------- 1 | -- Look at recent Full backups for the current database (Query 65) (Recent Full Backups) 2 | SELECT TOP (30) bs.machine_name, bs.server_name, bs.database_name AS [Database Name], bs.recovery_model, 3 | CONVERT (BIGINT, bs.backup_size / 1048576 ) AS [Uncompressed Backup Size (MB)], 4 | CONVERT (BIGINT, bs.compressed_backup_size / 1048576 ) AS [Compressed Backup Size (MB)], 5 | CONVERT (NUMERIC (20,2), (CONVERT (FLOAT, bs.backup_size) / 6 | CONVERT (FLOAT, bs.compressed_backup_size))) AS [Compression Ratio], 7 | DATEDIFF (SECOND, bs.backup_start_date, bs.backup_finish_date) AS [Backup Elapsed Time (sec)], 8 | bs.backup_finish_date AS [Backup Finish Date], 9 | bs.is_copy_only, 10 | f.logical_device_name, 11 | f.physical_device_name 12 | FROM msdb.dbo.backupset AS bs WITH (NOLOCK) 13 | INNER JOIN msdb.dbo.backupmediafamily f ON f.media_set_id = bs.media_set_id 14 | WHERE DATEDIFF (SECOND, bs.backup_start_date, bs.backup_finish_date) > 0 15 | AND bs.backup_size > 0 16 | AND bs.type = 'D' -- Change to L if you want Log backups 17 | AND database_name = DB_NAME(DB_ID()) 18 | ORDER BY bs.backup_finish_date DESC OPTION (RECOMPILE); 19 | 20 | -- Are your backup sizes and times changing over time? 21 | -------------------------------------------------------------------------------- /Change Data Capture/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Change Tracking/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Constraints/README.md: -------------------------------------------------------------------------------- 1 | ### Default Constraints: 2 | ```sql 3 | SELECT OBJECT_NAME(parent_object_id) AS TableName 4 | ,cl.name AS ColumnName 5 | ,type.name AS Type 6 | ,ct.DEFINITION 7 | FROM sys.default_constraints ct 8 | JOIN sys.columns cl ON ct.parent_column_id = cl.column_id 9 | AND ct.parent_object_id = cl.object_id 10 | JOIN sys.types type ON cl.user_type_id = type.user_type_id 11 | ORDER BY TableName 12 | OPTION (RECOMPILE); 13 | ``` 14 | 15 | ### Key Constraints: 16 | ```sql 17 | SELECT K.TABLE_NAME AS TableName 18 | ,K.COLUMN_NAME AS ColumnName 19 | ,K.CONSTRAINT_NAME AS ConstaintName 20 | FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS C 21 | JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS K ON C.TABLE_NAME = K.TABLE_NAME 22 | AND C.CONSTRAINT_CATALOG = K.CONSTRAINT_CATALOG 23 | AND C.CONSTRAINT_SCHEMA = K.CONSTRAINT_SCHEMA 24 | AND C.CONSTRAINT_NAME = K.CONSTRAINT_NAME 25 | WHERE C.CONSTRAINT_TYPE = 'PRIMARY KEY' 26 | OPTION (RECOMPILE); 27 | ``` 28 | -------------------------------------------------------------------------------- /Data Compression/README.md: -------------------------------------------------------------------------------- 1 | [Data Compression - SQL Server | Microsoft Docs](https://docs.microsoft.com/en-us/sql/relational-databases/data-compression/data-compression) 2 | 3 | ### Estimate Data Compression Savings 4 | ```sql 5 | -- ROW Compression: 6 | EXEC sp_estimate_data_compression_savings 7 |     @schema_name = 'dbo', 8 |     @object_name = 'TableName', 9 |     @index_id = NULL, 10 |     @partition_number = NULL, 11 |     @data_compression = 'ROW' 12 | GO 13 | ``` 14 | ```sql 15 | -- PAGE Compression: 16 | EXEC sp_estimate_data_compression_savings 17 |     @schema_name = 'dbo', 18 |     @object_name = 'TableName', 19 |     @index_id = NULL, 20 |     @partition_number = NULL, 21 |     @data_compression = 'PAGE' 22 | GO 23 | ``` 24 | -------------------------------------------------------------------------------- /Data Encryption/README.md: -------------------------------------------------------------------------------- 1 | 2 | [SQL Server Encryption](https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/sql-server-encryption) 3 | 4 | [Transparent Data Encryption (TDE)](https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/transparent-data-encryption) 5 | 6 | [Always Encrypted (Database Engine)](https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/always-encrypted-database-engine) 7 | -------------------------------------------------------------------------------- /Deadlock Analysis/Get Deadlock Graph from Extended Events.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Deadlock Analysis/Get Deadlock Graph from Extended Events.sql -------------------------------------------------------------------------------- /Deadlock Analysis/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Deadlock Analysis/README.md -------------------------------------------------------------------------------- /Entity Framework Profiler/README.md: -------------------------------------------------------------------------------- 1 | ```c# 2 | public class StackTraceInterceptor : DbCommandInterceptor 3 | { 4 | public static void Initialize() 5 | { 6 | if (ConfigurationManager.AppSettings["Tracing.EnableStackTraceInterceptor"] == "true") 7 | { 8 | var includedNameSpace = "YourNameSpace."; 9 | DbInterception.Add(new StackTraceInterceptor(includedNameSpace)); 10 | } 11 | } 12 | 13 | private string _includedNameSpace; 14 | 15 | public StackTraceInterceptor(string includedNameSpace) 16 | { 17 | _includedNameSpace = includedNameSpace; 18 | } 19 | 20 | public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) 21 | { 22 | command.CommandText = AddStackTrace(command.CommandText); 23 | } 24 | 25 | public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) 26 | { 27 | command.CommandText = AddStackTrace(command.CommandText); 28 | } 29 | 30 | public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) 31 | { 32 | command.CommandText = AddStackTrace(command.CommandText); 33 | } 34 | 35 | private string AddStackTrace(string query) 36 | { 37 | bool SELECT_WITHOUT_WHERE = query.Contains("SELECT") && !query.Contains("WHERE"); 38 | bool WHERE_XX_IN_XX = query.Contains("SELECT") && query.Contains("WHERE") && query.Contains(" IN ("); 39 | 40 | bool needToAddStackTrace = SELECT_WITHOUT_WHERE || WHERE_XX_IN_XX; 41 | 42 | if (!needToAddStackTrace) 43 | return query; 44 | 45 | var stackTrace = string.Join("\n", Environment.StackTrace.Split('\n') 46 | .Where(line => !line.Contains(".StackTraceInterceptor.")) 47 | .Where(line => string.IsNullOrWhiteSpace(_includedNameSpace) || line.Contains(_includedNameSpace)) 48 | .Select(x => "-- " + x)); 49 | 50 | return query += Environment.NewLine + stackTrace + Environment.NewLine; 51 | } 52 | } 53 | ``` 54 | 55 | ```c# 56 | public static void Main(string[] args) 57 | { 58 | StackTraceInterceptor.Initialize(); 59 | .... 60 | } 61 | ``` 62 | 63 | ```c# 64 | protected void Application_Start() 65 | { 66 | StackTraceInterceptor.Initialize(); 67 | .... 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /Extended Events/Active Session DMVs.sql: -------------------------------------------------------------------------------- 1 | -- Event Information for a running session 2 | SELECT [s].[name] AS session_name, 3 | [e].[event_name] AS event_name, 4 | [e].[event_predicate] AS event_predicate, 5 | [ea].[action_name] AS action_name 6 | FROM [sys].[dm_xe_sessions] AS s 7 | INNER JOIN [sys].[dm_xe_session_events] AS e 8 | ON [s].[address] = [e].[event_session_address] 9 | INNER JOIN [sys].[dm_xe_session_event_actions] AS ea 10 | ON [e].[event_session_address] = [ea].[event_session_address] AND 11 | [e].[event_name] = [ea].[event_name] ; 12 | 13 | -- Target information for a running session 14 | SELECT [s].[name] AS session_name, 15 | [t].[target_name] AS target_name, 16 | [t].[execution_count] AS execution_count, 17 | [t].[execution_duration_ms] AS execution_duration, 18 | CAST([t].[target_data] AS XML) AS target_data 19 | FROM [sys].[dm_xe_sessions] AS s 20 | INNER JOIN [sys].[dm_xe_session_targets] AS t 21 | ON [s].[address] = [t].[event_session_address] ; 22 | 23 | -- Configurable event and target column information 24 | SELECT DISTINCT 25 | [s].[name] AS session_name, 26 | [oc].[object_name], 27 | [oc].[object_type], 28 | [oc].[column_name], 29 | [oc].[column_value] 30 | FROM [sys].[dm_xe_sessions] AS s 31 | INNER JOIN [sys].[dm_xe_session_targets] AS t 32 | ON [s].[address] = [t].[event_session_address] 33 | INNER JOIN [sys].[dm_xe_session_events] AS e 34 | ON [s].[address] = [e].[event_session_address] 35 | INNER JOIN [sys].[dm_xe_session_object_columns] AS oc 36 | ON [s].[address] = [oc].[event_session_address] AND 37 | (([oc].[object_type] = N'target' AND 38 | [t].[target_name] = [oc].[object_name]) OR 39 | ([oc].[object_type] = N'event' AND 40 | [e].[event_name] = [oc].[object_name])) ; 41 | -------------------------------------------------------------------------------- /Extended Events/Common Sessions/capture_delete_statements.sql: -------------------------------------------------------------------------------- 1 | CREATE EVENT SESSION [capture_delete_statements] ON SERVER ADD EVENT sqlserver.sp_statement_completed ( 2 | SET collect_object_name = (1) 3 | ,collect_statement = (1) ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name, sqlserver.nt_username, sqlserver.server_instance_name, sqlserver.server_principal_name, sqlserver.session_id, sqlserver.session_nt_username, sqlserver.sql_text, sqlserver.username) WHERE ( 4 | [sqlserver].[database_name] = N'DBName' 5 | AND [sqlserver].[client_app_name] != N'.Net SqlClient Data Provider' 6 | AND [statement] LIKE N'%DELETE%' 7 | ) 8 | ) 9 | ,ADD EVENT sqlserver.sql_statement_completed ( 10 | SET collect_statement = (1) ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name, sqlserver.nt_username, sqlserver.server_instance_name, sqlserver.server_principal_name, sqlserver.session_id, sqlserver.session_nt_username, sqlserver.sql_text, sqlserver.username) WHERE ( 11 | [package0].[equal_boolean]([sqlserver].[is_system], (0)) 12 | AND [sqlserver].[database_name] = N'DBName' 13 | AND [sqlserver].[client_app_name] != N'.Net SqlClient Data Provider' 14 | AND [sqlserver].[sql_text] LIKE N'%DELETE%' 15 | ) 16 | ) ADD TARGET package0.event_file ( 17 | SET filename = N'capture_delete_statements' 18 | ,max_file_size = (10) 19 | ) 20 | WITH ( 21 | MAX_MEMORY = 4096 KB 22 | ,EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS 23 | ,MAX_DISPATCH_LATENCY = 30 SECONDS 24 | ,MAX_EVENT_SIZE = 0 KB 25 | ,MEMORY_PARTITION_MODE = NONE 26 | ,TRACK_CAUSALITY = OFF 27 | ,STARTUP_STATE = ON 28 | ) 29 | GO -------------------------------------------------------------------------------- /Extended Events/Common Sessions/capture_execution_timeout.sql: -------------------------------------------------------------------------------- 1 | CREATE EVENT SESSION [execution_timeout] 2 | ON SERVER 3 | ADD EVENT sqlserver.attention ( 4 | ACTION ( 5 | sqlos.task_time, 6 | sqlserver.client_app_name, 7 | sqlserver.client_hostname, 8 | sqlserver.database_id, 9 | sqlserver.database_name, 10 | sqlserver.session_id, 11 | sqlserver.sql_text, 12 | sqlserver.username 13 | ) 14 | WHERE ( 15 | [package0].[equal_boolean]([sqlserver].[is_system], (0)) 16 | AND [sqlserver].[client_app_name] = N'.Net SqlClient Data Provider' 17 | AND [sqlserver].[database_name] = N'DBName' 18 | ) 19 | ) 20 | ADD TARGET package0.event_file ( 21 | SET filename = N'execution_timeout.xel', 22 | max_file_size = (5), 23 | max_rollover_files = (2) 24 | ) 25 | WITH ( 26 | MAX_MEMORY = 4096 KB, 27 | EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS, 28 | MAX_DISPATCH_LATENCY = 30 SECONDS, 29 | MAX_EVENT_SIZE = 0 KB, 30 | MEMORY_PARTITION_MODE = NONE, 31 | TRACK_CAUSALITY = OFF, 32 | STARTUP_STATE = ON 33 | ) 34 | GO -------------------------------------------------------------------------------- /Extended Events/Common Sessions/capture_truncate_statements.sql: -------------------------------------------------------------------------------- 1 | CREATE EVENT SESSION [capture_truncate_statements] ON SERVER ADD EVENT sqlserver.sp_statement_completed ( 2 | SET collect_object_name = (1) 3 | ,collect_statement = (1) ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name, sqlserver.nt_username, sqlserver.server_instance_name, sqlserver.server_principal_name, sqlserver.session_id, sqlserver.session_nt_username, sqlserver.sql_text, sqlserver.username) WHERE ( 4 | [sqlserver].[database_name] = N'DBName' 5 | AND [sqlserver].[client_app_name] != N'.Net SqlClient Data Provider' 6 | AND [statement] LIKE N'%TRUNCATE%' 7 | ) 8 | ) 9 | ,ADD EVENT sqlserver.sql_statement_completed ( 10 | SET collect_statement = (1) ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name, sqlserver.nt_username, sqlserver.server_instance_name, sqlserver.server_principal_name, sqlserver.session_id, sqlserver.session_nt_username, sqlserver.sql_text, sqlserver.username) WHERE ( 11 | [package0].[equal_boolean]([sqlserver].[is_system], (0)) 12 | AND [sqlserver].[database_name] = N'DBName' 13 | AND [sqlserver].[client_app_name] != N'.Net SqlClient Data Provider' 14 | AND [sqlserver].[sql_text] LIKE N'%TRUNCATE%' 15 | ) 16 | ) ADD TARGET package0.event_file ( 17 | SET filename = N'capture_truncate_statements' 18 | ,max_file_size = (10) 19 | ) 20 | WITH ( 21 | MAX_MEMORY = 4096 KB 22 | ,EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS 23 | ,MAX_DISPATCH_LATENCY = 30 SECONDS 24 | ,MAX_EVENT_SIZE = 0 KB 25 | ,MEMORY_PARTITION_MODE = NONE 26 | ,TRACK_CAUSALITY = OFF 27 | ,STARTUP_STATE = ON 28 | ) 29 | GO -------------------------------------------------------------------------------- /Extended Events/Common Sessions/capture_update_statements.sql: -------------------------------------------------------------------------------- 1 | CREATE EVENT SESSION [capture_update_statements] ON SERVER ADD EVENT sqlserver.sp_statement_completed ( 2 | SET collect_object_name = (1) 3 | ,collect_statement = (1) ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name, sqlserver.nt_username, sqlserver.server_instance_name, sqlserver.server_principal_name, sqlserver.session_id, sqlserver.session_nt_username, sqlserver.sql_text, sqlserver.username) WHERE ( 4 | [sqlserver].[database_name] = N'DBName' 5 | AND [sqlserver].[client_app_name] != N'.Net SqlClient Data Provider' 6 | AND [statement] LIKE N'%UPDATE%SET%' 7 | ) 8 | ) 9 | ,ADD EVENT sqlserver.sql_statement_completed ( 10 | SET collect_statement = (1) ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name, sqlserver.nt_username, sqlserver.server_instance_name, sqlserver.server_principal_name, sqlserver.session_id, sqlserver.session_nt_username, sqlserver.sql_text, sqlserver.username) WHERE ( 11 | [package0].[equal_boolean]([sqlserver].[is_system], (0)) 12 | AND [sqlserver].[database_name] = N'DBName' 13 | AND [sqlserver].[client_app_name] != N'.Net SqlClient Data Provider' 14 | AND [sqlserver].[sql_text] LIKE N'%UPDATE%SET%' 15 | ) 16 | ) ADD TARGET package0.event_file ( 17 | SET filename = N'capture_update_statements' 18 | ,max_file_size = (10) 19 | ) 20 | WITH ( 21 | MAX_MEMORY = 4096 KB 22 | ,EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS 23 | ,MAX_DISPATCH_LATENCY = 30 SECONDS 24 | ,MAX_EVENT_SIZE = 0 KB 25 | ,MEMORY_PARTITION_MODE = NONE 26 | ,TRACK_CAUSALITY = OFF 27 | ,STARTUP_STATE = ON 28 | ) 29 | GO 30 | -------------------------------------------------------------------------------- /Extended Events/Common Sessions/capture_users_queries.sql: -------------------------------------------------------------------------------- 1 | CREATE EVENT SESSION [capture_users_queries] ON SERVER ADD EVENT sqlserver.sp_statement_completed ( 2 | SET collect_object_name = (1) 3 | ,collect_statement = (1) ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name, sqlserver.nt_username, sqlserver.server_instance_name, sqlserver.server_principal_name, sqlserver.session_id, sqlserver.session_nt_username, sqlserver.sql_text, sqlserver.username) WHERE ( 4 | [sqlserver].[database_name] = N'DBName' 5 | AND [sqlserver].[client_app_name] != N'.Net SqlClient Data Provider' 6 | ) 7 | ) 8 | ,ADD EVENT sqlserver.sql_statement_completed ( 9 | SET collect_statement = (1) ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name, sqlserver.nt_username, sqlserver.server_instance_name, sqlserver.server_principal_name, sqlserver.session_id, sqlserver.session_nt_username, sqlserver.sql_text, sqlserver.username) WHERE ( 10 | [package0].[equal_boolean]([sqlserver].[is_system], (0)) 11 | AND [sqlserver].[database_name] = N'DBName' 12 | AND [sqlserver].[client_app_name] != N'.Net SqlClient Data Provider' 13 | ) 14 | ) ADD TARGET package0.event_file ( 15 | SET filename = N'capture_users_queries' 16 | ,max_file_size = (10) 17 | ) 18 | WITH ( 19 | MAX_MEMORY = 4096 KB 20 | ,EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS 21 | ,MAX_DISPATCH_LATENCY = 30 SECONDS 22 | ,MAX_EVENT_SIZE = 0 KB 23 | ,MEMORY_PARTITION_MODE = NONE 24 | ,TRACK_CAUSALITY = OFF 25 | ,STARTUP_STATE = ON 26 | ) 27 | GO 28 | -------------------------------------------------------------------------------- /Extended Events/Event Targets/event_file.sql: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Extended Events/Event Targets/ring_buffer.sql: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Extended Events/Extended Events Objects/01 Packages.sql: -------------------------------------------------------------------------------- 1 | -- View Extended Event packages 2 | SELECT * 3 | FROM [sys].[dm_xe_packages] p 4 | WHERE ([p].[capabilities] IS NULL OR 5 | [p].[capabilities] & 1 = 0); 6 | 7 | -- View the module that loaded the packages 8 | SELECT [p].[name] AS [package_name], 9 | [p].[guid] AS [package_guid], 10 | [p].[description], 11 | [olm].[name] AS [module] 12 | FROM [sys].[dm_xe_packages] AS p 13 | INNER JOIN [sys].[dm_os_loaded_modules] AS olm 14 | ON [p].[module_address] = [olm].[base_address] 15 | WHERE ([p].[capabilities] IS NULL OR 16 | [p].[capabilities] & 1 = 0) 17 | ORDER BY [p].[name] ; 18 | -------------------------------------------------------------------------------- /Extended Events/Extended Events Objects/02 Events.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Event objects 3 | SELECT [p].[name] AS package_name, 4 | [o].[name] AS event_name, 5 | [o].[description] 6 | FROM [sys].[dm_xe_packages] AS p 7 | INNER JOIN [sys].[dm_xe_objects] AS o 8 | ON [p].[guid] = [o].[package_guid] 9 | WHERE ([p].[capabilities] IS NULL OR 10 | [p].[capabilities] & 1 = 0) AND 11 | ([o].[capabilities] IS NULL OR 12 | [o].[capabilities] & 1 = 0) AND 13 | [o].[object_type] = N'event' ; 14 | 15 | -- Event Columns 16 | SELECT [oc].[name] AS column_name, 17 | [oc].[column_type] AS column_type, 18 | [oc].[column_value] AS column_value, 19 | [oc].[description] AS column_description 20 | FROM [sys].[dm_xe_packages] AS p 21 | INNER JOIN [sys].[dm_xe_objects] AS o 22 | ON [p].[guid] = [o].[package_guid] 23 | INNER JOIN [sys].[dm_xe_object_columns] AS oc 24 | ON [o].[name] = [oc].[object_name] AND 25 | [o].[package_guid] = [oc].[object_package_guid] 26 | WHERE ([p].[capabilities] IS NULL OR 27 | [p].[capabilities] & 1 = 0) AND 28 | ([o].[capabilities] IS NULL OR 29 | [o].[capabilities] & 1 = 0) AND 30 | ([oc].[capabilities] IS NULL OR 31 | [oc].[capabilities] & 1 = 0) AND 32 | [o].[object_type] = N'event' AND 33 | [o].[name] = N'wait_info' ; 34 | 35 | -- Look at available customizable columns 36 | SELECT [o].[name] AS event_name, 37 | [oc].[name] AS column_name, 38 | [oc].[column_value], 39 | [oc].[description] 40 | FROM [sys].[dm_xe_packages] AS p 41 | INNER JOIN [sys].[dm_xe_objects] AS o 42 | ON [p].[guid] = [o].[package_guid] 43 | INNER JOIN [sys].[dm_xe_object_columns] AS oc 44 | ON [o].[package_guid] = [oc].[object_package_guid] AND 45 | [o].[name] = [oc].[object_name] 46 | WHERE ([p].[capabilities] IS NULL OR 47 | [p].[capabilities] & 1 = 0) AND 48 | ([o].[capabilities] IS NULL OR 49 | [o].[capabilities] & 1 = 0) AND 50 | ([oc].[capabilities] IS NULL OR 51 | [oc].[capabilities] & 1 = 0) AND 52 | [o].[object_type] = N'event' AND 53 | [oc].[column_type] = N'customizable' ; 54 | 55 | -------------------------------------------------------------------------------- /Extended Events/Extended Events Objects/05 Targets.sql: -------------------------------------------------------------------------------- 1 | -- Targets 2 | SELECT [p].[name] AS package_name, 3 | [o].[name] AS target_name, 4 | [o].[description] 5 | FROM [sys].[dm_xe_packages] AS p 6 | INNER JOIN [sys].[dm_xe_objects] AS o 7 | ON [p].[guid] = [o].[package_guid] 8 | WHERE ([p].[capabilities] IS NULL OR 9 | [p].[capabilities] & 1 = 0) AND 10 | ([o].[capabilities] IS NULL OR 11 | [o].[capabilities] & 1 = 0) AND 12 | [o].[object_type] = N'target' ; 13 | 14 | -- Target Columns 15 | SELECT [oc].[name] AS column_name, 16 | [oc].[column_id], 17 | [oc].[type_name], 18 | [oc].[capabilities_desc], 19 | [oc].[description] 20 | FROM [sys].[dm_xe_packages] AS p 21 | INNER JOIN [sys].[dm_xe_objects] AS o 22 | ON [p].[guid] = [o].[package_guid] 23 | INNER JOIN [sys].[dm_xe_object_columns] AS oc 24 | ON [o].[name] = [oc].[object_name] AND 25 | [o].[package_guid] = [oc].[object_package_guid] 26 | WHERE ([p].[capabilities] IS NULL OR 27 | [p].[capabilities] & 1 = 0) AND 28 | ([o].[capabilities] IS NULL OR 29 | [o].[capabilities] & 1 = 0) AND 30 | [o].[object_type] = N'target' AND 31 | [o].[name] = N'event_file' ; 32 | -------------------------------------------------------------------------------- /Extended Events/Extended Events Objects/06 Types & Maps.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Types 3 | SELECT [p].[name] AS package_name, 4 | [o].[name] AS target_name, 5 | [o].[description] 6 | FROM [sys].[dm_xe_packages] AS p 7 | INNER JOIN [sys].[dm_xe_objects] AS o 8 | ON [p].[guid] = [o].[package_guid] 9 | WHERE ([p].[capabilities] IS NULL OR 10 | [p].[capabilities] & 1 = 0) AND 11 | ([o].[capabilities] IS NULL OR 12 | [o].[capabilities] & 1 = 0) AND 13 | [o].[object_type] = N'type' ; 14 | 15 | -- Maps 16 | SELECT [p].[name] AS package_name, 17 | [o].[name] AS action_name, 18 | [o].[description] 19 | FROM [sys].[dm_xe_packages] AS p 20 | INNER JOIN [sys].[dm_xe_objects] AS o 21 | ON [p].[guid] = [o].[package_guid] 22 | WHERE ([p].[capabilities] IS NULL OR 23 | [p].[capabilities] & 1 = 0) AND 24 | ([o].[capabilities] IS NULL OR 25 | [o].[capabilities] & 1 = 0) AND 26 | [o].[object_type] = N'map' ; 27 | 28 | -- Show mapped columns 29 | SELECT [oc].[name] AS column_name, 30 | [oc].[type_name] AS [type_name], 31 | [o2].[object_type] AS [object_type] 32 | FROM [sys].[dm_xe_packages] AS p 33 | INNER JOIN [sys].[dm_xe_objects] AS o 34 | ON [p].[guid] = [o].[package_guid] 35 | INNER JOIN [sys].[dm_xe_object_columns] AS oc 36 | ON [o].[name] = [oc].[object_name] AND 37 | [o].[package_guid] = [oc].[object_package_guid] 38 | INNER JOIN [sys].[dm_xe_objects] AS o2 39 | ON [oc].[type_name] = [o2].[name] AND 40 | [oc].[type_package_guid] = [o2].[package_guid] AND 41 | [o2].[object_type] IN ('map', 'type') 42 | WHERE ([p].[capabilities] IS NULL OR 43 | [p].[capabilities] & 1 = 0) AND 44 | ([o].[capabilities] IS NULL OR 45 | [o].[capabilities] & 1 = 0) AND 46 | ([oc].[capabilities] IS NULL OR 47 | [oc].[capabilities] & 1 = 0) AND 48 | [o].[object_type] = N'event' AND 49 | [o].[name] = N'wait_info' AND 50 | [oc].[column_type] = N'data' ; 51 | 52 | -- Map Values 53 | SELECT [mv].[name], 54 | [mv].[map_key], 55 | [mv].[map_value] 56 | FROM [sys].[dm_xe_map_values] AS mv 57 | WHERE [mv].[name] = N'wait_types' ; 58 | -------------------------------------------------------------------------------- /Extended Events/README.md: -------------------------------------------------------------------------------- 1 | ## Troubleshooting Timeout Issue with XEvent 2 | 3 | [SQL SERVER – Timeout expired. The timeout period elapsed prior to completion of the operation](https://blog.sqlauthority.com/2016/01/26/sql-server-timeout-expired-the-timeout-period-elapsed-prior-to-completion-of-the-operation-or-the-server-is-not-responding/) 4 | 5 | [Connection timeout and Command timeout in SQL Server](https://blogs.msdn.microsoft.com/docast/2018/10/11/connection-timeout-and-command-timeout-in-sql-server/) 6 | 7 | [Troubleshooting Query timeouts in SQL Server](https://blogs.msdn.microsoft.com/docast/2018/10/12/troubleshooting-query-timeouts-in-sql-server/) 8 | 9 | [How to detect query timeout errors with Extended Events](http://blog.sqlgrease.com/how-to-detect-query-timeout-errors-with-extended-events/) 10 | 11 | [How To Capture Query Timeouts With Extended Events](https://dbtut.com/index.php/2019/01/23/how-to-capture-query-timeouts-with-extended-events/) 12 | 13 | [Attention Event Class](https://docs.microsoft.com/en-us/sql/relational-databases/event-classes/attention-event-class?view=sql-server-2017) 14 | 15 | ```sql 16 | CREATE EVENT SESSION [execution_timeout] 17 | ON SERVER 18 | ADD EVENT sqlserver.attention ( 19 | ACTION ( 20 | sqlos.task_time, 21 | sqlserver.client_app_name, 22 | sqlserver.client_hostname, 23 | sqlserver.database_id, 24 | sqlserver.database_name, 25 | sqlserver.session_id, 26 | sqlserver.sql_text, 27 | sqlserver.username 28 | ) 29 | WHERE ( 30 | [package0].[equal_boolean]([sqlserver].[is_system], (0)) 31 | AND [sqlserver].[client_app_name] = N'.Net SqlClient Data Provider' 32 | AND [sqlserver].[database_name] = N'DBName' 33 | ) 34 | ) 35 | ADD TARGET package0.event_file ( 36 | SET filename = N'execution_timeout.xel', 37 | max_file_size = (5), 38 | max_rollover_files = (2) 39 | ) 40 | WITH ( 41 | MAX_MEMORY = 4096 KB, 42 | EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS, 43 | MAX_DISPATCH_LATENCY = 30 SECONDS, 44 | MAX_EVENT_SIZE = 0 KB, 45 | MEMORY_PARTITION_MODE = NONE, 46 | TRACK_CAUSALITY = OFF, 47 | STARTUP_STATE = ON 48 | ) 49 | GO 50 | ``` 51 | -------------------------------------------------------------------------------- /Extended Events/Session Definition Views.sql: -------------------------------------------------------------------------------- 1 | -- Get events in a session 2 | SELECT [sese].[package] AS event_package, 3 | [sese].[name] AS event_name, 4 | [sese].[predicate] AS event_predicate 5 | FROM [sys].[server_event_sessions] AS ses 6 | INNER JOIN [sys].[server_event_session_events] AS sese 7 | ON [ses].[event_session_id] = [sese].[event_session_id] 8 | WHERE [ses].[name] = N'system_health' ; 9 | 10 | -- Get actions 11 | SELECT [sese].[package] AS event_package, 12 | [sese].[name] AS event_name, 13 | [sese].[predicate] AS event_predicate, 14 | [sesa].[package] AS action_package, 15 | [sesa].[name] AS action_name 16 | FROM [sys].[server_event_sessions] AS ses 17 | INNER JOIN [sys].[server_event_session_events] AS sese 18 | ON [ses].[event_session_id] = [sese].[event_session_id] 19 | INNER JOIN [sys].[server_event_session_actions] AS sesa 20 | ON [ses].[event_session_id] = [sesa].[event_session_id] AND 21 | [sese].[event_id] = [sesa].[event_id] 22 | WHERE [ses].[name] = N'system_health' ; 23 | 24 | 25 | -- Get customizable column configuration 26 | SELECT [ses].[name] AS sesion_name, 27 | [sese].[package] AS event_package, 28 | [sese].[name] AS event_name, 29 | [sese].[predicate] AS event_predicate, 30 | [sesf].[name] AS customizable_column_name, 31 | [sesf].[value] AS value 32 | FROM [sys].[server_event_sessions] AS ses 33 | INNER JOIN [sys].[server_event_session_events] AS sese 34 | ON [ses].[event_session_id] = [sese].[event_session_id] 35 | INNER JOIN [sys].[server_event_session_fields] AS sesf 36 | ON [ses].[event_session_id] = [sesf].[event_session_id] AND 37 | [sese].[event_id] = [sesf].[object_id] 38 | WHERE [ses].[name] = N'system_health' ; 39 | 40 | 41 | -- Get target information 42 | SELECT [ses].[name] AS session_name, 43 | [sest].[name] AS target_name, 44 | [sesf].[name] AS option_name, 45 | [sesf].[value] AS option_value 46 | FROM [sys].[server_event_sessions] AS ses 47 | INNER JOIN [sys].[server_event_session_targets] AS sest 48 | ON [ses].[event_session_id] = [sest].[event_session_id] 49 | INNER JOIN [sys].[server_event_session_fields] AS sesf 50 | ON [sest].[event_session_id] = [sesf].[event_session_id] AND 51 | [sest].[target_id] = [sesf].[object_id] 52 | WHERE [ses].[name] = N'system_health' ; 53 | -------------------------------------------------------------------------------- /Fundamentals/CURSOR.md: -------------------------------------------------------------------------------- 1 | ```sql 2 | DECLARE @tblStudent table(Name varchar(50), Age int); 3 | insert into @tblStudent(Name,Age) values('Name 1',1) 4 | insert into @tblStudent(Name,Age) values('Name 2',2) 5 | 6 | DECLARE @name VARCHAR(50) 7 | DECLARE @age int 8 | 9 | DECLARE myCursor CURSOR FOR 10 | SELECT Name, Age 11 | FROM @tblStudent 12 | 13 | OPEN myCursor 14 | FETCH NEXT FROM myCursor INTO @name,@age 15 | 16 | WHILE @@FETCH_STATUS = 0 17 | BEGIN 18 | print(@name + ' - ' + cast(@age as varchar)) 19 | FETCH NEXT FROM myCursor INTO @name ,@age 20 | END 21 | 22 | CLOSE myCursor 23 | DEALLOCATE myCursor 24 | ``` 25 | -------------------------------------------------------------------------------- /Fundamentals/Collations.md: -------------------------------------------------------------------------------- 1 | [Questions About SQL Server Collations You Were Too Shy to Ask](https://www.red-gate.com/simple-talk/sql/sql-development/questions-sql-server-collations-shy-ask/) 2 | 3 | [#SQL Collation – SQL_Latin1_General_CP1_CI_AS vs Latin1_General_CI_AS](https://winthropdc.wordpress.com/2018/08/08/sql-collation-sql_latin1_general_cp1_ci_as-vs-latin1_general_ci_as/) 4 | 5 | [SQL_Latin1_General_CP1_CS_AS vs Latin1_General_CS_AS](https://stackoverflow.com/questions/9698618/sql-latin1-general-cp1-cs-as-vs-latin1-general-cs-as?noredirect=1&lq=1) 6 | -------------------------------------------------------------------------------- /Fundamentals/Common Table Expression (CTE).md: -------------------------------------------------------------------------------- 1 | [Common Table Expression (CTE)](https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql) 2 | -------------------------------------------------------------------------------- /Fundamentals/JSON.md: -------------------------------------------------------------------------------- 1 | - ISJSON 2 | - JSON_VALUE 3 | - JSON_QUERY 4 | - JSON_MODIFY 5 | - OPENJSON 6 | 7 | - FOR JSON AUTO 8 | - FOR JSON PATH 9 | -------------------------------------------------------------------------------- /Fundamentals/Sequence.md: -------------------------------------------------------------------------------- 1 | [CREATE SEQUENCE (Transact-SQL)](https://docs.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql) 2 | -------------------------------------------------------------------------------- /Fundamentals/T-SQL Data Modification/MERGE.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Fundamentals/T-SQL Data Modification/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Fundamentals/T-SQL Data Retrieval/JOINS.md: -------------------------------------------------------------------------------- 1 | ### Different Types of SQL JOINs 2 | Here are the different types of the **JOINs** in **SQL**: 3 | 1. **(INNER) JOIN**: Returns records that have matching values in both tables. 4 | 2. **LEFT (OUTER) JOIN**: Return all records from the left table, and the matched records from the right table. 5 | 3. **RIGHT (OUTER) JOIN**: Return all records from the right table, and the matched records from the left table. 6 | 4. **FULL (OUTER) JOIN**: Return all records when there is a match in either left or right table. 7 | 8 | ![alt text](imgs/inner_join.gif) 9 | ![alt text](imgs/left_join.gif) 10 | ![alt text](imgs/right_join.gif) 11 | ![alt text](imgs/full_join.gif) 12 | 13 | 5. **CROSS JOIN**: The SQL CROSS JOIN produces a result set which is the number of rows in the first table multiplied by the number of rows in the second table if no WHERE clause is used along with CROSS JOIN.This kind of result is called as Cartesian Product. 14 | If WHERE clause is used with CROSS JOIN, it functions like an INNER JOIN. 15 | An alternative way of achieving the same result is to use column names separated by commas after SELECT and mentioning the table names involved, after a FROM clause. 16 | 17 | ![alt text](imgs/cross_join.png) 18 | 19 | -------------------------------------------------------------------------------- /Fundamentals/T-SQL Data Retrieval/Paging.md: -------------------------------------------------------------------------------- 1 | ### SQL Server 2012: 2 | 3 | ```sql 4 | DECLARE @currPage INT = 2, 5 | @recodperpage INT = 20; 6 | 7 | SELECT * 8 | , COUNT(*) OVER () AS TotalRecords 9 | FROM [TenBang] 10 | ORDER BY [TenCot] 11 | OFFSET(@currPage - 1) * @recodperpage ROWS 12 | FETCH NEXT @recodperpage ROWS ONLY 13 | ``` 14 | -------------------------------------------------------------------------------- /Fundamentals/T-SQL Data Retrieval/Window Functions.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Fundamentals/T-SQL Data Retrieval/imgs/cross_join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Fundamentals/T-SQL Data Retrieval/imgs/cross_join.png -------------------------------------------------------------------------------- /Fundamentals/T-SQL Data Retrieval/imgs/full_join.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Fundamentals/T-SQL Data Retrieval/imgs/full_join.gif -------------------------------------------------------------------------------- /Fundamentals/T-SQL Data Retrieval/imgs/inner_join.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Fundamentals/T-SQL Data Retrieval/imgs/inner_join.gif -------------------------------------------------------------------------------- /Fundamentals/T-SQL Data Retrieval/imgs/left_join.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Fundamentals/T-SQL Data Retrieval/imgs/left_join.gif -------------------------------------------------------------------------------- /Fundamentals/T-SQL Data Retrieval/imgs/right_join.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Fundamentals/T-SQL Data Retrieval/imgs/right_join.gif -------------------------------------------------------------------------------- /Fundamentals/Table-Valued Parameters.md: -------------------------------------------------------------------------------- 1 | [Table-Valued Parameters ](https://docs.microsoft.com/en-us/sql/relational-databases/tables/use-table-valued-parameters-database-engine) 2 | 3 | [User-Defined Table Types](https://docs.microsoft.com/en-us/sql/t-sql/statements/create-type-transact-sql) 4 | -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/README.md: -------------------------------------------------------------------------------- 1 | [SQL Server Diagnostic Information Queries](https://www.sqlskills.com/blogs/glenn/category/dmv-queries/) -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 01 - Getting the Product Version.sql: -------------------------------------------------------------------------------- 1 | -- Query 1 - Getting the Product Version 2 | 3 | -- SQL and OS Version information for current instance (Query 1) (Version Info) 4 | SELECT @@SERVERNAME AS [Server Name], @@VERSION AS [SQL Server and OS Version Info]; 5 | 6 | -- SQL Server 2014 RTM Branch Builds 7 | -- Build Description Release Date 8 | -- 11.0.9120 CTP1 6/2/2013 9 | -- 12.0.1524 CTP2 10/15/2013 10 | -- 12.0.2000 RTM 4/1/2014 11 | -- 12.0.2342 CU1 4/21/2014 12 | 13 | -- SQL Server 2014 build versions 14 | -- http://support.microsoft.com/kb/2936603 -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 02 - When Was SQL Server Installed.sql: -------------------------------------------------------------------------------- 1 | -- Query 2 - When Was SQL Server Installed 2 | 3 | -- When was SQL Server installed (Query 2) (SQL Server Install Date) 4 | SELECT @@SERVERNAME AS [Server Name], create_date AS [SQL Server Install Date] 5 | FROM sys.server_principals WITH (NOLOCK) 6 | WHERE name = N'NT AUTHORITY\SYSTEM' 7 | OR name = N'NT AUTHORITY\NETWORK SERVICE' OPTION (RECOMPILE); 8 | 9 | -- Tells you the date and time that SQL Server was installed 10 | -- It is a good idea to know how old your instance is -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 03 - Getting Useful Server Properties.sql: -------------------------------------------------------------------------------- 1 | -- Query 3 - Getting Useful Server Properties 2 | 3 | 4 | -- Get selected server properties (SQL Server 2014) (Query 3) (Server Properties) 5 | SELECT SERVERPROPERTY('MachineName') AS [MachineName], SERVERPROPERTY('ServerName') AS [ServerName], 6 | SERVERPROPERTY('InstanceName') AS [Instance], SERVERPROPERTY('IsClustered') AS [IsClustered], 7 | SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS [ComputerNamePhysicalNetBIOS], 8 | SERVERPROPERTY('Edition') AS [Edition], SERVERPROPERTY('ProductLevel') AS [ProductLevel], 9 | SERVERPROPERTY('ProductVersion') AS [ProductVersion], SERVERPROPERTY('ProcessID') AS [ProcessID], 10 | SERVERPROPERTY('Collation') AS [Collation], SERVERPROPERTY('IsFullTextInstalled') AS [IsFullTextInstalled], 11 | SERVERPROPERTY('IsIntegratedSecurityOnly') AS [IsIntegratedSecurityOnly], 12 | SERVERPROPERTY('IsHadrEnabled') AS [IsHadrEnabled], SERVERPROPERTY('HadrManagerStatus') AS [HadrManagerStatus], 13 | SERVERPROPERTY('IsXTPSupported') AS [IsXTPSupported]; 14 | 15 | -- This gives you a lot of useful information about your instance of SQL Server, 16 | -- such as the ProcessID for SQL Server and your collation 17 | -- The last column is new for SQL Server 2014 -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 04 - Getting SQL Server Agent Job Information.sql: -------------------------------------------------------------------------------- 1 | -- Query 4 - Getting SQL Server Agent Job Information 2 | 3 | 4 | -- Get SQL Server Agent jobs and Category information (Query 4) (SQL Server Agent Jobs) 5 | SELECT sj.name AS [JobName], sj.[description] AS [JobDescription], SUSER_SNAME(sj.owner_sid) AS [JobOwner], 6 | sj.date_created, sj.[enabled], sj.notify_email_operator_id, sc.name AS [CategoryName] 7 | FROM msdb.dbo.sysjobs AS sj WITH (NOLOCK) 8 | INNER JOIN msdb.dbo.syscategories AS sc WITH (NOLOCK) 9 | ON sj.category_id = sc.category_id 10 | ORDER BY sj.name OPTION (RECOMPILE); 11 | 12 | -- Gives you some basic information about your SQL Server Agent jobs, who owns them and how they are configured 13 | -- Look for Agent jobs that are not owned by sa -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 05 - Getting SQL Server Agent Alert Information.sql: -------------------------------------------------------------------------------- 1 | -- Query 5 - Getting SQL Server Agent Alert Information 2 | 3 | -- Get SQL Server Agent Alert Information (Query 5) (SQL Server Agent Alerts) 4 | SELECT name, event_source, message_id, severity, [enabled], has_notification, 5 | delay_between_responses, occurrence_count, last_occurrence_date, last_occurrence_time 6 | FROM msdb.dbo.sysalerts WITH (NOLOCK) 7 | ORDER BY name OPTION (RECOMPILE); 8 | 9 | -- Gives you some basic information about your SQL Server Agent Alerts (which are different from SQL Server Agent jobs) 10 | -- Read more about Agent Alerts here: http://www.sqlskills.com/blogs/glenn/creating-sql-server-agent-alerts-for-critical-errors/ -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 06 - Global Trace Flag Information.sql: -------------------------------------------------------------------------------- 1 | -- Query 6 - Global Trace Flag Information 2 | 3 | -- Returns a list of all global trace flags that are enabled (Query 6) (Global Trace Flags) 4 | DBCC TRACESTATUS (-1); 5 | 6 | -- If no global trace flags are enabled, no results will be returned. 7 | -- It is very useful to know what global trace flags are currently enabled as part of the diagnostic process. 8 | 9 | -- Common trace flags that should be enabled in most cases 10 | -- TF 3226 - Supresses logging of successful database backup messages to the SQL Server Error Log 11 | -- TF 1118 - Helps alleviate allocation contention in tempdb (more important with older versions of SQL Server) -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 07 - Getting Information About Windows.sql: -------------------------------------------------------------------------------- 1 | -- Query 7 - Getting Information About Windows 2 | 3 | -- Windows information (SQL Server 2014) (Query 7) (Windows Info) 4 | SELECT windows_release, windows_service_pack_level, 5 | windows_sku, os_language_version 6 | FROM sys.dm_os_windows_info WITH (NOLOCK) OPTION (RECOMPILE); 7 | 8 | -- Gives you major OS version, Service Pack, Edition, and language info for the operating system 9 | -- 6.3 is either Windows 8.1 or Windows Server 2012 R2 10 | -- 6.2 is either Windows 8 or Windows Server 2012 11 | -- 6.1 is either Windows 7 or Windows Server 2008 R2 12 | -- 6.0 is either Windows Vista or Windows Server 2008 13 | 14 | -- Windows SKU codes 15 | -- 4 is Enterprise Edition 16 | -- 48 is Professional Edition 17 | 18 | -- 1033 for os_language_version is US-English 19 | 20 | -- Using SQL Server in Windows 8, Windows 8.1, Windows Server 2012 and Windows Server 2012 R2 environments 21 | -- http://support.microsoft.com/kb/2681562 -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 08 - SQL Server Services Information.sql: -------------------------------------------------------------------------------- 1 | -- Query 8 - SQL Server Services Information 2 | 3 | -- SQL Server Services information (SQL Server 2014) (Query 8) (SQL Server Services Info) 4 | SELECT servicename, process_id, startup_type_desc, status_desc, 5 | last_startup_time, service_account, is_clustered, cluster_nodename, [filename] 6 | FROM sys.dm_server_services WITH (NOLOCK) OPTION (RECOMPILE); 7 | 8 | -- Tells you the account being used for the SQL Server Service and the SQL Agent Service 9 | -- Shows the processid, when they were last started, and their current status 10 | -- Shows whether you are running on a failover cluster instance -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 09 - SQL Server NUMA Node Information.sql: -------------------------------------------------------------------------------- 1 | -- Query 9 - SQL Server NUMA Node Information 2 | 3 | -- SQL Server NUMA Node information (Query 9) (SQL Server NUMA Info) 4 | SELECT node_id, node_state_desc, memory_node_id, processor_group, online_scheduler_count, 5 | active_worker_count, avg_load_balance, resource_monitor_state 6 | FROM sys.dm_os_nodes WITH (NOLOCK) 7 | WHERE node_state_desc <> N'ONLINE DAC' OPTION (RECOMPILE); 8 | 9 | -- Gives you some useful information about the composition 10 | -- and relative load on your NUMA nodes -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 10 - Getting Hardware Information.sql: -------------------------------------------------------------------------------- 1 | -- Query 10 - Getting Hardware Information 2 | 3 | 4 | -- Hardware information from SQL Server 2014 (Query 10) (Hardware Info) 5 | -- (Cannot distinguish between HT and multi-core) 6 | SELECT cpu_count AS [Logical CPU Count], scheduler_count, hyperthread_ratio AS [Hyperthread Ratio], 7 | cpu_count/hyperthread_ratio AS [Physical CPU Count], 8 | physical_memory_kb/1024 AS [Physical Memory (MB)], committed_kb/1024 AS [Committed Memory (MB)], 9 | committed_target_kb/1024 AS [Committed Target Memory (MB)], 10 | max_workers_count AS [Max Workers Count], affinity_type_desc AS [Affinity Type], 11 | sqlserver_start_time AS [SQL Server Start Time], virtual_machine_type_desc AS [Virtual Machine Type] 12 | FROM sys.dm_os_sys_info WITH (NOLOCK) OPTION (RECOMPILE); 13 | 14 | -- Gives you some good basic hardware information about your database server 15 | -- Note: virtual_machine_type_desc of HYPERVISOR does not automatically mean you are running SQL Server inside of a VM 16 | -- It merely indicates that you have a hypervisor running on your host -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 11 - Getting the Server Model Number.sql: -------------------------------------------------------------------------------- 1 | -- Query 11 - Getting the Server Model Number 2 | 3 | -- Get System Manufacturer and model number from (Query 11) (System Manufacturer) 4 | -- SQL Server Error log. This query might take a few seconds 5 | -- if you have not recycled your error log recently 6 | EXEC xp_readerrorlog 0, 1, "Manufacturer"; 7 | 8 | -- This can help you determine the capabilities 9 | -- and capacities of your database server -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 12 - Getting the Processor Description.sql: -------------------------------------------------------------------------------- 1 | -- Query 12 - Getting the Processor Description 2 | 3 | -- Get processor description from Windows Registry (Query 12) (Processor Description) 4 | EXEC xp_instance_regread N'HKEY_LOCAL_MACHINE', N'HARDWARE\DESCRIPTION\System\CentralProcessor\0', N'ProcessorNameString'; 5 | 6 | -- Gives you the model number and rated clock speed of your processor(s) 7 | -- Your processors may be running at less than the rated clock speed due 8 | -- to the Windows Power Plan or hardware power management -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 13 - SQL Server Error Log Properties.sql: -------------------------------------------------------------------------------- 1 | -- Query 13 - SQL Server Error Log Properties 2 | 3 | -- Shows you where the SQL Server failover cluster diagnostic log is located and how it is configured (Query 13) (SQL Server Error Log) 4 | SELECT is_enabled, [path], max_size, max_files 5 | FROM sys.dm_os_server_diagnostics_log_configurations WITH (NOLOCK) OPTION (RECOMPILE); 6 | 7 | -- Knowing this information is important for troubleshooting purposes 8 | -- Also shows you the location of other error and diagnostic log files -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 14 - OS Cluster Properties.sql: -------------------------------------------------------------------------------- 1 | -- Query 14 - OS Cluster Properties 2 | 3 | -- Get information about your OS cluster (if your database server is in a cluster) (Query 14) (Cluster Properties) 4 | SELECT VerboseLogging, SqlDumperDumpFlags, SqlDumperDumpPath, 5 | SqlDumperDumpTimeOut, FailureConditionLevel, HealthCheckTimeout 6 | FROM sys.dm_os_cluster_properties WITH (NOLOCK) OPTION (RECOMPILE); 7 | 8 | -- You will see no results if your instance is not clustered -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 15 - Cluster Node Properties.sql: -------------------------------------------------------------------------------- 1 | -- Query 15 - Cluster Node Properties 2 | 3 | -- Get information about your cluster nodes and their status (Query 15) (Cluster Node Properties) 4 | -- (if your database server is in a failover cluster) 5 | SELECT NodeName, status_description, is_current_owner 6 | FROM sys.dm_os_cluster_nodes WITH (NOLOCK) OPTION (RECOMPILE); 7 | 8 | -- Knowing which node owns the cluster resources is critical 9 | -- Especially when you are installing Windows or SQL Server updates 10 | -- You will see no results if your instance is not clustered -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 16 - Failover Cluster Node with AlwaysOn AG.sql: -------------------------------------------------------------------------------- 1 | -- Query 16 - Failover Cluster Node with AlwaysOn AG 2 | 3 | -- Get information about any AlwaysOn AG cluster this instance is a part of (Query 16) (AlwaysOn AG Cluster) 4 | SELECT cluster_name, quorum_type_desc, quorum_state_desc 5 | FROM sys.dm_hadr_cluster WITH (NOLOCK) OPTION (RECOMPILE); 6 | 7 | -- You will see no results if your instance is not using AlwaysOn AGs -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 17 - Instance Configuration Properties.sql: -------------------------------------------------------------------------------- 1 | -- Query 17 - Instance Configuration Properties 2 | 3 | -- Get configuration values for instance (Query 17) (Configuration Values) 4 | SELECT name, value, value_in_use, minimum, maximum, [description], is_dynamic, is_advanced 5 | FROM sys.configurations WITH (NOLOCK) 6 | ORDER BY name OPTION (RECOMPILE); 7 | 8 | -- Focus on 9 | -- backup compression default (should be 1 in most cases) 10 | -- cost threshold for parallelism 11 | -- clr enabled (only enable if it is needed) 12 | -- lightweight pooling (should be zero) 13 | -- max degree of parallelism 14 | -- max server memory (MB) (set to an appropriate value) 15 | -- optimize for ad hoc workloads (should be 1) 16 | -- priority boost (should be zero) -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 18 - Buffer Pool Extension Properties.sql: -------------------------------------------------------------------------------- 1 | -- Query 18 - Buffer Pool Extension Properties 2 | 3 | 4 | -- See if buffer pool extension (BPE) is enabled (Query 18) (BPE Enabled) 5 | SELECT [path], state_description, current_size_in_kb, 6 | CAST(current_size_in_kb/1048576.0 AS DECIMAL(10,2)) AS [Size (GB)] 7 | FROM sys.dm_os_buffer_pool_extension_configuration WITH (NOLOCK) OPTION (RECOMPILE); 8 | 9 | -- BPE is available in both Standard Edition and Enterprise Edition -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 19 - Buffer Pool Extension Usage.sql: -------------------------------------------------------------------------------- 1 | -- Query 19 - Buffer Pool Extension Usage 2 | 3 | -- Look at buffer descriptors to see BPE usage by database (Query 19) (BPE Usage) 4 | SELECT DB_NAME(database_id) AS [Database Name], COUNT(page_id) AS [Page Count], 5 | CAST(COUNT(*)/128.0 AS DECIMAL(10, 2)) AS [Buffer size(MB)], 6 | AVG(read_microsec) AS [Avg Read Time (microseconds)] 7 | FROM sys.dm_os_buffer_descriptors WITH (NOLOCK) 8 | WHERE database_id <> 32767 9 | AND is_in_bpool_extension = 1 10 | GROUP BY DB_NAME(database_id) 11 | ORDER BY [Buffer size(MB)] DESC OPTION (RECOMPILE); 12 | 13 | -- You will see no results if BPE is not enabled or if there is no BPE usage -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 20 - TCP Listener States.sql: -------------------------------------------------------------------------------- 1 | -- Query 20 - TCP Listener States 2 | 3 | -- Get information about TCP Listener for SQL Server (Query 20) (TCP Listener States) 4 | SELECT listener_id, ip_address, is_ipv4, port, type_desc, state_desc, start_time 5 | FROM sys.dm_tcp_listener_states WITH (NOLOCK) 6 | ORDER BY listener_id OPTION (RECOMPILE); 7 | 8 | -- Helpful for network and connectivity troubleshooting 9 | -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 21 - Memory Dump Information.sql: -------------------------------------------------------------------------------- 1 | -- Query 21 - Memory Dump Information 2 | 3 | -- Get information on location, time and size of any memory dumps from SQL Server (Query 21) (Memory Dump Info) 4 | SELECT [filename], creation_time, size_in_bytes/1048576.0 AS [Size (MB)] 5 | FROM sys.dm_server_memory_dumps WITH (NOLOCK) 6 | ORDER BY creation_time DESC OPTION (RECOMPILE); 7 | 8 | -- This will not return any rows if you have 9 | -- not had any memory dumps (which is a good thing) -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 22 - Database Filenames and Paths.sql: -------------------------------------------------------------------------------- 1 | -- Query 22 - Database Filenames and Paths 2 | 3 | -- File names and paths for TempDB and all user databases in instance (Query 22) (Database Filenames and Paths) 4 | SELECT DB_NAME([database_id]) AS [Database Name], 5 | [file_id], name, physical_name, type_desc, state_desc, 6 | is_percent_growth, growth, 7 | CONVERT(bigint, growth/128.0) AS [Growth in MB], 8 | CONVERT(bigint, size/128.0) AS [Total Size in MB] 9 | FROM sys.master_files WITH (NOLOCK) 10 | WHERE [database_id] > 4 11 | AND [database_id] <> 32767 12 | OR [database_id] = 2 13 | ORDER BY DB_NAME([database_id]) OPTION (RECOMPILE); 14 | 15 | -- Things to look at: 16 | -- Are data files and log files on different drives? 17 | -- Is everything on the C: drive? 18 | -- Is TempDB on dedicated drives? 19 | -- Is there only one TempDB data file? 20 | -- Are all of the TempDB data files the same size? 21 | -- Are there multiple data files for user databases? 22 | -- Is percent growth enabled for any files (which is bad)? -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 23 - Volume Information.sql: -------------------------------------------------------------------------------- 1 | -- Query 23 - Volume Information 2 | 3 | -- Volume info for all LUNS that have database files on the current instance (Query 23) (Volume Info) 4 | SELECT DISTINCT vs.volume_mount_point, vs.file_system_type, 5 | vs.logical_volume_name, CONVERT(DECIMAL(18,2),vs.total_bytes/1073741824.0) AS [Total Size (GB)], 6 | CONVERT(DECIMAL(18,2),vs.available_bytes/1073741824.0) AS [Available Size (GB)], 7 | CAST(CAST(vs.available_bytes AS FLOAT)/ CAST(vs.total_bytes AS FLOAT) AS DECIMAL(18,2)) * 100 AS [Space Free %] 8 | FROM sys.master_files AS f WITH (NOLOCK) 9 | CROSS APPLY sys.dm_os_volume_stats(f.database_id, f.[file_id]) AS vs OPTION (RECOMPILE); 10 | 11 | --Shows you the total and free space on the LUNs where you have database files -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 24 - IO Warnings.sql: -------------------------------------------------------------------------------- 1 | -- Look for I/O requests taking longer than 15 seconds in the five most recent SQL Server Error Logs (Query 24) (IO Warnings) 2 | CREATE TABLE #IOWarningResults(LogDate datetime, ProcessInfo sysname, LogText nvarchar(1000)); 3 | 4 | INSERT INTO #IOWarningResults 5 | EXEC xp_readerrorlog 0, 1, N'taking longer than 15 seconds'; 6 | 7 | INSERT INTO #IOWarningResults 8 | EXEC xp_readerrorlog 1, 1, N'taking longer than 15 seconds'; 9 | 10 | INSERT INTO #IOWarningResults 11 | EXEC xp_readerrorlog 2, 1, N'taking longer than 15 seconds'; 12 | 13 | INSERT INTO #IOWarningResults 14 | EXEC xp_readerrorlog 3, 1, N'taking longer than 15 seconds'; 15 | 16 | INSERT INTO #IOWarningResults 17 | EXEC xp_readerrorlog 4, 1, N'taking longer than 15 seconds'; 18 | 19 | SELECT LogDate, ProcessInfo, LogText 20 | FROM #IOWarningResults 21 | ORDER BY LogDate DESC; 22 | 23 | DROP TABLE #IOWarningResults; 24 | 25 | -- Finding 15 second I/O warnings in the SQL Server Error Log is useful evidence of 26 | -- poor I/O performance (which might have many different causes) -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 25 - Drive-Level Latency.sql: -------------------------------------------------------------------------------- 1 | -- Drive level latency information (Query 25) (Drive Level Latency) 2 | -- Based on code from Jimmy May 3 | SELECT [Drive], 4 | CASE 5 | WHEN num_of_reads = 0 THEN 0 6 | ELSE (io_stall_read_ms/num_of_reads) 7 | END AS [Read Latency], 8 | CASE 9 | WHEN io_stall_write_ms = 0 THEN 0 10 | ELSE (io_stall_write_ms/num_of_writes) 11 | END AS [Write Latency], 12 | CASE 13 | WHEN (num_of_reads = 0 AND num_of_writes = 0) THEN 0 14 | ELSE (io_stall/(num_of_reads + num_of_writes)) 15 | END AS [Overall Latency], 16 | CASE 17 | WHEN num_of_reads = 0 THEN 0 18 | ELSE (num_of_bytes_read/num_of_reads) 19 | END AS [Avg Bytes/Read], 20 | CASE 21 | WHEN io_stall_write_ms = 0 THEN 0 22 | ELSE (num_of_bytes_written/num_of_writes) 23 | END AS [Avg Bytes/Write], 24 | CASE 25 | WHEN (num_of_reads = 0 AND num_of_writes = 0) THEN 0 26 | ELSE ((num_of_bytes_read + num_of_bytes_written)/(num_of_reads + num_of_writes)) 27 | END AS [Avg Bytes/Transfer] 28 | FROM (SELECT LEFT(UPPER(mf.physical_name), 2) AS Drive, SUM(num_of_reads) AS num_of_reads, 29 | SUM(io_stall_read_ms) AS io_stall_read_ms, SUM(num_of_writes) AS num_of_writes, 30 | SUM(io_stall_write_ms) AS io_stall_write_ms, SUM(num_of_bytes_read) AS num_of_bytes_read, 31 | SUM(num_of_bytes_written) AS num_of_bytes_written, SUM(io_stall) AS io_stall 32 | FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS vfs 33 | INNER JOIN sys.master_files AS mf WITH (NOLOCK) 34 | ON vfs.database_id = mf.database_id AND vfs.file_id = mf.file_id 35 | GROUP BY LEFT(UPPER(mf.physical_name), 2)) AS tab 36 | ORDER BY [Overall Latency] OPTION (RECOMPILE); 37 | 38 | -- Shows you the drive-level latency for reads and writes, in milliseconds 39 | -- Latency above 20-25ms is usually a problem -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 26 - IO Latencies by Database File.sql: -------------------------------------------------------------------------------- 1 | -- Calculates average stalls per read, per write, and per total input/output for each database file (Query 26) (IO Stalls by File) 2 | 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], 3 | CAST(fs.io_stall_write_ms/(1.0 + fs.num_of_writes) AS NUMERIC(10,1)) AS [avg_write_stall_ms], 4 | 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], 5 | 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, 6 | 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], 7 | io_stall_queued_read_ms AS [Resource Governor Total Read IO Latency (ms)], io_stall_queued_write_ms AS [Resource Governor Total Write IO Latency (ms)] 8 | FROM sys.dm_io_virtual_file_stats(null,null) AS fs 9 | INNER JOIN sys.master_files AS mf WITH (NOLOCK) 10 | ON fs.database_id = mf.database_id 11 | AND fs.[file_id] = mf.[file_id] 12 | ORDER BY avg_io_stall_ms DESC OPTION (RECOMPILE); 13 | 14 | -- Helps determine which database files on the entire instance have the most I/O bottlenecks 15 | -- This can help you decide whether certain LUNs are overloaded and whether you might 16 | -- want to move some files to a different location or perhaps improve your I/O performance -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 27 - Database Properties.sql: -------------------------------------------------------------------------------- 1 | -- Recovery model, log reuse wait description, log file size, log usage size (Query 27) (Database Properties) 2 | -- and compatibility level for all databases on instance 3 | SELECT db.[name] AS [Database Name], db.recovery_model_desc AS [Recovery Model], db.state_desc, 4 | db.log_reuse_wait_desc AS [Log Reuse Wait Description], 5 | 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)], 6 | CAST(CAST(lu.cntr_value AS FLOAT) / CAST(ls.cntr_value AS FLOAT)AS DECIMAL(18,2)) * 100 AS [Log Used %], 7 | db.[compatibility_level] AS [DB Compatibility Level], db.page_verify_option_desc AS [Page Verify Option], 8 | db.is_auto_create_stats_on, db.is_auto_update_stats_on, db.is_auto_update_stats_async_on, db.is_parameterization_forced, 9 | db.snapshot_isolation_state_desc, db.is_read_committed_snapshot_on, db.is_auto_close_on, db.is_auto_shrink_on, 10 | db.target_recovery_time_in_seconds, db.is_cdc_enabled, db.is_memory_optimized_elevate_to_snapshot_on, db.delayed_durability_desc, 11 | db.is_auto_create_stats_incremental_on 12 | FROM sys.databases AS db WITH (NOLOCK) 13 | INNER JOIN sys.dm_os_performance_counters AS lu WITH (NOLOCK) 14 | ON db.name = lu.instance_name 15 | INNER JOIN sys.dm_os_performance_counters AS ls WITH (NOLOCK) 16 | ON db.name = ls.instance_name 17 | WHERE lu.counter_name LIKE N'Log File(s) Used Size (KB)%' 18 | AND ls.counter_name LIKE N'Log File(s) Size (KB)%' 19 | AND ls.cntr_value > 0 20 | ORDER BY db.[name] OPTION (RECOMPILE); 21 | 22 | -- Things to look at: 23 | -- How many databases are on the instance? 24 | -- What recovery models are they using? 25 | -- What is the log reuse wait description? 26 | -- How full are the transaction logs ? 27 | -- What compatibility level are the databases on? 28 | -- What is the Page Verify Option? (should be CHECKSUM) 29 | -- Is Auto Update Statistics Asynchronously enabled? 30 | -- Make sure auto_shrink and auto_close are not enabled! -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 28 - Missing Indexes for All Databases.sql: -------------------------------------------------------------------------------- 1 | -- Missing Indexes for all databases by Index Advantage (Query 28) (Missing Indexes All Databases) 2 | SELECT CONVERT(decimal(18,2), user_seeks * avg_total_user_cost * (avg_user_impact * 0.01)) AS [index_advantage], 3 | migs.last_user_seek, mid.[statement] AS [Database.Schema.Table], 4 | mid.equality_columns, mid.inequality_columns, mid.included_columns, 5 | migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact 6 | FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK) 7 | INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK) 8 | ON migs.group_handle = mig.index_group_handle 9 | INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK) 10 | ON mig.index_handle = mid.index_handle 11 | ORDER BY index_advantage DESC OPTION (RECOMPILE); 12 | 13 | -- Getting missing index information for all of the databases on the instance is very useful 14 | -- Look at last user seek time, number of user seeks to help determine source and importance 15 | -- Also look at avg_user_impact and avg_total_user_cost to help determine importance 16 | -- SQL Server is overly eager to add included columns, so beware 17 | -- Do not just blindly add indexes that show up from this query!!! -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 29 - Getting VLF Counts.sql: -------------------------------------------------------------------------------- 1 | -- Get VLF Counts for all databases on the instance (Query 29) (VLF Counts) 2 | -- (adapted from Michelle Ufford) 3 | CREATE TABLE #VLFInfo (RecoveryUnitID int, FileID int, 4 | FileSize bigint, StartOffset bigint, 5 | FSeqNo bigint, [Status] bigint, 6 | Parity bigint, CreateLSN numeric(38)); 7 | 8 | CREATE TABLE #VLFCountResults(DatabaseName sysname, VLFCount int); 9 | 10 | EXEC sp_MSforeachdb N'Use [?]; 11 | 12 | INSERT INTO #VLFInfo 13 | EXEC sp_executesql N''DBCC LOGINFO([?])''; 14 | 15 | INSERT INTO #VLFCountResults 16 | SELECT DB_NAME(), COUNT(*) 17 | FROM #VLFInfo; 18 | 19 | TRUNCATE TABLE #VLFInfo;' 20 | 21 | SELECT DatabaseName, VLFCount 22 | FROM #VLFCountResults 23 | ORDER BY VLFCount DESC; 24 | 25 | DROP TABLE #VLFInfo; 26 | DROP TABLE #VLFCountResults; 27 | 28 | -- High VLF counts can affect write performance 29 | -- and they can make database restores and recovery take much longer 30 | -- Try to keep your VLF counts under 200 in most cases -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 30 - CPU Usage by Database.sql: -------------------------------------------------------------------------------- 1 | -- Get CPU utilization by database (Query 30) (CPU Usage by Database) 2 | WITH DB_CPU_Stats 3 | AS 4 | (SELECT DatabaseID, DB_Name(DatabaseID) AS [Database Name], SUM(total_worker_time) AS [CPU_Time_Ms] 5 | FROM sys.dm_exec_query_stats AS qs 6 | CROSS APPLY (SELECT CONVERT(int, value) AS [DatabaseID] 7 | FROM sys.dm_exec_plan_attributes(qs.plan_handle) 8 | WHERE attribute = N'dbid') AS F_DB 9 | GROUP BY DatabaseID) 10 | SELECT ROW_NUMBER() OVER(ORDER BY [CPU_Time_Ms] DESC) AS [CPU Rank], 11 | [Database Name], [CPU_Time_Ms] AS [CPU Time (ms)], 12 | CAST([CPU_Time_Ms] * 1.0 / SUM([CPU_Time_Ms]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CPU Percent] 13 | FROM DB_CPU_Stats 14 | WHERE DatabaseID <> 32767 -- ResourceDB 15 | ORDER BY [CPU Rank] OPTION (RECOMPILE); 16 | 17 | -- Helps determine which database is using the most CPU resources on the instance -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 31 - IO Usage by Database.sql: -------------------------------------------------------------------------------- 1 | -- Get I/O utilization by database (Query 31) (IO Usage By Database) 2 | WITH Aggregate_IO_Statistics 3 | AS 4 | (SELECT DB_NAME(database_id) AS [Database Name], 5 | CAST(SUM(num_of_bytes_read + num_of_bytes_written)/1048576 AS DECIMAL(12, 2)) AS io_in_mb 6 | FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS [DM_IO_STATS] 7 | GROUP BY database_id) 8 | SELECT ROW_NUMBER() OVER(ORDER BY io_in_mb DESC) AS [I/O Rank], [Database Name], io_in_mb AS [Total I/O (MB)], 9 | CAST(io_in_mb/ SUM(io_in_mb) OVER() * 100.0 AS DECIMAL(5,2)) AS [I/O Percent] 10 | FROM Aggregate_IO_Statistics 11 | ORDER BY [I/O Rank] OPTION (RECOMPILE); 12 | 13 | -- Helps determine which database is using the most I/O resources on the instance -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 32 - Total Buffer Usage by Database.sql: -------------------------------------------------------------------------------- 1 | -- Get total buffer usage by database for current instance (Query 32) (Total Buffer Usage by Database) 2 | WITH AggregateBufferPoolUsage 3 | AS 4 | (SELECT DB_NAME(database_id) AS [Database Name], 5 | CAST(COUNT(*) * 8/1024.0 AS DECIMAL (10,2)) AS [CachedSize] 6 | FROM sys.dm_os_buffer_descriptors WITH (NOLOCK) 7 | WHERE database_id <> 32767 -- ResourceDB 8 | GROUP BY DB_NAME(database_id)) 9 | SELECT ROW_NUMBER() OVER(ORDER BY CachedSize DESC) AS [Buffer Pool Rank], [Database Name], CachedSize AS [Cached Size (MB)], 10 | CAST(CachedSize / SUM(CachedSize) OVER() * 100.0 AS DECIMAL(5,2)) AS [Buffer Pool Percent] 11 | FROM AggregateBufferPoolUsage 12 | ORDER BY [Buffer Pool Rank] OPTION (RECOMPILE); 13 | 14 | -- Tells you how much memory (in the buffer pool) 15 | -- is being used by each database on the instance -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 34 - Signal Waits.sql: -------------------------------------------------------------------------------- 1 | -- Signal Waits for instance (Query 34) (Signal Waits) 2 | SELECT CAST(100.0 * SUM(signal_wait_time_ms) / SUM (wait_time_ms) AS NUMERIC(20,2)) AS [% Signal (CPU) Waits], 3 | CAST(100.0 * SUM(wait_time_ms - signal_wait_time_ms) / SUM (wait_time_ms) AS NUMERIC(20,2)) AS [% Resource Waits] 4 | FROM sys.dm_os_wait_stats WITH (NOLOCK) 5 | WHERE wait_type NOT IN ( 6 | N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR', N'BROKER_TASK_STOP', 7 | N'BROKER_TO_FLUSH', N'BROKER_TRANSMITTER', N'CHECKPOINT_QUEUE', 8 | N'CHKPT', N'CLR_AUTO_EVENT', N'CLR_MANUAL_EVENT', N'CLR_SEMAPHORE', 9 | N'DBMIRROR_DBM_EVENT', N'DBMIRROR_EVENTS_QUEUE', N'DBMIRROR_WORKER_QUEUE', 10 | N'DBMIRRORING_CMD', N'DIRTY_PAGE_POLL', N'DISPATCHER_QUEUE_SEMAPHORE', 11 | N'EXECSYNC', N'FSAGENT', N'FT_IFTS_SCHEDULER_IDLE_WAIT', N'FT_IFTSHC_MUTEX', 12 | N'HADR_CLUSAPI_CALL', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', N'HADR_LOGCAPTURE_WAIT', 13 | N'HADR_NOTIFICATION_DEQUEUE', N'HADR_TIMER_TASK', N'HADR_WORK_QUEUE', 14 | N'KSOURCE_WAKEUP', N'LAZYWRITER_SLEEP', N'LOGMGR_QUEUE', N'ONDEMAND_TASK_QUEUE', 15 | N'PWAIT_ALL_COMPONENTS_INITIALIZED', N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', 16 | N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', N'REQUEST_FOR_DEADLOCK_SEARCH', 17 | N'RESOURCE_QUEUE', N'SERVER_IDLE_CHECK', N'SLEEP_BPOOL_FLUSH', N'SLEEP_DBSTARTUP', 18 | N'SLEEP_DCOMSTARTUP', N'SLEEP_MASTERDBREADY', N'SLEEP_MASTERMDREADY', 19 | N'SLEEP_MASTERUPGRADED', N'SLEEP_MSDBSTARTUP', N'SLEEP_SYSTEMTASK', N'SLEEP_TASK', 20 | N'SLEEP_TEMPDBSTARTUP', N'SNI_HTTP_ACCEPT', N'SP_SERVER_DIAGNOSTICS_SLEEP', 21 | N'SQLTRACE_BUFFER_FLUSH', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', N'SQLTRACE_WAIT_ENTRIES', 22 | N'WAIT_FOR_RESULTS', N'WAITFOR', N'WAITFOR_TASKSHUTDOWN', N'WAIT_XTP_HOST_WAIT', 23 | N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', N'WAIT_XTP_CKPT_CLOSE', N'XE_DISPATCHER_JOIN', 24 | N'XE_DISPATCHER_WAIT', N'XE_TIMER_EVENT') OPTION (RECOMPILE); 25 | 26 | -- Signal Waits above 10-15% is usually a confirming sign of CPU pressure 27 | -- Cumulative wait stats are not as useful on an idle instance that is not under load or performance pressure 28 | -- Resource waits are non-CPU related waits -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 35 - Connection Counts.sql: -------------------------------------------------------------------------------- 1 | -- Get logins that are connected and how many sessions they have (Query 35) (Connection Counts) 2 | SELECT login_name, [program_name], COUNT(session_id) AS [session_count] 3 | FROM sys.dm_exec_sessions WITH (NOLOCK) 4 | GROUP BY login_name, [program_name] 5 | ORDER BY COUNT(session_id) DESC OPTION (RECOMPILE); 6 | 7 | -- This can help characterize your workload and 8 | -- determine whether you are seeing a normal level of activity -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 36 - Connection Counts by IP Address.sql: -------------------------------------------------------------------------------- 1 | -- Get a count of SQL connections by IP address (Query 36) (Connection Counts by IP Address) 2 | SELECT ec.client_net_address, es.[program_name], es.[host_name], es.login_name, 3 | COUNT(ec.session_id) AS [connection count] 4 | FROM sys.dm_exec_sessions AS es WITH (NOLOCK) 5 | INNER JOIN sys.dm_exec_connections AS ec WITH (NOLOCK) 6 | ON es.session_id = ec.session_id 7 | GROUP BY ec.client_net_address, es.[program_name], es.[host_name], es.login_name 8 | ORDER BY ec.client_net_address, es.[program_name] OPTION (RECOMPILE); 9 | 10 | -- Helps troubleshoot connectivity from other machines -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 37 - Average Task Counts.sql: -------------------------------------------------------------------------------- 1 | -- Get Average Task Counts (run multiple times) (Query 37) (Avg Task Counts) 2 | SELECT AVG(current_tasks_count) AS [Avg Task Count], 3 | AVG(runnable_tasks_count) AS [Avg Runnable Task Count], 4 | AVG(pending_disk_io_count) AS [Avg Pending DiskIO Count] 5 | FROM sys.dm_os_schedulers WITH (NOLOCK) 6 | WHERE scheduler_id < 255 OPTION (RECOMPILE); 7 | 8 | -- Sustained values above 10 suggest further investigation in this area 9 | -- High Avg Task Counts are often caused by blocking or other resource contention 10 | 11 | -- Sustained values above 1 suggest further investigation in that area 12 | -- High Avg Runnable Task Counts are a good sign of CPU pressure 13 | -- High Avg Pending DiskIO Counts are a sign of disk pressure -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 38 - CPU Utilization History.sql: -------------------------------------------------------------------------------- 1 | -- Get CPU Utilization History for last 256 minutes (in one minute intervals) (Query 38) (CPU Utilization History) 2 | -- This version works with SQL Server 2014 3 | DECLARE @ts_now bigint = (SELECT cpu_ticks/(cpu_ticks/ms_ticks) FROM sys.dm_os_sys_info WITH (NOLOCK)); 4 | 5 | SELECT TOP(256) SQLProcessUtilization AS [SQL Server Process CPU Utilization], 6 | SystemIdle AS [System Idle Process], 7 | 100 - SystemIdle - SQLProcessUtilization AS [Other Process CPU Utilization], 8 | DATEADD(ms, -1 * (@ts_now - [timestamp]), GETDATE()) AS [Event Time] 9 | FROM (SELECT record.value('(./Record/@id)[1]', 'int') AS record_id, 10 | record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int') 11 | AS [SystemIdle], 12 | record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]', 'int') 13 | AS [SQLProcessUtilization], [timestamp] 14 | FROM (SELECT [timestamp], CONVERT(xml, record) AS [record] 15 | FROM sys.dm_os_ring_buffers WITH (NOLOCK) 16 | WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR' 17 | AND record LIKE N'%%') AS x) AS y 18 | ORDER BY record_id DESC OPTION (RECOMPILE); 19 | 20 | -- Look at the trend over the entire period 21 | -- Also look at high sustained Other Process CPU Utilization values -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 39 - Top Work Time Queries.sql: -------------------------------------------------------------------------------- 1 | -- Get top total worker time queries for entire instance (Query 39) (Top Worker Time Queries) 2 | SELECT TOP(50) DB_NAME(t.[dbid]) AS [Database Name], t.[text] AS [Query Text], 3 | qs.total_worker_time AS [Total Worker Time], qs.min_worker_time AS [Min Worker Time], 4 | qs.total_worker_time/qs.execution_count AS [Avg Worker Time], 5 | qs.max_worker_time AS [Max Worker Time], qs.execution_count AS [Execution Count], 6 | qs.total_elapsed_time/qs.execution_count AS [Avg Elapsed Time], 7 | qs.total_logical_reads/qs.execution_count AS [Avg Logical Reads], 8 | qs.total_physical_reads/qs.execution_count AS [Avg Physical Reads], 9 | qp.query_plan AS [Query Plan], qs.creation_time AS [Creation Time] 10 | FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) 11 | CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t 12 | CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp 13 | ORDER BY qs.total_worker_time DESC OPTION (RECOMPILE); 14 | 15 | -- Helps you find the most expensive queries from a CPU perspective across the entire instance -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 40 - System Memory.sql: -------------------------------------------------------------------------------- 1 | -- Good basic information about OS memory amounts and state (Query 40) (System Memory) 2 | SELECT total_physical_memory_kb/1024 AS [Physical Memory (MB)], 3 | available_physical_memory_kb/1024 AS [Available Memory (MB)], 4 | total_page_file_kb/1024 AS [Total Page File (MB)], 5 | available_page_file_kb/1024 AS [Available Page File (MB)], 6 | system_cache_kb/1024 AS [System Cache (MB)], 7 | system_memory_state_desc AS [System Memory State] 8 | FROM sys.dm_os_sys_memory WITH (NOLOCK) OPTION (RECOMPILE); 9 | 10 | -- You want to see "Available physical memory is high" 11 | -- This indicates that you are not under external memory pressure -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 41 - Process Memory.sql: -------------------------------------------------------------------------------- 1 | 2 | -- SQL Server Process Address space info (Query 41) (Process Memory) 3 | -- (shows whether locked pages is enabled, among other things) 4 | SELECT physical_memory_in_use_kb/1024 AS [SQL Server Memory Usage (MB)], 5 | large_page_allocations_kb, locked_page_allocations_kb, page_fault_count, 6 | memory_utilization_percentage, available_commit_limit_kb, 7 | process_physical_memory_low, process_virtual_memory_low 8 | FROM sys.dm_os_process_memory WITH (NOLOCK) OPTION (RECOMPILE); 9 | 10 | -- You want to see 0 for process_physical_memory_low 11 | -- You want to see 0 for process_virtual_memory_low 12 | -- This indicates that you are not under internal memory pressure -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 42 - Page Life Expectancy by NUMA Node.sql: -------------------------------------------------------------------------------- 1 | -- Page Life Expectancy (PLE) value for each NUMA node in current instance (Query 42) (PLE by NUMA Node) 2 | SELECT @@SERVERNAME AS [Server Name], [object_name], instance_name, cntr_value AS [Page Life Expectancy] 3 | FROM sys.dm_os_performance_counters WITH (NOLOCK) 4 | WHERE [object_name] LIKE N'%Buffer Node%' -- Handles named instances 5 | AND counter_name = N'Page life expectancy' OPTION (RECOMPILE); 6 | 7 | -- PLE is a good measurement of memory pressure. 8 | -- Higher PLE is better. Watch the trend over time, not the absolute value. 9 | -- This will only return one row for non-NUMA systems. -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 43 - Memory Grants Pending.sql: -------------------------------------------------------------------------------- 1 | -- Memory Grants Pending value for current instance (Query 43) (Memory Grants Pending) 2 | SELECT @@SERVERNAME AS [Server Name], [object_name], cntr_value AS [Memory Grants Pending] 3 | FROM sys.dm_os_performance_counters WITH (NOLOCK) 4 | WHERE [object_name] LIKE N'%Memory Manager%' -- Handles named instances 5 | AND counter_name = N'Memory Grants Pending' OPTION (RECOMPILE); 6 | 7 | -- Memory Grants Pending above zero for a sustained period is a very strong indicator of memory pressure -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 44 - Memory Clerk Usage.sql: -------------------------------------------------------------------------------- 1 | -- Memory Clerk Usage for instance (Query 44) (Memory Clerk Usage) 2 | -- Look for high value for CACHESTORE_SQLCP (Ad-hoc query plans) 3 | SELECT TOP(10) [type] AS [Memory Clerk Type], 4 | SUM(pages_kb)/1024 AS [Memory Usage (MB)] 5 | FROM sys.dm_os_memory_clerks WITH (NOLOCK) 6 | GROUP BY [type] 7 | ORDER BY SUM(pages_kb) DESC OPTION (RECOMPILE); 8 | 9 | -- MEMORYCLERK_SQLBUFFERPOOL was new for SQL Server 2012. It should be your highest consumer of memory 10 | 11 | 12 | -- CACHESTORE_SQLCP SQL Plans 13 | -- These are cached SQL statements or batches that aren't in stored procedures, functions and triggers 14 | -- Watch out for high values for CACHESTORE_SQLCP 15 | 16 | -- CACHESTORE_OBJCP Object Plans 17 | -- These are compiled plans for stored procedures, functions and triggers -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 45 - Ad Hoc Queries.sql: -------------------------------------------------------------------------------- 1 | -- Find single-use, ad-hoc and prepared queries that are bloating the plan cache (Query 44) (Ad hoc Queries) 2 | SELECT TOP(50) [text] AS [QueryText], cp.cacheobjtype, cp.objtype, cp.size_in_bytes 3 | FROM sys.dm_exec_cached_plans AS cp WITH (NOLOCK) 4 | CROSS APPLY sys.dm_exec_sql_text(plan_handle) 5 | WHERE cp.cacheobjtype = N'Compiled Plan' 6 | AND cp.objtype IN (N'Adhoc', N'Prepared') 7 | AND cp.usecounts = 1 8 | ORDER BY cp.size_in_bytes DESC OPTION (RECOMPILE); 9 | 10 | -- Gives you the text, type and size of single-use ad-hoc and prepared queries that waste space in the plan cache 11 | -- Enabling 'optimize for ad hoc workloads' for the instance can help (SQL Server 2008 and above only) 12 | -- Running DBCC FREESYSTEMCACHE ('SQL Plans') periodically may be required to better control this. 13 | -- Enabling forced parameterization for the database can help, but test first! -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 46 - File Sizes and Space.sql: -------------------------------------------------------------------------------- 1 | -- Individual File Sizes and space available for current database (Query 46) (File Sizes and Space) 2 | SELECT f.name AS [File Name] , f.physical_name AS [Physical Name], 3 | CAST((f.size/128.0) AS DECIMAL(15,2)) AS [Total Size in MB], 4 | CAST(f.size/128.0 - CAST(FILEPROPERTY(f.name, 'SpaceUsed') AS int)/128.0 AS DECIMAL(15,2)) 5 | AS [Available Space In MB], [file_id], fg.name AS [Filegroup Name], f.is_percent_growth 6 | FROM sys.database_files AS f WITH (NOLOCK) 7 | LEFT OUTER JOIN sys.data_spaces AS fg WITH (NOLOCK) 8 | ON f.data_space_id = fg.data_space_id OPTION (RECOMPILE); 9 | 10 | -- Look at how large and how full the files are and where they are located 11 | -- Make sure the transaction log is not full!! -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 47 - IO Stats By File.sql: -------------------------------------------------------------------------------- 1 | -- I/O Statistics by file for the current database (Query 47) (IO Stats By File) 2 | SELECT DB_NAME(DB_ID()) AS [Database Name], df.name AS [Logical Name], vfs.[file_id], 3 | df.physical_name AS [Physical Name], vfs.num_of_reads, vfs.num_of_writes, vfs.io_stall_read_ms, vfs.io_stall_write_ms, 4 | 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], 5 | 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], 6 | (vfs.num_of_reads + vfs.num_of_writes) AS [Writes + Reads], 7 | CAST(vfs.num_of_bytes_read/1048576.0 AS DECIMAL(10, 2)) AS [MB Read], 8 | CAST(vfs.num_of_bytes_written/1048576.0 AS DECIMAL(10, 2)) AS [MB Written], 9 | CAST(100. * vfs.num_of_reads/(vfs.num_of_reads + vfs.num_of_writes) AS DECIMAL(10,1)) AS [# Reads Pct], 10 | CAST(100. * vfs.num_of_writes/(vfs.num_of_reads + vfs.num_of_writes) AS DECIMAL(10,1)) AS [# Write Pct], 11 | 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], 12 | 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] 13 | FROM sys.dm_io_virtual_file_stats(DB_ID(), NULL) AS vfs 14 | INNER JOIN sys.database_files AS df WITH (NOLOCK) 15 | ON vfs.[file_id]= df.[file_id] 16 | OPTION (RECOMPILE); 17 | 18 | -- This helps you characterize your workload better from an I/O perspective for this database 19 | -- It helps you determine whether you has an OLTP or DW/DSS type of workload -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 48 - Query Execution Counts.sql: -------------------------------------------------------------------------------- 1 | -- Top cached queries by Execution Count (SQL Server 2014) (Query 48) (Query Execution Counts) 2 | SELECT TOP (100) qs.execution_count, qs.total_rows, qs.last_rows, qs.min_rows, qs.max_rows, 3 | qs.last_elapsed_time, qs.min_elapsed_time, qs.max_elapsed_time, 4 | total_worker_time, total_logical_reads, 5 | SUBSTRING(qt.TEXT,qs.statement_start_offset/2 +1, 6 | (CASE WHEN qs.statement_end_offset = -1 7 | THEN LEN(CONVERT(NVARCHAR(MAX), qt.TEXT)) * 2 8 | ELSE qs.statement_end_offset END - qs.statement_start_offset)/2) AS query_text 9 | FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) 10 | CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt 11 | WHERE qt.dbid = DB_ID() 12 | ORDER BY qs.execution_count DESC OPTION (RECOMPILE); 13 | 14 | -- Uses several new rows returned columns to help troubleshoot performance problems -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 49 - SP Execution Counts.sql: -------------------------------------------------------------------------------- 1 | -- Top Cached SPs By Execution Count (SQL Server 2014) (Query 49) (SP Execution Counts) 2 | SELECT TOP(100) p.name AS [SP Name], qs.execution_count, 3 | ISNULL(qs.execution_count/DATEDIFF(Minute, qs.cached_time, GETDATE()), 0) AS [Calls/Minute], 4 | qs.total_worker_time/qs.execution_count AS [AvgWorkerTime], qs.total_worker_time AS [TotalWorkerTime], 5 | qs.total_elapsed_time, qs.total_elapsed_time/qs.execution_count AS [avg_elapsed_time], 6 | qs.cached_time 7 | FROM sys.procedures AS p WITH (NOLOCK) 8 | INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK) 9 | ON p.[object_id] = qs.[object_id] 10 | WHERE qs.database_id = DB_ID() 11 | ORDER BY qs.execution_count DESC OPTION (RECOMPILE); 12 | 13 | -- Tells you which cached stored procedures are called the most often 14 | -- This helps you characterize and baseline your workload -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 50 - SP Avg Elapsed Time.sql: -------------------------------------------------------------------------------- 1 | -- Top Cached SPs By Avg Elapsed Time (SQL Server 2014) (Query 50) (SP Avg Elapsed Time) 2 | SELECT TOP(25) p.name AS [SP Name], qs.total_elapsed_time/qs.execution_count AS [avg_elapsed_time], 3 | qs.total_elapsed_time, qs.execution_count, ISNULL(qs.execution_count/DATEDIFF(Minute, qs.cached_time, 4 | GETDATE()), 0) AS [Calls/Minute], qs.total_worker_time/qs.execution_count AS [AvgWorkerTime], 5 | qs.total_worker_time AS [TotalWorkerTime], qs.cached_time 6 | FROM sys.procedures AS p WITH (NOLOCK) 7 | INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK) 8 | ON p.[object_id] = qs.[object_id] 9 | WHERE qs.database_id = DB_ID() 10 | ORDER BY avg_elapsed_time DESC OPTION (RECOMPILE); 11 | 12 | -- This helps you find long-running cached stored procedures that 13 | -- may be easy to optimize with standard query tuning techniques -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 51 - SP Avg Elapsed Variable Time.sql: -------------------------------------------------------------------------------- 1 | -- Top Cached SPs By Avg Elapsed Time with execution time variability (SQL Server 2014) (Query 51) (SP Avg Elapsed Variable Time) 2 | SELECT TOP(25) p.name AS [SP Name], qs.execution_count, qs.min_elapsed_time, 3 | qs.total_elapsed_time/qs.execution_count AS [avg_elapsed_time], 4 | qs.max_elapsed_time, qs.last_elapsed_time, qs.cached_time 5 | FROM sys.procedures AS p WITH (NOLOCK) 6 | INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK) 7 | ON p.[object_id] = qs.[object_id] 8 | WHERE qs.database_id = DB_ID() 9 | ORDER BY avg_elapsed_time DESC OPTION (RECOMPILE); 10 | 11 | -- This gives you some interesting information about the variability in the 12 | -- execution time of your cached stored procedures, which is useful for tuning -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 52 - SP Worker Time.sql: -------------------------------------------------------------------------------- 1 | -- Top Cached SPs By Total Worker time (SQL Server 2014). Worker time relates to CPU cost (Query 52) (SP Worker Time) 2 | SELECT TOP(25) p.name AS [SP Name], qs.total_worker_time AS [TotalWorkerTime], 3 | qs.total_worker_time/qs.execution_count AS [AvgWorkerTime], qs.execution_count, 4 | ISNULL(qs.execution_count/DATEDIFF(Minute, qs.cached_time, GETDATE()), 0) AS [Calls/Minute], 5 | qs.total_elapsed_time, qs.total_elapsed_time/qs.execution_count 6 | AS [avg_elapsed_time], qs.cached_time 7 | FROM sys.procedures AS p WITH (NOLOCK) 8 | INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK) 9 | ON p.[object_id] = qs.[object_id] 10 | WHERE qs.database_id = DB_ID() 11 | ORDER BY qs.total_worker_time DESC OPTION (RECOMPILE); 12 | 13 | -- This helps you find the most expensive cached stored procedures from a CPU perspective 14 | -- You should look at this if you see signs of CPU pressure -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 53 - SP Logical Reads.sql: -------------------------------------------------------------------------------- 1 | -- Top Cached SPs By Total Logical Reads (SQL Server 2014) (Query 53) (SP Logical Reads) 2 | -- Logical reads relate to memory pressure 3 | SELECT TOP(25) p.name AS [SP Name], qs.total_logical_reads AS [TotalLogicalReads], 4 | qs.total_logical_reads/qs.execution_count AS [AvgLogicalReads],qs.execution_count, 5 | ISNULL(qs.execution_count/DATEDIFF(Minute, qs.cached_time, GETDATE()), 0) AS [Calls/Minute], 6 | qs.total_elapsed_time, qs.total_elapsed_time/qs.execution_count 7 | AS [avg_elapsed_time], qs.cached_time 8 | FROM sys.procedures AS p WITH (NOLOCK) 9 | INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK) 10 | ON p.[object_id] = qs.[object_id] 11 | WHERE qs.database_id = DB_ID() 12 | ORDER BY qs.total_logical_reads DESC OPTION (RECOMPILE); 13 | 14 | -- This helps you find the most expensive cached stored procedures from a memory perspective 15 | -- You should look at this if you see signs of memory pressure -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 54 - SP Physical Reads.sql: -------------------------------------------------------------------------------- 1 | -- Top Cached SPs By Total Physical Reads (SQL Server 2014) (Query 54) (SP Physical Reads) 2 | -- Physical reads relate to disk I/O pressure 3 | SELECT TOP(25) p.name AS [SP Name],qs.total_physical_reads AS [TotalPhysicalReads], 4 | qs.total_physical_reads/qs.execution_count AS [AvgPhysicalReads], qs.execution_count, 5 | qs.total_logical_reads,qs.total_elapsed_time, qs.total_elapsed_time/qs.execution_count 6 | AS [avg_elapsed_time], qs.cached_time 7 | FROM sys.procedures AS p WITH (NOLOCK) 8 | INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK) 9 | ON p.[object_id] = qs.[object_id] 10 | WHERE qs.database_id = DB_ID() 11 | AND qs.total_physical_reads > 0 12 | ORDER BY qs.total_physical_reads DESC, qs.total_logical_reads DESC OPTION (RECOMPILE); 13 | 14 | -- This helps you find the most expensive cached stored procedures from a read I/O perspective 15 | -- You should look at this if you see signs of I/O pressure or of memory pressure -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 55 - SP Logical Writes.sql: -------------------------------------------------------------------------------- 1 | -- Top Cached SPs By Total Logical Writes (SQL Server 2014) (Query 55) (SP Logical Writes) 2 | -- Logical writes relate to both memory and disk I/O pressure 3 | SELECT TOP(25) p.name AS [SP Name], qs.total_logical_writes AS [TotalLogicalWrites], 4 | qs.total_logical_writes/qs.execution_count AS [AvgLogicalWrites], qs.execution_count, 5 | ISNULL(qs.execution_count/DATEDIFF(Minute, qs.cached_time, GETDATE()), 0) AS [Calls/Minute], 6 | qs.total_elapsed_time, qs.total_elapsed_time/qs.execution_count AS [avg_elapsed_time], 7 | qs.cached_time 8 | FROM sys.procedures AS p WITH (NOLOCK) 9 | INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK) 10 | ON p.[object_id] = qs.[object_id] 11 | WHERE qs.database_id = DB_ID() 12 | AND qs.total_logical_writes > 0 13 | ORDER BY qs.total_logical_writes DESC OPTION (RECOMPILE); 14 | 15 | -- This helps you find the most expensive cached stored procedures from a write I/O perspective 16 | -- You should look at this if you see signs of I/O pressure or of memory pressure -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 56 - Top IO Statements.sql: -------------------------------------------------------------------------------- 1 | -- Lists the top statements by average input/output usage for the current database (Query 56) (Top IO Statements) 2 | SELECT TOP(50) OBJECT_NAME(qt.objectid, dbid) AS [SP Name], 3 | (qs.total_logical_reads + qs.total_logical_writes) /qs.execution_count AS [Avg IO], qs.execution_count AS [Execution Count], 4 | SUBSTRING(qt.[text],qs.statement_start_offset/2, 5 | (CASE 6 | WHEN qs.statement_end_offset = -1 7 | THEN LEN(CONVERT(nvarchar(max), qt.[text])) * 2 8 | ELSE qs.statement_end_offset 9 | END - qs.statement_start_offset)/2) AS [Query Text] 10 | FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) 11 | CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt 12 | WHERE qt.[dbid] = DB_ID() 13 | ORDER BY [Avg IO] DESC OPTION (RECOMPILE); 14 | 15 | -- Helps you find the most expensive statements for I/O by SP -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 57 - Bad NC Indexes.sql: -------------------------------------------------------------------------------- 1 | -- Possible Bad NC Indexes (writes > reads) (Query 55) (Bad NC Indexes) 2 | SELECT OBJECT_NAME(s.[object_id]) AS [Table Name], i.name AS [Index Name], i.index_id, 3 | i.is_disabled, i.is_hypothetical, i.has_filter, i.fill_factor, 4 | user_updates AS [Total Writes], user_seeks + user_scans + user_lookups AS [Total Reads], 5 | user_updates - (user_seeks + user_scans + user_lookups) AS [Difference] 6 | FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) 7 | INNER JOIN sys.indexes AS i WITH (NOLOCK) 8 | ON s.[object_id] = i.[object_id] 9 | AND i.index_id = s.index_id 10 | WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 11 | AND s.database_id = DB_ID() 12 | AND user_updates > (user_seeks + user_scans + user_lookups) 13 | AND i.index_id > 1 14 | ORDER BY [Difference] DESC, [Total Writes] DESC, [Total Reads] ASC OPTION (RECOMPILE); 15 | 16 | -- Look for indexes with high numbers of writes and zero or very low numbers of reads 17 | -- Consider your complete workload, and how long your instance has been running 18 | -- Investigate further before dropping an index! -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 58 - Missing Indexes.sql: -------------------------------------------------------------------------------- 1 | -- Missing Indexes for current database by Index Advantage (Query 56) (Missing Indexes) 2 | SELECT DISTINCT CONVERT(decimal(18,2), user_seeks * avg_total_user_cost * (avg_user_impact * 0.01)) AS [index_advantage], 3 | migs.last_user_seek, mid.[statement] AS [Database.Schema.Table], 4 | mid.equality_columns, mid.inequality_columns, mid.included_columns, 5 | migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact, 6 | OBJECT_NAME(mid.[object_id]) AS [Table Name], p.rows AS [Table Rows] 7 | FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK) 8 | INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK) 9 | ON migs.group_handle = mig.index_group_handle 10 | INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK) 11 | ON mig.index_handle = mid.index_handle 12 | INNER JOIN sys.partitions AS p WITH (NOLOCK) 13 | ON p.[object_id] = mid.[object_id] 14 | WHERE mid.database_id = DB_ID() 15 | ORDER BY index_advantage DESC OPTION (RECOMPILE); 16 | 17 | -- Look at last user seek time, number of user seeks to help determine source and importance 18 | -- SQL Server is overly eager to add included columns, so beware 19 | -- Do not just blindly add indexes that show up from this query!!! -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 59 - Missing Index Warnings.sql: -------------------------------------------------------------------------------- 1 | -- Find missing index warnings for cached plans in the current database (Query 57) (Missing Index Warnings) 2 | -- Note: This query could take some time on a busy instance 3 | SELECT TOP(25) OBJECT_NAME(objectid) AS [ObjectName], 4 | query_plan, cp.objtype, cp.usecounts 5 | FROM sys.dm_exec_cached_plans AS cp WITH (NOLOCK) 6 | CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp 7 | WHERE CAST(query_plan AS NVARCHAR(MAX)) LIKE N'%MissingIndex%' 8 | AND dbid = DB_ID() 9 | ORDER BY cp.usecounts DESC OPTION (RECOMPILE); 10 | 11 | -- Helps you connect missing indexes to specific stored procedures or queries 12 | -- This can help you decide whether to add them or not -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 60 - Buffer Usage.sql: -------------------------------------------------------------------------------- 1 | -- Breaks down buffers used by current database by object (table, index) in the buffer cache (Query 58) (Buffer Usage) 2 | -- This query can take some time on a large database 3 | SELECT OBJECT_NAME(p.[object_id]) AS [Object Name], p.index_id, 4 | CAST(COUNT(*)/128.0 AS DECIMAL(10, 2)) AS [Buffer size(MB)], 5 | COUNT(*) AS [BufferCount], p.Rows AS [Row Count], 6 | p.data_compression_desc AS [Compression Type] 7 | FROM sys.allocation_units AS a WITH (NOLOCK) 8 | INNER JOIN sys.dm_os_buffer_descriptors AS b WITH (NOLOCK) 9 | ON a.allocation_unit_id = b.allocation_unit_id 10 | INNER JOIN sys.partitions AS p WITH (NOLOCK) 11 | ON a.container_id = p.hobt_id 12 | WHERE b.database_id = CONVERT(int,DB_ID()) 13 | AND p.[object_id] > 100 14 | GROUP BY p.[object_id], p.index_id, p.data_compression_desc, p.[Rows] 15 | ORDER BY [BufferCount] DESC OPTION (RECOMPILE); 16 | 17 | -- Tells you what tables and indexes are using the most memory in the buffer cache 18 | -- It can help identify possible candidates for data compression -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 61 - Table Sizes.sql: -------------------------------------------------------------------------------- 1 | -- Get Table names, row counts, and compression status for clustered index or heap (Query 59) (Table Sizes) 2 | SELECT OBJECT_NAME(object_id) AS [ObjectName], 3 | SUM(Rows) AS [RowCount], data_compression_desc AS [CompressionType] 4 | FROM sys.partitions WITH (NOLOCK) 5 | WHERE index_id < 2 --ignore the partitions from the non-clustered index if any 6 | AND OBJECT_NAME(object_id) NOT LIKE N'sys%' 7 | AND OBJECT_NAME(object_id) NOT LIKE N'queue_%' 8 | AND OBJECT_NAME(object_id) NOT LIKE N'filestream_tombstone%' 9 | AND OBJECT_NAME(object_id) NOT LIKE N'fulltext%' 10 | AND OBJECT_NAME(object_id) NOT LIKE N'ifts_comp_fragment%' 11 | AND OBJECT_NAME(object_id) NOT LIKE N'filetable_updates%' 12 | AND OBJECT_NAME(object_id) NOT LIKE N'xml_index_nodes%' 13 | GROUP BY object_id, data_compression_desc 14 | ORDER BY SUM(Rows) DESC OPTION (RECOMPILE); 15 | 16 | -- Gives you an idea of table sizes, and possible data compression opportunities -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 62 - Table Properties.sql: -------------------------------------------------------------------------------- 1 | -- Get some key table properties (Query 60) (Table Properties) 2 | SELECT [name], create_date, lock_on_bulk_load, is_replicated, has_replication_filter, 3 | is_tracked_by_cdc, lock_escalation_desc, is_memory_optimized, durability_desc 4 | FROM sys.tables WITH (NOLOCK) 5 | ORDER BY [name] OPTION (RECOMPILE); 6 | 7 | -- Gives you some good information about your tables 8 | -- Is Memory optimized and durability description are Hekaton-related properties that are new in SQL Server 2014 -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 63 - Statistics Update.sql: -------------------------------------------------------------------------------- 1 | -- When were Statistics last updated on all indexes? (Query 61) (Statistics Update) 2 | SELECT o.name, i.name AS [Index Name], 3 | STATS_DATE(i.[object_id], i.index_id) AS [Statistics Date], 4 | s.auto_created, s.no_recompute, s.user_created, st.row_count, 5 | s.is_incremental, s.is_temporary, st.used_page_count 6 | FROM sys.objects AS o WITH (NOLOCK) 7 | INNER JOIN sys.indexes AS i WITH (NOLOCK) 8 | ON o.[object_id] = i.[object_id] 9 | INNER JOIN sys.stats AS s WITH (NOLOCK) 10 | ON i.[object_id] = s.[object_id] 11 | AND i.index_id = s.stats_id 12 | INNER JOIN sys.dm_db_partition_stats AS st WITH (NOLOCK) 13 | ON o.[object_id] = st.[object_id] 14 | AND i.[index_id] = st.[index_id] 15 | WHERE o.[type] IN ('U', 'V') 16 | AND st.row_count > 0 17 | ORDER BY STATS_DATE(i.[object_id], i.index_id) DESC OPTION (RECOMPILE); 18 | 19 | -- Helps discover possible problems with out-of-date statistics 20 | -- Also gives you an idea which indexes are most active -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 64 - Index Fragmentation.sql: -------------------------------------------------------------------------------- 1 | -- Get fragmentation info for all indexes above a certain size in the current database (Query 62) (Index Fragmentation) 2 | -- Note: This could take some time on a very large database 3 | SELECT DB_NAME(ps.database_id) AS [Database Name], OBJECT_NAME(ps.OBJECT_ID) AS [Object Name], 4 | i.name AS [Index Name], ps.index_id, ps.index_type_desc, ps.avg_fragmentation_in_percent, 5 | ps.fragment_count, ps.page_count, i.fill_factor, i.has_filter, i.filter_definition 6 | FROM sys.dm_db_index_physical_stats(DB_ID(),NULL, NULL, NULL , N'LIMITED') AS ps 7 | INNER JOIN sys.indexes AS i WITH (NOLOCK) 8 | ON ps.[object_id] = i.[object_id] 9 | AND ps.index_id = i.index_id 10 | WHERE ps.database_id = DB_ID() 11 | AND ps.page_count > 2500 12 | ORDER BY ps.avg_fragmentation_in_percent DESC OPTION (RECOMPILE); 13 | 14 | -- Helps determine whether you have framentation in your relational indexes 15 | -- and how effective your index maintenance strategy is -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 65 - Overall Index Usage - Reads.sql: -------------------------------------------------------------------------------- 1 | --- Index Read/Write stats (all tables in current DB) ordered by Reads (Query 63) (Overall Index Usage - Reads) 2 | SELECT OBJECT_NAME(s.[object_id]) AS [ObjectName], i.index_id, i.name AS [IndexName], 3 | user_seeks + user_scans + user_lookups AS [Reads], s.user_updates AS [Writes], 4 | i.type_desc AS [IndexType], i.fill_factor AS [FillFactor], i.has_filter, i.filter_definition, 5 | s.last_user_scan, s.last_user_lookup, s.last_user_seek 6 | FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) 7 | INNER JOIN sys.indexes AS i WITH (NOLOCK) 8 | ON s.[object_id] = i.[object_id] 9 | WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 10 | AND i.index_id = s.index_id 11 | AND s.database_id = DB_ID() 12 | ORDER BY user_seeks + user_scans + user_lookups DESC OPTION (RECOMPILE); -- Order by reads 13 | 14 | 15 | -- Show which indexes in the current database are most active for Reads -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 66 - Overall Index Usage - Writes.sql: -------------------------------------------------------------------------------- 1 | --- Index Read/Write stats (all tables in current DB) ordered by Writes (Query 64) (Overall Index Usage - Writes) 2 | SELECT OBJECT_NAME(s.[object_id]) AS [ObjectName], i.index_id, i.name AS [IndexName], 3 | s.user_updates AS [Writes], user_seeks + user_scans + user_lookups AS [Reads], 4 | i.type_desc AS [IndexType], i.fill_factor AS [FillFactor], i.has_filter, i.filter_definition, 5 | s.last_system_update, s.last_user_update 6 | FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) 7 | INNER JOIN sys.indexes AS i WITH (NOLOCK) 8 | ON s.[object_id] = i.[object_id] 9 | WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 10 | AND i.index_id = s.index_id 11 | AND s.database_id = DB_ID() 12 | ORDER BY s.user_updates DESC OPTION (RECOMPILE); -- Order by writes 13 | 14 | -- Show which indexes in the current database are most active for Writes -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 67 - Recent Full Backups.sql: -------------------------------------------------------------------------------- 1 | -- Look at recent Full backups for the current database (Query 65) (Recent Full Backups) 2 | SELECT TOP (30) bs.machine_name, bs.server_name, bs.database_name AS [Database Name], bs.recovery_model, 3 | CONVERT (BIGINT, bs.backup_size / 1048576 ) AS [Uncompressed Backup Size (MB)], 4 | CONVERT (BIGINT, bs.compressed_backup_size / 1048576 ) AS [Compressed Backup Size (MB)], 5 | CONVERT (NUMERIC (20,2), (CONVERT (FLOAT, bs.backup_size) / 6 | CONVERT (FLOAT, bs.compressed_backup_size))) AS [Compression Ratio], 7 | DATEDIFF (SECOND, bs.backup_start_date, bs.backup_finish_date) AS [Backup Elapsed Time (sec)], 8 | bs.backup_finish_date AS [Backup Finish Date] 9 | FROM msdb.dbo.backupset AS bs WITH (NOLOCK) 10 | WHERE DATEDIFF (SECOND, bs.backup_start_date, bs.backup_finish_date) > 0 11 | AND bs.backup_size > 0 12 | AND bs.type = 'D' -- Change to L if you want Log backups 13 | AND database_name = DB_NAME(DB_ID()) 14 | ORDER BY bs.backup_finish_date DESC OPTION (RECOMPILE); 15 | 16 | -- Are your backup sizes and times changing over time? -------------------------------------------------------------------------------- /Glenn Berry's DMV Scripts/SQL Server 2014 Diagnostic Information Queries (April 2014)/Query 68 - Database Size History.sql: -------------------------------------------------------------------------------- 1 | -- Get the average full backup size by month for the current database (SQL 2012) (Query 66) (Database Size History) 2 | -- This helps you understand your database growth over time 3 | -- Adapted from Erin Stellato 4 | SELECT [database_name] AS [Database], DATEPART(month,[backup_start_date]) AS [Month], 5 | CAST(AVG([backup_size]/1024/1024) AS DECIMAL(15,2)) AS [Backup Size (MB)], 6 | CAST(AVG([compressed_backup_size]/1024/1024) AS DECIMAL(15,2)) AS [Compressed Backup Size (MB)], 7 | CAST(AVG([backup_size]/[compressed_backup_size]) AS DECIMAL(15,2)) AS [Compression Ratio] 8 | FROM msdb.dbo.backupset WITH (NOLOCK) 9 | WHERE [database_name] = DB_NAME(DB_ID()) 10 | AND [type] = 'D' 11 | AND backup_start_date >= DATEADD(MONTH, -12, GETDATE()) 12 | GROUP BY [database_name],DATEPART(mm,[backup_start_date]) OPTION (RECOMPILE); 13 | 14 | -- The Backup Size (MB) (without backup compression) shows the true size of your database over time 15 | -- This helps you track and plan your data size growth 16 | -- It is possible that your data files may be larger on disk due to empty space within those files -------------------------------------------------------------------------------- /Hardware/CPU/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Hardware/Memory/Query 18 - Buffer Pool Extension Properties.sql: -------------------------------------------------------------------------------- 1 | -- Query 18 - Buffer Pool Extension Properties 2 | 3 | 4 | -- See if buffer pool extension (BPE) is enabled (Query 18) (BPE Enabled) 5 | SELECT [path], state_description, current_size_in_kb, 6 | CAST(current_size_in_kb/1048576.0 AS DECIMAL(10,2)) AS [Size (GB)] 7 | FROM sys.dm_os_buffer_pool_extension_configuration WITH (NOLOCK) OPTION (RECOMPILE); 8 | 9 | -- BPE is available in both Standard Edition and Enterprise Edition -------------------------------------------------------------------------------- /Hardware/Memory/Query 19 - Buffer Pool Extension Usage.sql: -------------------------------------------------------------------------------- 1 | -- Query 19 - Buffer Pool Extension Usage 2 | 3 | -- Look at buffer descriptors to see BPE usage by database (Query 19) (BPE Usage) 4 | SELECT DB_NAME(database_id) AS [Database Name], COUNT(page_id) AS [Page Count], 5 | CAST(COUNT(*)/128.0 AS DECIMAL(10, 2)) AS [Buffer size(MB)], 6 | AVG(read_microsec) AS [Avg Read Time (microseconds)] 7 | FROM sys.dm_os_buffer_descriptors WITH (NOLOCK) 8 | WHERE database_id <> 32767 9 | AND is_in_bpool_extension = 1 10 | GROUP BY DB_NAME(database_id) 11 | ORDER BY [Buffer size(MB)] DESC OPTION (RECOMPILE); 12 | 13 | -- You will see no results if BPE is not enabled or if there is no BPE usage -------------------------------------------------------------------------------- /Hardware/Memory/Query 21 - Memory Dump Information.sql: -------------------------------------------------------------------------------- 1 | -- Query 21 - Memory Dump Information 2 | 3 | -- Get information on location, time and size of any memory dumps from SQL Server (Query 21) (Memory Dump Info) 4 | SELECT [filename], creation_time, size_in_bytes/1048576.0 AS [Size (MB)] 5 | FROM sys.dm_server_memory_dumps WITH (NOLOCK) 6 | ORDER BY creation_time DESC OPTION (RECOMPILE); 7 | 8 | -- This will not return any rows if you have 9 | -- not had any memory dumps (which is a good thing) -------------------------------------------------------------------------------- /Hardware/Memory/Query 32 - Total Buffer Usage by Database.sql: -------------------------------------------------------------------------------- 1 | -- Get total buffer usage by database for current instance (Query 32) (Total Buffer Usage by Database) 2 | WITH AggregateBufferPoolUsage 3 | AS 4 | (SELECT DB_NAME(database_id) AS [Database Name], 5 | CAST(COUNT(*) * 8/1024.0 AS DECIMAL (10,2)) AS [CachedSize] 6 | FROM sys.dm_os_buffer_descriptors WITH (NOLOCK) 7 | WHERE database_id <> 32767 -- ResourceDB 8 | GROUP BY DB_NAME(database_id)) 9 | SELECT ROW_NUMBER() OVER(ORDER BY CachedSize DESC) AS [Buffer Pool Rank], [Database Name], CachedSize AS [Cached Size (MB)], 10 | CAST(CachedSize / SUM(CachedSize) OVER() * 100.0 AS DECIMAL(5,2)) AS [Buffer Pool Percent] 11 | FROM AggregateBufferPoolUsage 12 | ORDER BY [Buffer Pool Rank] OPTION (RECOMPILE); 13 | 14 | -- Tells you how much memory (in the buffer pool) 15 | -- is being used by each database on the instance -------------------------------------------------------------------------------- /Hardware/Memory/Query 40 - System Memory.sql: -------------------------------------------------------------------------------- 1 | -- Good basic information about OS memory amounts and state (Query 40) (System Memory) 2 | SELECT total_physical_memory_kb/1024 AS [Physical Memory (MB)], 3 | available_physical_memory_kb/1024 AS [Available Memory (MB)], 4 | total_page_file_kb/1024 AS [Total Page File (MB)], 5 | available_page_file_kb/1024 AS [Available Page File (MB)], 6 | system_cache_kb/1024 AS [System Cache (MB)], 7 | system_memory_state_desc AS [System Memory State] 8 | FROM sys.dm_os_sys_memory WITH (NOLOCK) OPTION (RECOMPILE); 9 | 10 | -- You want to see "Available physical memory is high" 11 | -- This indicates that you are not under external memory pressure -------------------------------------------------------------------------------- /Hardware/Memory/Query 41 - Process Memory.sql: -------------------------------------------------------------------------------- 1 | 2 | -- SQL Server Process Address space info (Query 41) (Process Memory) 3 | -- (shows whether locked pages is enabled, among other things) 4 | SELECT physical_memory_in_use_kb/1024 AS [SQL Server Memory Usage (MB)], 5 | large_page_allocations_kb, locked_page_allocations_kb, page_fault_count, 6 | memory_utilization_percentage, available_commit_limit_kb, 7 | process_physical_memory_low, process_virtual_memory_low 8 | FROM sys.dm_os_process_memory WITH (NOLOCK) OPTION (RECOMPILE); 9 | 10 | -- You want to see 0 for process_physical_memory_low 11 | -- You want to see 0 for process_virtual_memory_low 12 | -- This indicates that you are not under internal memory pressure -------------------------------------------------------------------------------- /Hardware/Memory/Query 42 - Page Life Expectancy by NUMA Node.sql: -------------------------------------------------------------------------------- 1 | -- Page Life Expectancy (PLE) value for each NUMA node in current instance (Query 42) (PLE by NUMA Node) 2 | SELECT @@SERVERNAME AS [Server Name], [object_name], instance_name, cntr_value AS [Page Life Expectancy] 3 | FROM sys.dm_os_performance_counters WITH (NOLOCK) 4 | WHERE [object_name] LIKE N'%Buffer Node%' -- Handles named instances 5 | AND counter_name = N'Page life expectancy' OPTION (RECOMPILE); 6 | 7 | -- PLE is a good measurement of memory pressure. 8 | -- Higher PLE is better. Watch the trend over time, not the absolute value. 9 | -- This will only return one row for non-NUMA systems. -------------------------------------------------------------------------------- /Hardware/Memory/Query 43 - Memory Grants Pending.sql: -------------------------------------------------------------------------------- 1 | -- Memory Grants Pending value for current instance (Query 43) (Memory Grants Pending) 2 | SELECT @@SERVERNAME AS [Server Name], [object_name], cntr_value AS [Memory Grants Pending] 3 | FROM sys.dm_os_performance_counters WITH (NOLOCK) 4 | WHERE [object_name] LIKE N'%Memory Manager%' -- Handles named instances 5 | AND counter_name = N'Memory Grants Pending' OPTION (RECOMPILE); 6 | 7 | -- Memory Grants Pending above zero for a sustained period is a very strong indicator of memory pressure -------------------------------------------------------------------------------- /Hardware/Memory/Query 44 - Memory Clerk Usage.sql: -------------------------------------------------------------------------------- 1 | -- Memory Clerk Usage for instance (Query 44) (Memory Clerk Usage) 2 | -- Look for high value for CACHESTORE_SQLCP (Ad-hoc query plans) 3 | SELECT TOP(10) [type] AS [Memory Clerk Type], 4 | SUM(pages_kb)/1024 AS [Memory Usage (MB)] 5 | FROM sys.dm_os_memory_clerks WITH (NOLOCK) 6 | GROUP BY [type] 7 | ORDER BY SUM(pages_kb) DESC OPTION (RECOMPILE); 8 | 9 | -- MEMORYCLERK_SQLBUFFERPOOL was new for SQL Server 2012. It should be your highest consumer of memory 10 | 11 | 12 | -- CACHESTORE_SQLCP SQL Plans 13 | -- These are cached SQL statements or batches that aren't in stored procedures, functions and triggers 14 | -- Watch out for high values for CACHESTORE_SQLCP 15 | 16 | -- CACHESTORE_OBJCP Object Plans 17 | -- These are compiled plans for stored procedures, functions and triggers -------------------------------------------------------------------------------- /Hardware/Memory/Query 60 - Buffer Usage.sql: -------------------------------------------------------------------------------- 1 | -- Breaks down buffers used by current database by object (table, index) in the buffer cache (Query 58) (Buffer Usage) 2 | -- This query can take some time on a large database 3 | SELECT OBJECT_NAME(p.[object_id]) AS [Object Name], p.index_id, 4 | CAST(COUNT(*)/128.0 AS DECIMAL(10, 2)) AS [Buffer size(MB)], 5 | COUNT(*) AS [BufferCount], p.Rows AS [Row Count], 6 | p.data_compression_desc AS [Compression Type] 7 | FROM sys.allocation_units AS a WITH (NOLOCK) 8 | INNER JOIN sys.dm_os_buffer_descriptors AS b WITH (NOLOCK) 9 | ON a.allocation_unit_id = b.allocation_unit_id 10 | INNER JOIN sys.partitions AS p WITH (NOLOCK) 11 | ON a.container_id = p.hobt_id 12 | WHERE b.database_id = CONVERT(int,DB_ID()) 13 | AND p.[object_id] > 100 14 | GROUP BY p.[object_id], p.index_id, p.data_compression_desc, p.[Rows] 15 | ORDER BY [BufferCount] DESC OPTION (RECOMPILE); 16 | 17 | -- Tells you what tables and indexes are using the most memory in the buffer cache 18 | -- It can help identify possible candidates for data compression -------------------------------------------------------------------------------- /Hardware/Memory/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Hardware/README.md: -------------------------------------------------------------------------------- 1 | ### Troubleshooting Disk Fragmentation 2 | 3 | [Defragmenting SQL Server database disk drives](https://support.microsoft.com/en-us/help/3195161/defragmenting-sql-server-database-disk-drives) 4 | 5 | [Solving SQL Server Database Physical File Fragmentation](https://www.mssqltips.com/sqlservertip/3008/solving-sql-server-database-physical-file-fragmentation/) 6 | 7 | [Contig - Windows Sysinternals Tool](https://docs.microsoft.com/en-us/sysinternals/downloads/contig) 8 | 9 | [Avoiding SQL Server Fragmentation](https://logicalread.com/avoiding-sql-server-fragmentation-w02/#.XUEJmOgzaHt) 10 | -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Module 3 - IO Related Counters.PerfmonCfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Hardware/Storage Subsystem/Module 3 - IO Related Counters.PerfmonCfg -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Query 22 - Database Filenames and Paths.sql: -------------------------------------------------------------------------------- 1 | -- Query 22 - Database Filenames and Paths 2 | 3 | -- File names and paths for TempDB and all user databases in instance (Query 22) (Database Filenames and Paths) 4 | SELECT DB_NAME([database_id]) AS [Database Name], 5 | [file_id], name, physical_name, type_desc, state_desc, 6 | is_percent_growth, growth, 7 | CONVERT(bigint, growth/128.0) AS [Growth in MB], 8 | CONVERT(bigint, size/128.0) AS [Total Size in MB] 9 | FROM sys.master_files WITH (NOLOCK) 10 | WHERE [database_id] > 4 11 | AND [database_id] <> 32767 12 | OR [database_id] = 2 13 | ORDER BY DB_NAME([database_id]) OPTION (RECOMPILE); 14 | 15 | -- Things to look at: 16 | -- Are data files and log files on different drives? 17 | -- Is everything on the C: drive? 18 | -- Is TempDB on dedicated drives? 19 | -- Is there only one TempDB data file? 20 | -- Are all of the TempDB data files the same size? 21 | -- Are there multiple data files for user databases? 22 | -- Is percent growth enabled for any files (which is bad)? -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Query 23 - Volume Information.sql: -------------------------------------------------------------------------------- 1 | -- Query 23 - Volume Information 2 | 3 | -- Volume info for all LUNS that have database files on the current instance (Query 23) (Volume Info) 4 | SELECT DISTINCT vs.volume_mount_point, vs.file_system_type, 5 | vs.logical_volume_name, CONVERT(DECIMAL(18,2),vs.total_bytes/1073741824.0) AS [Total Size (GB)], 6 | CONVERT(DECIMAL(18,2),vs.available_bytes/1073741824.0) AS [Available Size (GB)], 7 | CAST(CAST(vs.available_bytes AS FLOAT)/ CAST(vs.total_bytes AS FLOAT) AS DECIMAL(18,2)) * 100 AS [Space Free %] 8 | FROM sys.master_files AS f WITH (NOLOCK) 9 | CROSS APPLY sys.dm_os_volume_stats(f.database_id, f.[file_id]) AS vs OPTION (RECOMPILE); 10 | 11 | --Shows you the total and free space on the LUNs where you have database files -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Query 24 - IO Warnings.sql: -------------------------------------------------------------------------------- 1 | -- Look for I/O requests taking longer than 15 seconds in the five most recent SQL Server Error Logs (Query 24) (IO Warnings) 2 | CREATE TABLE #IOWarningResults(LogDate datetime, ProcessInfo sysname, LogText nvarchar(1000)); 3 | 4 | INSERT INTO #IOWarningResults 5 | EXEC xp_readerrorlog 0, 1, N'taking longer than 15 seconds'; 6 | 7 | INSERT INTO #IOWarningResults 8 | EXEC xp_readerrorlog 1, 1, N'taking longer than 15 seconds'; 9 | 10 | INSERT INTO #IOWarningResults 11 | EXEC xp_readerrorlog 2, 1, N'taking longer than 15 seconds'; 12 | 13 | INSERT INTO #IOWarningResults 14 | EXEC xp_readerrorlog 3, 1, N'taking longer than 15 seconds'; 15 | 16 | INSERT INTO #IOWarningResults 17 | EXEC xp_readerrorlog 4, 1, N'taking longer than 15 seconds'; 18 | 19 | SELECT LogDate, ProcessInfo, LogText 20 | FROM #IOWarningResults 21 | ORDER BY LogDate DESC; 22 | 23 | DROP TABLE #IOWarningResults; 24 | 25 | -- Finding 15 second I/O warnings in the SQL Server Error Log is useful evidence of 26 | -- poor I/O performance (which might have many different causes) 27 | -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Query 25 - Drive-Level Latency.sql: -------------------------------------------------------------------------------- 1 | -- Drive level latency information (Query 25) (Drive Level Latency) 2 | -- Based on code from Jimmy May 3 | SELECT [Drive], 4 | CASE 5 | WHEN num_of_reads = 0 THEN 0 6 | ELSE (io_stall_read_ms/num_of_reads) 7 | END AS [Read Latency], 8 | CASE 9 | WHEN io_stall_write_ms = 0 THEN 0 10 | ELSE (io_stall_write_ms/num_of_writes) 11 | END AS [Write Latency], 12 | CASE 13 | WHEN (num_of_reads = 0 AND num_of_writes = 0) THEN 0 14 | ELSE (io_stall/(num_of_reads + num_of_writes)) 15 | END AS [Overall Latency], 16 | CASE 17 | WHEN num_of_reads = 0 THEN 0 18 | ELSE (num_of_bytes_read/num_of_reads) 19 | END AS [Avg Bytes/Read], 20 | CASE 21 | WHEN io_stall_write_ms = 0 THEN 0 22 | ELSE (num_of_bytes_written/num_of_writes) 23 | END AS [Avg Bytes/Write], 24 | CASE 25 | WHEN (num_of_reads = 0 AND num_of_writes = 0) THEN 0 26 | ELSE ((num_of_bytes_read + num_of_bytes_written)/(num_of_reads + num_of_writes)) 27 | END AS [Avg Bytes/Transfer] 28 | FROM (SELECT LEFT(UPPER(mf.physical_name), 2) AS Drive, SUM(num_of_reads) AS num_of_reads, 29 | SUM(io_stall_read_ms) AS io_stall_read_ms, SUM(num_of_writes) AS num_of_writes, 30 | SUM(io_stall_write_ms) AS io_stall_write_ms, SUM(num_of_bytes_read) AS num_of_bytes_read, 31 | SUM(num_of_bytes_written) AS num_of_bytes_written, SUM(io_stall) AS io_stall 32 | FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS vfs 33 | INNER JOIN sys.master_files AS mf WITH (NOLOCK) 34 | ON vfs.database_id = mf.database_id AND vfs.file_id = mf.file_id 35 | GROUP BY LEFT(UPPER(mf.physical_name), 2)) AS tab 36 | ORDER BY [Overall Latency] OPTION (RECOMPILE); 37 | 38 | -- Shows you the drive-level latency for reads and writes, in milliseconds 39 | -- Latency above 20-25ms is usually a problem -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Query 26 - IO Latencies by Database File.sql: -------------------------------------------------------------------------------- 1 | -- Calculates average stalls per read, per write, and per total input/output for each database file (Query 26) (IO Stalls by File) 2 | 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], 3 | CAST(fs.io_stall_write_ms/(1.0 + fs.num_of_writes) AS NUMERIC(10,1)) AS [avg_write_stall_ms], 4 | 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], 5 | 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, 6 | 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], 7 | io_stall_queued_read_ms AS [Resource Governor Total Read IO Latency (ms)], io_stall_queued_write_ms AS [Resource Governor Total Write IO Latency (ms)] 8 | FROM sys.dm_io_virtual_file_stats(null,null) AS fs 9 | INNER JOIN sys.master_files AS mf WITH (NOLOCK) 10 | ON fs.database_id = mf.database_id 11 | AND fs.[file_id] = mf.[file_id] 12 | ORDER BY avg_io_stall_ms DESC OPTION (RECOMPILE); 13 | 14 | -- Helps determine which database files on the entire instance have the most I/O bottlenecks 15 | -- This can help you decide whether certain LUNs are overloaded and whether you might 16 | -- want to move some files to a different location or perhaps improve your I/O performance -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Query 31 - IO Usage by Database.sql: -------------------------------------------------------------------------------- 1 | -- Get I/O utilization by database (Query 31) (IO Usage By Database) 2 | WITH Aggregate_IO_Statistics 3 | AS 4 | (SELECT DB_NAME(database_id) AS [Database Name], 5 | CAST(SUM(num_of_bytes_read + num_of_bytes_written)/1048576 AS DECIMAL(12, 2)) AS io_in_mb 6 | FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS [DM_IO_STATS] 7 | GROUP BY database_id) 8 | SELECT ROW_NUMBER() OVER(ORDER BY io_in_mb DESC) AS [I/O Rank], [Database Name], io_in_mb AS [Total I/O (MB)], 9 | CAST(io_in_mb/ SUM(io_in_mb) OVER() * 100.0 AS DECIMAL(5,2)) AS [I/O Percent] 10 | FROM Aggregate_IO_Statistics 11 | ORDER BY [I/O Rank] OPTION (RECOMPILE); 12 | 13 | -- Helps determine which database is using the most I/O resources on the instance -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Query 47 - IO Stats By File.sql: -------------------------------------------------------------------------------- 1 | -- I/O Statistics by file for the current database (Query 47) (IO Stats By File) 2 | SELECT DB_NAME(DB_ID()) AS [Database Name], df.name AS [Logical Name], vfs.[file_id], 3 | df.physical_name AS [Physical Name], vfs.num_of_reads, vfs.num_of_writes, vfs.io_stall_read_ms, vfs.io_stall_write_ms, 4 | 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], 5 | 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], 6 | (vfs.num_of_reads + vfs.num_of_writes) AS [Writes + Reads], 7 | CAST(vfs.num_of_bytes_read/1048576.0 AS DECIMAL(10, 2)) AS [MB Read], 8 | CAST(vfs.num_of_bytes_written/1048576.0 AS DECIMAL(10, 2)) AS [MB Written], 9 | CAST(100. * vfs.num_of_reads/(vfs.num_of_reads + vfs.num_of_writes) AS DECIMAL(10,1)) AS [# Reads Pct], 10 | CAST(100. * vfs.num_of_writes/(vfs.num_of_reads + vfs.num_of_writes) AS DECIMAL(10,1)) AS [# Write Pct], 11 | 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], 12 | 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] 13 | FROM sys.dm_io_virtual_file_stats(DB_ID(), NULL) AS vfs 14 | INNER JOIN sys.database_files AS df WITH (NOLOCK) 15 | ON vfs.[file_id]= df.[file_id] 16 | OPTION (RECOMPILE); 17 | 18 | -- This helps you characterize your workload better from an I/O perspective for this database 19 | -- It helps you determine whether you has an OLTP or DW/DSS type of workload -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Query 61 - Table Sizes.sql: -------------------------------------------------------------------------------- 1 | -- Get Table names, row counts, and compression status for clustered index or heap (Query 59) (Table Sizes) 2 | SELECT OBJECT_NAME(object_id) AS [ObjectName], 3 | SUM(Rows) AS [RowCount], data_compression_desc AS [CompressionType] 4 | FROM sys.partitions WITH (NOLOCK) 5 | WHERE index_id < 2 --ignore the partitions from the non-clustered index if any 6 | AND OBJECT_NAME(object_id) NOT LIKE N'sys%' 7 | AND OBJECT_NAME(object_id) NOT LIKE N'queue_%' 8 | AND OBJECT_NAME(object_id) NOT LIKE N'filestream_tombstone%' 9 | AND OBJECT_NAME(object_id) NOT LIKE N'fulltext%' 10 | AND OBJECT_NAME(object_id) NOT LIKE N'ifts_comp_fragment%' 11 | AND OBJECT_NAME(object_id) NOT LIKE N'filetable_updates%' 12 | AND OBJECT_NAME(object_id) NOT LIKE N'xml_index_nodes%' 13 | GROUP BY object_id, data_compression_desc 14 | ORDER BY SUM(Rows) DESC OPTION (RECOMPILE); 15 | 16 | -- Gives you an idea of table sizes, and possible data compression opportunities -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Query 67 - Recent Full Backups.sql: -------------------------------------------------------------------------------- 1 | -- Look at recent Full backups for the current database (Query 65) (Recent Full Backups) 2 | SELECT TOP (30) bs.machine_name, bs.server_name, bs.database_name AS [Database Name], bs.recovery_model, 3 | CONVERT (BIGINT, bs.backup_size / 1048576 ) AS [Uncompressed Backup Size (MB)], 4 | CONVERT (BIGINT, bs.compressed_backup_size / 1048576 ) AS [Compressed Backup Size (MB)], 5 | CONVERT (NUMERIC (20,2), (CONVERT (FLOAT, bs.backup_size) / 6 | CONVERT (FLOAT, bs.compressed_backup_size))) AS [Compression Ratio], 7 | DATEDIFF (SECOND, bs.backup_start_date, bs.backup_finish_date) AS [Backup Elapsed Time (sec)], 8 | bs.backup_finish_date AS [Backup Finish Date] 9 | FROM msdb.dbo.backupset AS bs WITH (NOLOCK) 10 | WHERE DATEDIFF (SECOND, bs.backup_start_date, bs.backup_finish_date) > 0 11 | AND bs.backup_size > 0 12 | AND bs.type = 'D' -- Change to L if you want Log backups 13 | AND database_name = DB_NAME(DB_ID()) 14 | ORDER BY bs.backup_finish_date DESC OPTION (RECOMPILE); 15 | 16 | -- Are your backup sizes and times changing over time? -------------------------------------------------------------------------------- /Hardware/Storage Subsystem/Query 68 - Database Size History.sql: -------------------------------------------------------------------------------- 1 | -- Get the average full backup size by month for the current database (SQL 2012) (Query 66) (Database Size History) 2 | -- This helps you understand your database growth over time 3 | -- Adapted from Erin Stellato 4 | SELECT [database_name] AS [Database], DATEPART(month,[backup_start_date]) AS [Month], 5 | CAST(AVG([backup_size]/1024/1024) AS DECIMAL(15,2)) AS [Backup Size (MB)], 6 | CAST(AVG([compressed_backup_size]/1024/1024) AS DECIMAL(15,2)) AS [Compressed Backup Size (MB)], 7 | CAST(AVG([backup_size]/[compressed_backup_size]) AS DECIMAL(15,2)) AS [Compression Ratio] 8 | FROM msdb.dbo.backupset WITH (NOLOCK) 9 | WHERE [database_name] = DB_NAME(DB_ID()) 10 | AND [type] = 'D' 11 | AND backup_start_date >= DATEADD(MONTH, -12, GETDATE()) 12 | GROUP BY [database_name],DATEPART(mm,[backup_start_date]) OPTION (RECOMPILE); 13 | 14 | -- The Backup Size (MB) (without backup compression) shows the true size of your database over time 15 | -- This helps you track and plan your data size growth 16 | -- It is possible that your data files may be larger on disk due to empty space within those files -------------------------------------------------------------------------------- /Hints/README.md: -------------------------------------------------------------------------------- 1 | [Hints (Transact-SQL) - Query](https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-query?view=sql-server-2017) 2 | 3 | [Hints (Transact-SQL) - Table](https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-2017) 4 | 5 | [SQL Hints: NOLOCK and NOWAIT Explained – SQLWizard](https://sqlwizardblog.wordpress.com/2020/04/07/sql-hint-nolock-and-nowait-explained/) 6 | -------------------------------------------------------------------------------- /Indexes/Index Physical Stats.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Indexes/Index Physical Stats.sql -------------------------------------------------------------------------------- /Indexes/Query 57 - Bad NC Indexes.sql: -------------------------------------------------------------------------------- 1 | -- Possible Bad NC Indexes (writes > reads) (Query 55) (Bad NC Indexes) 2 | SELECT OBJECT_NAME(s.[object_id]) AS [Table Name], i.name AS [Index Name], i.index_id, 3 | i.is_disabled, i.is_hypothetical, i.has_filter, i.fill_factor, 4 | user_updates AS [Total Writes], user_seeks + user_scans + user_lookups AS [Total Reads], 5 | user_updates - (user_seeks + user_scans + user_lookups) AS [Difference] 6 | FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) 7 | INNER JOIN sys.indexes AS i WITH (NOLOCK) 8 | ON s.[object_id] = i.[object_id] 9 | AND i.index_id = s.index_id 10 | WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 11 | AND s.database_id = DB_ID() 12 | AND user_updates > (user_seeks + user_scans + user_lookups) 13 | AND i.index_id > 1 14 | ORDER BY [Difference] DESC, [Total Writes] DESC, [Total Reads] ASC OPTION (RECOMPILE); 15 | 16 | -- Look for indexes with high numbers of writes and zero or very low numbers of reads 17 | -- Consider your complete workload, and how long your instance has been running 18 | -- Investigate further before dropping an index! -------------------------------------------------------------------------------- /Indexes/Query 58 - Missing Indexes.sql: -------------------------------------------------------------------------------- 1 | -- Missing Indexes for current database by Index Advantage (Query 56) (Missing Indexes) 2 | SELECT DISTINCT CONVERT(decimal(18,2), user_seeks * avg_total_user_cost * (avg_user_impact * 0.01)) AS [index_advantage], 3 | migs.last_user_seek, mid.[statement] AS [Database.Schema.Table], 4 | mid.equality_columns, mid.inequality_columns, mid.included_columns, 5 | migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact, 6 | OBJECT_NAME(mid.[object_id]) AS [Table Name], p.rows AS [Table Rows] 7 | FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK) 8 | INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK) 9 | ON migs.group_handle = mig.index_group_handle 10 | INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK) 11 | ON mig.index_handle = mid.index_handle 12 | INNER JOIN sys.partitions AS p WITH (NOLOCK) 13 | ON p.[object_id] = mid.[object_id] 14 | WHERE mid.database_id = DB_ID() 15 | ORDER BY index_advantage DESC OPTION (RECOMPILE); 16 | 17 | -- Look at last user seek time, number of user seeks to help determine source and importance 18 | -- SQL Server is overly eager to add included columns, so beware 19 | -- Do not just blindly add indexes that show up from this query!!! -------------------------------------------------------------------------------- /Indexes/Query 59 - Missing Index Warnings.sql: -------------------------------------------------------------------------------- 1 | -- Find missing index warnings for cached plans in the current database (Query 57) (Missing Index Warnings) 2 | -- Note: This query could take some time on a busy instance 3 | SELECT TOP(25) OBJECT_NAME(objectid) AS [ObjectName], 4 | query_plan, cp.objtype, cp.usecounts 5 | FROM sys.dm_exec_cached_plans AS cp WITH (NOLOCK) 6 | CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp 7 | WHERE CAST(query_plan AS NVARCHAR(MAX)) LIKE N'%MissingIndex%' 8 | AND dbid = DB_ID() 9 | ORDER BY cp.usecounts DESC OPTION (RECOMPILE); 10 | 11 | -- Helps you connect missing indexes to specific stored procedures or queries 12 | -- This can help you decide whether to add them or not -------------------------------------------------------------------------------- /Indexes/Query 64 - Index Fragmentation.sql: -------------------------------------------------------------------------------- 1 | -- Get fragmentation info for all indexes above a certain size in the current database (Query 62) (Index Fragmentation) 2 | -- Note: This could take some time on a very large database 3 | SELECT DB_NAME(ps.database_id) AS [Database Name], OBJECT_NAME(ps.OBJECT_ID) AS [Object Name], 4 | i.name AS [Index Name], ps.index_id, ps.index_type_desc, ps.avg_fragmentation_in_percent, 5 | ps.fragment_count, ps.page_count, i.fill_factor, i.has_filter, i.filter_definition 6 | FROM sys.dm_db_index_physical_stats(DB_ID(),NULL, NULL, NULL , N'LIMITED') AS ps 7 | INNER JOIN sys.indexes AS i WITH (NOLOCK) 8 | ON ps.[object_id] = i.[object_id] 9 | AND ps.index_id = i.index_id 10 | WHERE ps.database_id = DB_ID() 11 | AND ps.page_count > 2500 12 | ORDER BY ps.avg_fragmentation_in_percent DESC OPTION (RECOMPILE); 13 | 14 | -- Helps determine whether you have framentation in your relational indexes 15 | -- and how effective your index maintenance strategy is -------------------------------------------------------------------------------- /Indexes/Query 65 - Overall Index Usage - Reads.sql: -------------------------------------------------------------------------------- 1 | --- Index Read/Write stats (all tables in current DB) ordered by Reads (Query 63) (Overall Index Usage - Reads) 2 | SELECT OBJECT_NAME(s.[object_id]) AS [ObjectName], i.index_id, i.name AS [IndexName], 3 | user_seeks + user_scans + user_lookups AS [Reads], s.user_updates AS [Writes], 4 | i.type_desc AS [IndexType], i.fill_factor AS [FillFactor], i.has_filter, i.filter_definition, 5 | s.last_user_scan, s.last_user_lookup, s.last_user_seek 6 | FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) 7 | INNER JOIN sys.indexes AS i WITH (NOLOCK) 8 | ON s.[object_id] = i.[object_id] 9 | WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 10 | AND i.index_id = s.index_id 11 | AND s.database_id = DB_ID() 12 | ORDER BY user_seeks + user_scans + user_lookups DESC OPTION (RECOMPILE); -- Order by reads 13 | 14 | 15 | -- Show which indexes in the current database are most active for Reads -------------------------------------------------------------------------------- /Indexes/Query 66 - Overall Index Usage - Writes.sql: -------------------------------------------------------------------------------- 1 | --- Index Read/Write stats (all tables in current DB) ordered by Writes (Query 64) (Overall Index Usage - Writes) 2 | SELECT OBJECT_NAME(s.[object_id]) AS [ObjectName], i.index_id, i.name AS [IndexName], 3 | s.user_updates AS [Writes], user_seeks + user_scans + user_lookups AS [Reads], 4 | i.type_desc AS [IndexType], i.fill_factor AS [FillFactor], i.has_filter, i.filter_definition, 5 | s.last_system_update, s.last_user_update 6 | FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) 7 | INNER JOIN sys.indexes AS i WITH (NOLOCK) 8 | ON s.[object_id] = i.[object_id] 9 | WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 10 | AND i.index_id = s.index_id 11 | AND s.database_id = DB_ID() 12 | ORDER BY s.user_updates DESC OPTION (RECOMPILE); -- Order by writes 13 | 14 | -- Show which indexes in the current database are most active for Writes -------------------------------------------------------------------------------- /Indexes/README.md: -------------------------------------------------------------------------------- 1 | ### Review Clustered Indexes: 2 | ```sql 3 | SELECT tb.name AS TableName 4 | ,idx.name AS IndexName 5 | ,idx.type_desc AS IndexType 6 | ,cl.name AS ColumnName 7 | ,type.name AS ColumnType 8 | ,cl.is_identity IsIdentity 9 | ,dct.DEFINITION AS DefaultConstraint 10 | ,idx.is_primary_key AS IsPrimaryKey 11 | FROM sys.indexes idx 12 | JOIN sys.index_columns idxc ON idxc.index_id = idx.index_id 13 | AND idxc.object_id = idx.object_id 14 | JOIN sys.columns cl ON idxc.column_id = cl.column_id 15 | AND idxc.object_id = cl.object_id 16 | JOIN sys.tables tb ON idx.object_id = tb.object_id 17 | JOIN sys.types type ON cl.user_type_id = type.user_type_id 18 | LEFT JOIN sys.default_constraints dct ON dct.parent_column_id = cl.column_id 19 | AND dct.parent_object_id = cl.object_id 20 | WHERE idx.type_desc = 'CLUSTERED' 21 | ORDER BY TableName 22 | OPTION (RECOMPILE); 23 | ``` 24 | ### Review HEAP Tables: 25 | ```sql 26 | SELECT o.name AS TableName 27 | ,i.type_desc AS IndexType 28 | ,o.create_date AS CreateDate 29 | FROM sys.indexes i 30 | INNER JOIN sys.objects o ON i.object_id = o.object_id 31 | WHERE i.type_desc = 'HEAP' 32 | AND o.type_desc = 'USER_TABLE' 33 | ORDER BY o.name 34 | OPTION (RECOMPILE); 35 | GO 36 | ``` 37 | 38 | ### Review all HEAP: 39 | ```sql 40 | SELECT o.name AS ObjectName 41 | ,i.type_desc AS IndexType 42 | ,o.type_desc AS ObjectType 43 | ,o.create_date AS CreateDate 44 | FROM sys.indexes i 45 | INNER JOIN sys.objects o ON i.object_id = o.object_id 46 | WHERE i.type_desc = 'HEAP' 47 | ORDER BY o.name 48 | OPTION (RECOMPILE); 49 | GO 50 | ``` 51 | -------------------------------------------------------------------------------- /Indexes/Rebuild or Reorganize Indexes.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Indexes/Rebuild or Reorganize Indexes.sql -------------------------------------------------------------------------------- /Indexes/Size of Indexes.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | OBJECT_SCHEMA_NAME(i.OBJECT_ID) AS SchemaName, 3 | OBJECT_NAME(i.OBJECT_ID) AS TableName, 4 | i.name AS IndexName, 5 | i.index_id AS IndexID, 6 | 8 * SUM(a.used_pages) AS 'Indexsize(KB)' 7 | FROM sys.indexes AS i 8 | JOIN sys.partitions AS p ON p.OBJECT_ID = i.OBJECT_ID AND p.index_id = i.index_id 9 | JOIN sys.allocation_units AS a ON a.container_id = p.partition_id 10 | GROUP BY i.OBJECT_ID,i.index_id,i.name 11 | ORDER BY OBJECT_NAME(i.OBJECT_ID),i.index_id -------------------------------------------------------------------------------- /Indexes/Which Queries Use Which Indexes.sql: -------------------------------------------------------------------------------- 1 | declare @indexName nvarchar(255) = N'[IndexName]' 2 | 3 | ;with xmlnamespaces ('http://schemas.microsoft.com/sqlserver/2004/07/showplan' as sp) 4 | select 5 | n.value(N'@Index', N'sysname') as IndexName, 6 | n.value(N'@Table', N'sysname') as TableName, 7 | replace(t.text, '**', '') as entire_query, 8 | substring (t.text,(s.statement_start_offset/2) + 1, 9 | ((case when s.statement_end_offset = -1 then len(convert(nvarchar(max), t.text)) * 2 10 | else 11 | s.statement_end_offset 12 | end 13 | - s.statement_start_offset)/2) + 1) as query, 14 | p.query_plan 15 | from 16 | sys.dm_exec_query_stats as s 17 | cross apply sys.dm_exec_sql_text(s.sql_handle) as t 18 | cross apply sys.dm_exec_query_plan(s.plan_handle) as p 19 | cross apply query_plan.nodes('//sp:Object') as p1(n) 20 | where 21 | n.value(N'@Index', N'sysname') = @indexName 22 | and n.value(N'@Table', N'sysname') = '[TableName]' -------------------------------------------------------------------------------- /Locks/README.md: -------------------------------------------------------------------------------- 1 | [Locks & Locking Hints](http://sql-articles.com/articles/general/locks-a-locking-hints/) 2 | 3 | [Locking hints SQL Server](https://www.sqlservergeeks.com/locking-hints-sql-server/) 4 | -------------------------------------------------------------------------------- /Log Shipping/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Log Shipping/README.md -------------------------------------------------------------------------------- /Maintenance Plans/README.md: -------------------------------------------------------------------------------- 1 | - [Maintenance Plans - SQL Server | Microsoft Docs](https://docs.microsoft.com/en-us/sql/relational-databases/maintenance-plans/maintenance-plans) 2 | - [SQL Server Maintenance Solution | Ola Hallengren](https://ola.hallengren.com/) 3 | + [GitHub](https://github.com/olahallengren/sql-server-maintenance-solution) 4 | -------------------------------------------------------------------------------- /Maintenance Plans/sp_Maintenance_DeleteOldBackupFiles.sql: -------------------------------------------------------------------------------- 1 | IF EXISTS ( 2 | SELECT * 3 | FROM sys.objects 4 | WHERE object_id = OBJECT_ID(N'[dbo].[sp_Maintenance_DeleteOldBackupFiles]') 5 | AND type IN ( 6 | N'P' 7 | ,N'PC' 8 | ) 9 | ) 10 | DROP PROCEDURE [dbo].[sp_Maintenance_DeleteOldBackupFiles] 11 | GO 12 | 13 | CREATE PROCEDURE [dbo].[sp_Maintenance_DeleteOldBackupFiles] 14 | @path NVARCHAR(256), 15 | @extension NVARCHAR(10), 16 | @age_hrs INT 17 | AS 18 | BEGIN 19 | SET NOCOUNT ON; 20 | DECLARE @DeleteDateTime DATETIME = DateAdd(hh, - @age_hrs, GetDate()) 21 | DECLARE @DeleteDate NVARCHAR(50) = (Select Replace(Convert(nvarchar, @DeleteDateTime, 111), '/', '-') + 'T' + Convert(nvarchar, @DeleteDateTime, 108)) 22 | EXECUTE master.dbo.xp_delete_file 0, @path, @extension, @DeleteDate, 1 23 | END 24 | 25 | /* 26 | 27 | [dbo].[sp_Maintenance_DeleteOldBackupFiles] 'C:\Data\Backup', 'bak', 168 28 | 29 | */ 30 | -------------------------------------------------------------------------------- /Memory-Optimized Tables/README.md: -------------------------------------------------------------------------------- 1 | - [Introduction to Memory-Optimized Tables - SQL Server | Microsoft Docs](https://docs.microsoft.com/en-us/sql/relational-databases/in-memory-oltp/introduction-to-memory-optimized-tables) 2 | -------------------------------------------------------------------------------- /Query Plan Analysis/Currently Running Queries.sql: -------------------------------------------------------------------------------- 1 | SELECT DB_NAME(req.database_id) AS db_name 2 | ,sqltext.TEXT 3 | ,req.session_id 4 | ,req.STATUS 5 | ,req.command 6 | ,req.start_time 7 | ,req.cpu_time 8 | ,req.total_elapsed_time 9 | ,req.plan_handle 10 | ,queryplan.query_plan 11 | ,c.client_net_address 12 | ,s.login_name 13 | ,s.login_time 14 | ,s.program_name 15 | ,s.host_name 16 | ,s.host_process_id 17 | ,s.client_interface_name 18 | ,s.client_version 19 | --,req.* 20 | --,c.* 21 | --,s.* 22 | FROM sys.dm_exec_requests req 23 | JOIN sys.dm_exec_connections c ON req.connection_id = c.connection_id 24 | JOIN sys.dm_exec_sessions s ON req.session_id = s.session_id 25 | CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext 26 | CROSS APPLY sys.dm_exec_query_plan(req.plan_handle) AS queryplan 27 | 28 | /* 29 | 30 | -- Kill session_id 31 | KILL session_id; 32 | 33 | -- Remove the specific query plan from the cache using the plan handle from the above query 34 | DBCC FREEPROCCACHE (0x050011007A2CC30E204991F30200000001000000000000000000000000000000000000000000000000000000); 35 | 36 | */ 37 | -------------------------------------------------------------------------------- /Query Plan Analysis/Examining Query Execution Plans.sql: -------------------------------------------------------------------------------- 1 | -- Clearing the plan cache (don't do this in production) 2 | DBCC FREEPROCCACHE; 3 | GO 4 | 5 | -- Execute this query 6 | SELECT * 7 | FROM AspNetUsers 8 | 9 | -- sys.dm_exec_cached_plans 10 | SELECT [size_in_bytes], 11 | [cacheobjtype], 12 | [objtype], 13 | [plan_handle] 14 | FROM sys.dm_exec_cached_plans; 15 | 16 | -- Let's find our plan based on query text 17 | SELECT [cp].[size_in_bytes], 18 | [cp].[cacheobjtype], 19 | [cp].[objtype], 20 | [cp].[plan_handle], 21 | [dest].[text] 22 | FROM [sys].[dm_exec_cached_plans] AS cp 23 | CROSS APPLY [sys].[dm_exec_sql_text]([cp].[plan_handle]) AS dest 24 | WHERE [dest].[text] LIKE '%AspNetUsers%'; 25 | 26 | -- sys.dm_exec_query_plan 27 | SELECT [dbid], 28 | [query_plan] 29 | FROM sys.dm_exec_query_plan(0x060006008AFD781E801181ADB802000001000000000000000000000000000000000000000000000000000000); 30 | GO 31 | 32 | -- sys.dm_exec_text_query_plan 33 | SELECT [dbid], 34 | [query_plan] 35 | FROM sys.dm_exec_text_query_plan(0x0600060006861C06609F5A9FB802000001000000000000000000000000000000000000000000000000000000, 36 | 0, -1); 37 | GO 38 | -------------------------------------------------------------------------------- /Query Plan Analysis/README.md: -------------------------------------------------------------------------------- 1 | ### Tools: 2 | [SentryOne Plan Explorer - SQL Server Query Tuning](https://www.sentryone.com/plan-explorer) 3 | 4 | ### DMVs: 5 | - sys.dm_exec_cached_plans 6 | - sys.dm_exec_query_stats 7 | - sys.dm_exec_procedure_stats 8 | - sys.dm_exec_query_plan 9 | - sys.dm_exec_sql_text 10 | 11 | ### Query Tree: 12 | ![alt text](imgs/query-tree.png) 13 | 14 | ### Common Operators: [*link*](https://docs.microsoft.com/en-us/sql/relational-databases/showplan-logical-and-physical-operators-reference) 15 | 16 | **Scans**: 17 | - ![alt text](imgs/table-scan-32x.gif) **Table Scan** 18 | - ![alt text](imgs/clustered-index-scan-32x.gif) **Clustered Index Scan** 19 | - ![alt text](imgs/nonclustered-index-scan-32x.gif) **Index Scan** 20 | 21 | **Seeks**: 22 | - ![alt text](imgs/clustered-index-seek-32x.gif) **Clustered Index Seek** 23 | - ![alt text](imgs/index-seek-32x.gif) **Index Seek** 24 | 25 | **Lookups**: 26 | - ![alt text](imgs/bookmark-lookup-32x.gif) **Key Lookup** 27 | - ![alt text](imgs/rid-nonclust-locate-32x.gif) **RID Lookup** 28 | 29 | **Joins**: 30 | - ![alt text](imgs/nested-loops-32x.gif) **Nested Loops** *(HINT: LOOP JOIN)* 31 | - ![alt text](imgs/merge-join-32x.gif) **Merge Join** 32 | - ![alt text](imgs/hash-match-32x.gif) **Hash Match** *(HINT: HASH JOIN)* 33 | 34 | **Spools:** *The **Spool** operator saves an intermediate query result to the **tempdb** database*. 35 | - ![alt text](imgs/spool-32x.gif) **Eager Spool** 36 | - ![alt text](imgs/spool-32x.gif) **Lazy Spool** 37 | 38 | **Parallelism**: 39 | - ![alt text](imgs/parallelism-distribute-stream.gif) **Distribute Streams** 40 | - ![alt text](imgs/parallelism-repartition-stream.gif) **Repartition Streams** 41 | - ![alt text](imgs/parallelism-32x.gif) **Gather Streams** 42 | - ![alt text](imgs/bitmap-32x.gif) **Bitmap** 43 | 44 | ![alt text](imgs/stream-aggregate-32x.gif) **Stream Aggregate** *(GROUP BY)* 45 | 46 | ![alt text](imgs/filter-32x.gif) **Filter** *(HAVING)* 47 | 48 | ![alt text](imgs/sort-32x.gif) **Sort** *(ORDER BY)* 49 | 50 | ![alt text](imgs/compute-scalar-32x.gif) **Compute Scalar**: *(function expression)* 51 | 52 | ![alt text](imgs/concatenation-32x.gif) **Concatenation** *(UNION ALL)* 53 | -------------------------------------------------------------------------------- /Query Plan Analysis/Search Implicit Conversion in Plans.sql: -------------------------------------------------------------------------------- 1 | DECLARE @dbname SYSNAME = QUOTENAME(DB_NAME()); 2 | 3 | WITH XMLNAMESPACES 4 | (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan') 5 | SELECT 6 | stmt.value('(@StatementText)[1]', 'varchar(max)'), 7 | t.value('(ScalarOperator/Identifier/ColumnReference/@Database)[1]', 'varchar(128)') AS [Database], 8 | t.value('(ScalarOperator/Identifier/ColumnReference/@Schema)[1]', 'varchar(128)') AS [Schema], 9 | t.value('(ScalarOperator/Identifier/ColumnReference/@Table)[1]', 'varchar(128)') AS [Table], 10 | t.value('(ScalarOperator/Identifier/ColumnReference/@Column)[1]', 'varchar(128)') AS [Column], 11 | ic.DATA_TYPE AS ConvertFrom, 12 | ic.CHARACTER_MAXIMUM_LENGTH AS ConvertFromLength, 13 | t.value('(@DataType)[1]', 'varchar(128)') AS ConvertTo, 14 | t.value('(@Length)[1]', 'int') AS ConvertToLength, 15 | query_plan 16 | FROM sys.dm_exec_cached_plans AS cp 17 | CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp 18 | CROSS APPLY query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS x(stmt) 19 | CROSS APPLY stmt.nodes('//Convert[@Implicit="1"]') AS n(t) -- all implicit conversion 20 | --CROSS APPLY stmt.nodes('//Predicate/ScalarOperator/Compare/ScalarOperator/Convert[@Implicit="1"]') AS n(t) -- implicit in predicate 21 | --CROSS APPLY stmt.nodes('//Predicate/ScalarOperator/Compare') AS n(t) -- normal comparison in predicate 22 | JOIN INFORMATION_SCHEMA.COLUMNS AS ic 23 | ON QUOTENAME(ic.TABLE_SCHEMA) = t.value('(ScalarOperator/Identifier/ColumnReference/@Schema)[1]', 'varchar(128)') 24 | AND QUOTENAME(ic.TABLE_NAME) = t.value('(ScalarOperator/Identifier/ColumnReference/@Table)[1]', 'varchar(128)') 25 | AND ic.COLUMN_NAME = t.value('(ScalarOperator/Identifier/ColumnReference/@Column)[1]', 'varchar(128)') 26 | WHERE t.value('(ScalarOperator/Identifier/ColumnReference/@Database)[1]', 'varchar(128)') = @dbname 27 | -------------------------------------------------------------------------------- /Query Plan Analysis/Search Query Plans.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | [qs].[plan_generation_num] AS [VersionOfPlan] 3 | , [qs].[execution_count] AS [ExecutionsOfCurrentPlan] 4 | , SUBSTRING ([st].[text], 5 | ([qs].[statement_start_offset] / 2) + 1, 6 | ((CASE [statement_end_offset] 7 | WHEN -1 THEN DATALENGTH ([st].[text]) 8 | ELSE [qs].[statement_end_offset] END 9 | - [qs].[statement_start_offset]) / 2) + 1) 10 | AS [StatementText] 11 | , [st].[text] 12 | , [qs].[statement_start_offset] AS [offset] 13 | , [qs].[statement_end_offset] AS [offset_end] 14 | , [qp].[query_plan] AS [Query Plan XML] 15 | , [qs].[query_hash] AS [Query Fingerprint] 16 | , [qs].[query_plan_hash] AS [Query Plan Fingerprint] 17 | --,* 18 | FROM [sys].[dm_exec_query_stats] AS [qs] 19 | CROSS APPLY [sys].[dm_exec_query_plan] ([qs].[plan_handle]) AS [qp] 20 | CROSS APPLY [sys].[dm_exec_sql_text] ([qs].[sql_handle]) AS [st] 21 | --WHERE [st].[text] like '%%' 22 | -------------------------------------------------------------------------------- /Query Plan Analysis/Search Stored Procedures Query Plans.sql: -------------------------------------------------------------------------------- 1 | SELECT OBJECT_NAME([ps].[object_id], [ps].[database_id]) 2 |             AS [ProcedureName] 3 |  , [ps].[execution_count] AS [ProcedureExecutes] 4 |  , [qs].[plan_generation_num] AS [VersionOfPlan] 5 |  , [qs].[execution_count] AS [ExecutionsOfCurrentPlan] 6 |  , SUBSTRING ([st].[text], 7 |   ([qs].[statement_start_offset] / 2) + 1, 8 |      ((CASE [statement_end_offset] 9 |    WHEN -1 THEN DATALENGTH ([st].[text]) 10 |       ELSE [qs].[statement_end_offset] END 11 |    - [qs].[statement_start_offset]) / 2) + 1) 12 |       AS [StatementText] 13 |     , [qs].[statement_start_offset] AS [offset] 14 |     , [qs].[statement_end_offset] AS [offset_end] 15 |     , [qp].[query_plan] AS [Query Plan XML] 16 |     , [qs].[query_hash] AS [Query Fingerprint] 17 |     , [qs].[query_plan_hash] AS [Query Plan Fingerprint] 18 | FROM [sys].[dm_exec_procedure_stats] AS [ps] 19 | JOIN [sys].[dm_exec_query_stats] AS [qs] ON [ps].[plan_handle] = [qs].[plan_handle] 20 | CROSS APPLY [sys].[dm_exec_query_plan] ([qs].[plan_handle]) AS [qp] 21 | CROSS APPLY [sys].[dm_exec_sql_text] ([qs].[sql_handle]) AS [st] 22 | WHERE [ps].[database_id] = DB_ID() 23 | ORDER BY [ProcedureName], [qs].[statement_start_offset]; 24 | -------------------------------------------------------------------------------- /Query Plan Analysis/Troubleshooting Scripts/README.md: -------------------------------------------------------------------------------- 1 | **When was SQL Server restarted:** 2 | ```sql 3 | SELECT sqlserver_start_time FROM sys.dm_os_sys_info 4 | ``` 5 | 6 | **When Was SQL Server Installed:** 7 | ```sql 8 | SELECT @@SERVERNAME AS [Server Name], create_date AS [SQL Server Install Date] 9 | FROM sys.server_principals WITH (NOLOCK) 10 | WHERE name = N'NT AUTHORITY\SYSTEM' 11 | OR name = N'NT AUTHORITY\NETWORK SERVICE' 12 | OPTION (RECOMPILE); 13 | ``` 14 | **DB Compatibility Level:** 15 | ```sql 16 | SELECT name, database_id, create_date, compatibility_level 17 | FROM sys.databases 18 | ``` 19 | 20 | **View Query Plan:** 21 | ```sql 22 | select * 23 | from sys.dm_exec_query_plan (paste plan_handle here) 24 | ``` 25 | -------------------------------------------------------------------------------- /Query Plan Analysis/Troubleshooting Scripts/Verifying Instance Workload Complexity.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Trivial plan 3 | -- No joins, obvious plan 4 | -- Search 0 - Transaction Processing 5 | -- Serial plan, low cost (<.2) 6 | -- Search 1 - Quick Plan 7 | -- Cost < 1.0 8 | -- Search 2 - Full Optimization 9 | -- Parallelism considered 10 | -- All rules evaluated 11 | SELECT [counter] , 12 | [occurrence] , 13 | [value] 14 | FROM [sys].[dm_exec_query_optimizer_info] 15 | WHERE [counter] IN 16 | ( 'trivial plan', 17 | 'search 0', 18 | 'search 1', 19 | 'search 2' ); 20 | 21 | -- Is this what you expected? 22 | 23 | -- Hint usage? 24 | SELECT [counter] , 25 | [occurrence] , 26 | [value] 27 | FROM [sys].[dm_exec_query_optimizer_info] 28 | WHERE [counter] IN 29 | ( 'order hint', 30 | 'join hint' ); 31 | -------------------------------------------------------------------------------- /Query Plan Analysis/Troubleshooting Scripts/estimated rows vs actual rows.sql: -------------------------------------------------------------------------------- 1 | -- Checking estimated rows (from the plan) versus actual rows 2 | SELECT t.[text], 3 | p.[query_plan], 4 | s.[last_execution_time], 5 | p.[query_plan].value('(//@EstimateRows)[1]', 'varchar(128)') AS [estimated_rows], 6 | s.[last_rows] 7 | FROM sys.[dm_exec_query_stats] AS [s] 8 | CROSS APPLY sys.[dm_exec_sql_text](sql_handle) AS [t] 9 | CROSS APPLY sys.[dm_exec_query_plan](plan_handle) AS [p] 10 | WHERE DATEDIFF(mi, s.[last_execution_time], GETDATE()) < 10 11 | AND t.[dbid] = DB_ID() 12 | GO 13 | -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/bitmap-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/bitmap-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/bookmark-lookup-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/bookmark-lookup-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/clustered-index-scan-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/clustered-index-scan-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/clustered-index-seek-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/clustered-index-seek-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/compute-scalar-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/compute-scalar-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/concatenation-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/concatenation-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/filter-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/filter-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/hash-match-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/hash-match-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/index-seek-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/index-seek-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/merge-join-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/merge-join-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/nested-loops-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/nested-loops-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/nonclustered-index-scan-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/nonclustered-index-scan-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/parallelism-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/parallelism-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/parallelism-distribute-stream.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/parallelism-distribute-stream.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/parallelism-repartition-stream.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/parallelism-repartition-stream.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/query-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/query-tree.png -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/rid-nonclust-locate-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/rid-nonclust-locate-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/sort-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/sort-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/spool-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/spool-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/stream-aggregate-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/stream-aggregate-32x.gif -------------------------------------------------------------------------------- /Query Plan Analysis/imgs/table-scan-32x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Plan Analysis/imgs/table-scan-32x.gif -------------------------------------------------------------------------------- /Query Store/1 Creating Test DB.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Create a database to use for testing 3 | */ 4 | DROP DATABASE IF EXISTS [Movies]; 5 | GO 6 | 7 | CREATE DATABASE [Movies] 8 | ON PRIMARY 9 | (NAME = N'Movies', FILENAME = N'C:\Databases\Movies\Movies.mdf' , 10 | SIZE = 262144KB , FILEGROWTH = 65536KB ) 11 | LOG ON 12 | (NAME = N'Movies_log', FILENAME = N'C:\Databases\Movies\Movies_log.ldf' , 13 | SIZE = 131072KB , FILEGROWTH = 65536KB ); 14 | GO 15 | 16 | ALTER DATABASE [Movies] SET RECOVERY SIMPLE; 17 | GO 18 | 19 | /* 20 | Create a table and add some data 21 | */ 22 | USE [Movies]; 23 | GO 24 | 25 | CREATE TABLE [dbo].[MovieInfo] ( 26 | [MovieID] INT IDENTITY(1,1) PRIMARY KEY, 27 | [MovieName] VARCHAR(800), 28 | [ReleaseDate] SMALLDATETIME, 29 | [Rating] VARCHAR(5) 30 | ); 31 | GO 32 | 33 | INSERT INTO [dbo].[MovieInfo] ( 34 | [MovieName], [ReleaseDate], [Rating] 35 | ) 36 | VALUES 37 | ('IronMan', '2008-05-02 00:00:00', 'PG-13'), 38 | ('Joy', '2016-12-25', 'PG-13'), 39 | ('Caddyshack', '1980-07-25', 'R'), 40 | ('The Martian', '2015-10-02', 'PG-13'), 41 | ('Apollo 13', '1995-05-30 00:00:00', 'PG'), 42 | ('The Hunt for Red October', '1990-03-02 00:00:00', 'PG'), 43 | ('A Few Good Men', '1994-12-11 00:00:00', 'R'), 44 | ('Memento', '2000-10-11', 'R'), 45 | ('The Truman Show', '1998-06-05 00:00:00', 'PG-13'), 46 | ('All The President''s Men', '1976-04-09 00:00:00', 'R'), 47 | ('The Right Stuff', '1983-10-21 00:00:00', 'PG-13'), 48 | ('The Blind Side', '2009-11-20', 'PG-13'), 49 | ('The Natural', '1984-05-11 00:00:00', 'PG'), 50 | ('The Hangover', '2009-06-05 00:00:00', 'R'), 51 | ('The Incredibles', '2004-11-05 00:00:00', 'PG'); 52 | GO 53 | 54 | 55 | CREATE TABLE [dbo].[Actors]( 56 | [ActorID] INT IDENTITY(1,1) PRIMARY KEY, 57 | [FirstName] VARCHAR(100), 58 | [LastName] VARCHAR(200), 59 | [DOB] SMALLDATETIME 60 | ); 61 | GO 62 | 63 | INSERT INTO [dbo].[Actors]( 64 | [FirstName], [LastName], [DOB] 65 | ) 66 | VALUES 67 | ('Jennifer', 'Lawrence', '1990-08-15'), 68 | ('Robert', 'Redford', '1936-08-18'), 69 | ('Demi', 'Moore', '1962-11-11'), 70 | ('Alec', 'Baldwin', '1958-01-03'), 71 | ('Sandra', 'Bullock', '1964-07-26'), 72 | ('Tom', 'Hanks', '1956-07-09'); 73 | GO 74 | 75 | CREATE TABLE [dbo].[Cast]( 76 | [MovieID] INT, 77 | [ActorID] INT 78 | ); 79 | GO 80 | 81 | INSERT INTO [dbo].[Cast]( 82 | [MovieID], [ActorID]) 83 | VALUES 84 | (2, 1), 85 | (10, 2), 86 | (13, 2), 87 | (7, 3), 88 | (6, 4), 89 | (12, 5), 90 | (5, 6); 91 | GO 92 | -------------------------------------------------------------------------------- /Query Store/README.md: -------------------------------------------------------------------------------- 1 | ### [Monitoring performance by using the Query Store](https://docs.microsoft.com/en-us/sql/relational-databases/performance/monitoring-performance-by-using-the-query-store) 2 | 3 | ### [Best Practice with the Query Store](https://docs.microsoft.com/en-us/sql/relational-databases/performance/best-practice-with-the-query-store) 4 | 5 | ### [How Query Store Collects Data](https://docs.microsoft.com/en-us/sql/relational-databases/performance/how-query-store-collects-data) 6 | 7 | ![alt text](imgs/query-store-process-2processor.png) 8 | 9 | ![alt text](imgs/query-store-process-3.png) 10 | -------------------------------------------------------------------------------- /Query Store/imgs/query-store-process-2processor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Store/imgs/query-store-process-2processor.png -------------------------------------------------------------------------------- /Query Store/imgs/query-store-process-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Query Store/imgs/query-store-process-3.png -------------------------------------------------------------------------------- /Statistics/Query 63 - Statistics Update.sql: -------------------------------------------------------------------------------- 1 | -- When were Statistics last updated on all indexes? (Query 61) (Statistics Update) 2 | SELECT o.name, i.name AS [Index Name], 3 | STATS_DATE(i.[object_id], i.index_id) AS [Statistics Date], 4 | s.auto_created, s.no_recompute, s.user_created, st.row_count, 5 | s.is_incremental, s.is_temporary, st.used_page_count 6 | FROM sys.objects AS o WITH (NOLOCK) 7 | INNER JOIN sys.indexes AS i WITH (NOLOCK) 8 | ON o.[object_id] = i.[object_id] 9 | INNER JOIN sys.stats AS s WITH (NOLOCK) 10 | ON i.[object_id] = s.[object_id] 11 | AND i.index_id = s.stats_id 12 | INNER JOIN sys.dm_db_partition_stats AS st WITH (NOLOCK) 13 | ON o.[object_id] = st.[object_id] 14 | AND i.[index_id] = st.[index_id] 15 | WHERE o.[type] IN ('U', 'V') 16 | AND st.row_count > 0 17 | ORDER BY STATS_DATE(i.[object_id], i.index_id) DESC OPTION (RECOMPILE); 18 | 19 | -- Helps discover possible problems with out-of-date statistics 20 | -- Also gives you an idea which indexes are most active -------------------------------------------------------------------------------- /Statistics/README.md: -------------------------------------------------------------------------------- 1 | ```sql 2 | SELECT [name], 3 | [database_id], 4 | [is_auto_create_stats_on], 5 | [is_auto_update_stats_on], 6 | [is_auto_update_stats_async_on] 7 | FROM sys.[databases] 8 | WHERE [database_id] = DB_ID(); 9 | GO 10 | ``` 11 | 12 | ```sql 13 | -- Checking statistics for a specific table 14 | EXEC sp_helpstats '[table_name]', 'ALL' 15 | GO 16 | 17 | -- Using the catalog view 18 | SELECT object_name([object_id]) AS [object_name], 19 | [object_id], 20 | [name], 21 | [stats_id], 22 | [auto_created], 23 | [user_created], 24 | [no_recompute], 25 | STATS_DATE(object_id, stats_id) AS [stats_date] 26 | FROM sys.[stats] AS s 27 | WHERE object_name([object_id]) = 'table_name'; 28 | GO 29 | 30 | -- Confirming indexes for a table 31 | EXEC sp_helpindex 'table_name'; 32 | GO 33 | ``` 34 | 35 | ```sql 36 | DBCC SHOW_STATISTICS([table_name], [statistics_name]) 37 | GO 38 | ``` 39 | 40 | ```sql 41 | UPDATE STATISTICS [table_name] ([statistics_name]) 42 | WITH FULLSCAN; 43 | GO 44 | ``` 45 | 46 | ```sql 47 | UPDATE STATISTICS [table_name] 48 | WITH FULLSCAN; 49 | GO 50 | ``` 51 | 52 | ```sql 53 | EXEC sp_MSForEachTable 'UPDATE STATISTICS ? WITH FULLSCAN;' 54 | GO 55 | ``` 56 | -------------------------------------------------------------------------------- /Temporal Tables/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Transaction Isolation Levels/README.md: -------------------------------------------------------------------------------- 1 | [Transaction Isolation Levels](https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/transaction-isolation-levels?view=sql-server-2017) 2 | 3 | [Transaction Isolation Levels](https://www.sqlservercentral.com/articles/isolation-levels-in-sql-server) 4 | 5 | [SET TRANSACTION ISOLATION LEVEL (Transact-SQL)](https://docs.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql?view=sql-server-2017) 6 | 7 | [Transaction Isolation Levels](https://www.geeksforgeeks.org/transaction-isolation-levels-dbms/) 8 | -------------------------------------------------------------------------------- /Transactional Replication/compare tables and rows count/check_last_update.bat: -------------------------------------------------------------------------------- 1 | sqlcmd -S ServerIP -U UserName -P Password -d DBName -i "script-withdate.sql" -o "pub-withdate.txt" -W 2 | sqlcmd -S ServerIP -U UserName -P Password -d DBName -i "script-withdate.sql" -o "sub-withdate.txt" -W 3 | "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe" -diff sub-withdate.txt pub-withdate.txt -------------------------------------------------------------------------------- /Transactional Replication/compare tables and rows count/check_row_count_only.bat: -------------------------------------------------------------------------------- 1 | sqlcmd -S ServerIP -U UserName -P Password -d DBName -i "script-nodate.sql" -o "pub-nodate.txt" -W 2 | sqlcmd -S ServerIP -U UserName -P Password -d DBName -i "script-nodate.sql" -o "sub-nodate.txt" -W 3 | "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe" -diff sub-nodate.txt pub-nodate.txt 4 | -------------------------------------------------------------------------------- /Transactional Replication/compare tables and rows count/script-nodate.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | QUOTENAME(SCHEMA_NAME(sOBJ.schema_id)) + '.' + QUOTENAME(sOBJ.name) AS [Table Name] 3 | ,SUM(sdmvPTNS.row_count) AS [Row Count] 4 | FROM sys.objects AS sOBJ 5 | INNER JOIN sys.dm_db_partition_stats AS sdmvPTNS ON sOBJ.object_id = sdmvPTNS.object_id 6 | LEFT JOIN sys.dm_db_index_usage_stats id ON sOBJ.object_id = id.object_id 7 | AND id.index_id = sdmvPTNS.index_id 8 | AND id.database_id = DB_ID() 9 | WHERE sOBJ.type = 'U' 10 | AND sOBJ.is_ms_shipped = 0x0 11 | AND sdmvPTNS.index_id < 2 12 | GROUP BY sOBJ.schema_id 13 | ,sOBJ.name 14 | ,id.last_user_update 15 | ORDER BY [Table Name] 16 | GO -------------------------------------------------------------------------------- /Transactional Replication/compare tables and rows count/script-withdate.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | QUOTENAME(SCHEMA_NAME(sOBJ.schema_id)) + '.' + QUOTENAME(sOBJ.name) 3 | + ' ('+ cast( SUM(sdmvPTNS.row_count) as varchar(100)) + ')' 4 | + CHAR(10) + '('+ ISNULL(FORMAT(id.last_user_update, 'yyyy-MM-dd HH:mm:ss'),'') + ')' AS [Table Name] 5 | FROM sys.objects AS sOBJ 6 | INNER JOIN sys.dm_db_partition_stats AS sdmvPTNS ON sOBJ.object_id = sdmvPTNS.object_id 7 | LEFT JOIN sys.dm_db_index_usage_stats id ON sOBJ.object_id = id.object_id 8 | AND id.index_id = sdmvPTNS.index_id 9 | AND id.database_id = DB_ID() 10 | WHERE sOBJ.type = 'U' 11 | AND sOBJ.is_ms_shipped = 0x0 12 | AND sdmvPTNS.index_id < 2 13 | GROUP BY sOBJ.schema_id 14 | ,sOBJ.name 15 | ,id.last_user_update 16 | ORDER BY [Table Name] 17 | GO -------------------------------------------------------------------------------- /Transactional Replication/reinitialize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Transactional Replication/reinitialize.png -------------------------------------------------------------------------------- /Transactional Replication/view-snapshot-agent-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Transactional Replication/view-snapshot-agent-status.png -------------------------------------------------------------------------------- /Transactional Replication/view-synchronization-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Transactional Replication/view-synchronization-status.png -------------------------------------------------------------------------------- /Utilities/Create Or Alter Stored Procedure.sql: -------------------------------------------------------------------------------- 1 | IF NOT EXISTS ( 2 | SELECT * 3 | FROM sys.objects 4 | WHERE object_id = OBJECT_ID(N'[dbo].[StoredProcedureName]') 5 | AND type IN ( 6 | N'P' 7 | ,N'PC' 8 | ) 9 | ) 10 | BEGIN 11 | EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[StoredProcedureName] AS' 12 | END 13 | GO 14 | 15 | ALTER PROCEDURE [dbo].[StoredProcedureName] 16 | AS 17 | BEGIN 18 | 19 | -- BODY HERE 20 | 21 | END 22 | GO 23 | -------------------------------------------------------------------------------- /Utilities/Drop If Stored Procedure Exists.sql: -------------------------------------------------------------------------------- 1 | IF EXISTS ( 2 | SELECT * 3 | FROM sys.objects 4 | WHERE object_id = OBJECT_ID(N'[dbo].[StoredProcedureName]') 5 | AND type IN ( 6 | N'P' 7 | ,N'PC' 8 | ) 9 | ) 10 | BEGIN 11 | DROP PROCEDURE [dbo].[StoredProcedureName] 12 | END 13 | GO 14 | -------------------------------------------------------------------------------- /Utilities/Generate C# Class From Table.sql: -------------------------------------------------------------------------------- 1 | /* 2 | https://stackoverflow.com/questions/5873170/generate-class-from-database-table 3 | */ 4 | 5 | declare @TableName sysname = 'TableName' 6 | declare @Result varchar(max) = 'public class ' + @TableName + ' 7 | {' 8 | 9 | select @Result = @Result + ' 10 | public ' + ColumnType + NullableSign + ' ' + ColumnName + ' { get; set; } 11 | ' 12 | from 13 | ( 14 | select 15 | replace(col.name, ' ', '_') ColumnName, 16 | column_id ColumnId, 17 | case typ.name 18 | when 'bigint' then 'long' 19 | when 'binary' then 'byte[]' 20 | when 'bit' then 'bool' 21 | when 'char' then 'string' 22 | when 'date' then 'DateTime' 23 | when 'datetime' then 'DateTime' 24 | when 'datetime2' then 'DateTime' 25 | when 'datetimeoffset' then 'DateTimeOffset' 26 | when 'decimal' then 'decimal' 27 | when 'float' then 'double' 28 | when 'image' then 'byte[]' 29 | when 'int' then 'int' 30 | when 'money' then 'decimal' 31 | when 'nchar' then 'string' 32 | when 'ntext' then 'string' 33 | when 'numeric' then 'decimal' 34 | when 'nvarchar' then 'string' 35 | when 'real' then 'float' 36 | when 'smalldatetime' then 'DateTime' 37 | when 'smallint' then 'short' 38 | when 'smallmoney' then 'decimal' 39 | when 'text' then 'string' 40 | when 'time' then 'TimeSpan' 41 | when 'timestamp' then 'long' 42 | when 'tinyint' then 'byte' 43 | when 'uniqueidentifier' then 'Guid' 44 | when 'varbinary' then 'byte[]' 45 | when 'varchar' then 'string' 46 | else 'UNKNOWN_' + typ.name 47 | end ColumnType, 48 | case 49 | when col.is_nullable = 1 and typ.name in ('bigint', 'bit', 'date', 'datetime', 'datetime2', 'datetimeoffset', 'decimal', 'float', 'int', 'money', 'numeric', 'real', 'smalldatetime', 'smallint', 'smallmoney', 'time', 'tinyint', 'uniqueidentifier') 50 | then '?' 51 | else '' 52 | end NullableSign 53 | from sys.columns col 54 | join sys.types typ on 55 | col.system_type_id = typ.system_type_id AND col.user_type_id = typ.user_type_id 56 | where object_id = object_id(@TableName) 57 | ) t 58 | order by ColumnId 59 | 60 | set @Result = @Result + ' 61 | }' 62 | 63 | print @Result -------------------------------------------------------------------------------- /Utilities/Generate C# Classes From Tables.sql: -------------------------------------------------------------------------------- 1 | /* 2 | https://gist.github.com/joey-qc/6710702 3 | */ 4 | 5 | declare @tableName varchar(200) 6 | declare @columnName varchar(200) 7 | declare @nullable varchar(50) 8 | declare @datatype varchar(50) 9 | declare @maxlen int 10 | 11 | declare @sType varchar(50) 12 | declare @sProperty varchar(200) 13 | 14 | DECLARE table_cursor CURSOR FOR 15 | SELECT TABLE_NAME 16 | FROM [INFORMATION_SCHEMA].[TABLES] 17 | 18 | OPEN table_cursor 19 | 20 | FETCH NEXT FROM table_cursor 21 | INTO @tableName 22 | 23 | WHILE @@FETCH_STATUS = 0 24 | BEGIN 25 | 26 | PRINT 'public class ' + @tableName + ' {' 27 | 28 | DECLARE column_cursor CURSOR FOR 29 | SELECT COLUMN_NAME, IS_NULLABLE, DATA_TYPE, isnull(CHARACTER_MAXIMUM_LENGTH,'-1') 30 | from [INFORMATION_SCHEMA].[COLUMNS] 31 | WHERE [TABLE_NAME] = @tableName 32 | order by [ORDINAL_POSITION] 33 | 34 | OPEN column_cursor 35 | FETCH NEXT FROM column_cursor INTO @columnName, @nullable, @datatype, @maxlen 36 | 37 | WHILE @@FETCH_STATUS = 0 38 | BEGIN 39 | 40 | -- datatype 41 | select @sType = case @datatype 42 | when 'int' then 'Int32' 43 | when 'decimal' then 'Decimal' 44 | when 'money' then 'Decimal' 45 | when 'char' then 'String' 46 | when 'nchar' then 'String' 47 | when 'varchar' then 'String' 48 | when 'nvarchar' then 'String' 49 | when 'uniqueidentifier' then 'Guid' 50 | when 'datetime' then 'DateTime' 51 | when 'bit' then 'Boolean' 52 | else 'String' 53 | END 54 | 55 | If (@nullable = 'NO') 56 | PRINT '[Required]' 57 | if (@sType = 'String' and @maxLen <> '-1') 58 | Print '[MaxLength(' + convert(varchar(4),@maxLen) + ')]' 59 | SELECT @sProperty = 'public ' + @sType + ' ' + @columnName + ' { get; set;}' 60 | PRINT @sProperty 61 | 62 | print '' 63 | FETCH NEXT FROM column_cursor INTO @columnName, @nullable, @datatype, @maxlen 64 | END 65 | CLOSE column_cursor 66 | DEALLOCATE column_cursor 67 | 68 | print '}' 69 | print '' 70 | FETCH NEXT FROM table_cursor 71 | INTO @tableName 72 | END 73 | CLOSE table_cursor 74 | DEALLOCATE table_cursor -------------------------------------------------------------------------------- /Utilities/Generate C# List of Table Names Constant.sql: -------------------------------------------------------------------------------- 1 | 2 | declare @tables table(name varchar(100) primary key) 3 | insert into @tables 4 | select name 5 | from sys.tables 6 | order by name 7 | 8 | select 'public class TableNames' 9 | union all 10 | select '{' 11 | union all 12 | select 'public const string ' + name + ' = "' + name + '";' 13 | from @tables 14 | union all 15 | select '}' 16 | -------------------------------------------------------------------------------- /Utilities/Generate Sequential Ids.sql: -------------------------------------------------------------------------------- 1 | create table #temp(Id uniqueidentifier default NEWSEQUENTIALID(), Value int) 2 | insert into #temp(Value) values 3 | (0),(0),(0),(0),(0),(0),(0),(0),(0),(0) 4 | select Id from #temp order by Id 5 | drop table #temp; 6 | -------------------------------------------------------------------------------- /Utilities/Insert If Not Exists Avoid Duplicates.sql: -------------------------------------------------------------------------------- 1 | -- https://devblogs.microsoft.com/azure-sql/the-insert-if-not-exists-challenge-a-solution/ 2 | 3 | create table [dbo].[tags] ( 4 | [post_id] int not null, 5 | [tag] nvarchar(50) not null, 6 | constraint pk__tags primary key clustered ([post_id], [tag]) 7 | ) 8 | 9 | -- fist option 10 | insert into [dbo].[tags] ([post_id], [tag]) 11 | select * from ( 12 | values (10, 'tag123') -- sample value 13 | ) as s([post_id], [tag]) 14 | where not exists ( 15 | select * from [dbo].[tags] t with (updlock) 16 | where s.[post_id] = t.[post_id] and s.[tag] = t.[tag] 17 | ) 18 | 19 | -- second option 20 | merge into 21 | [dbo].[tags] with (holdlock) t 22 | using 23 | (values (10, 'tag1233')) s([post_id], [tag]) 24 | on 25 | t.[post_id] = s.[post_id] and t.[tag] = s.[tag] 26 | when not matched then 27 | insert values (s.[post_id], s.[tag]); 28 | -------------------------------------------------------------------------------- /Utilities/Move Data to Archived Table.sql: -------------------------------------------------------------------------------- 1 | 2 | DECLARE @TableName NVARCHAR(MAX) = 'OutboxEvents'; 3 | DECLARE @ArchivedTableName NVARCHAR(MAX) = 'PublishedOutboxEvents'; 4 | DECLARE @TempTableName NVARCHAR(MAX) = '#TEMP'; 5 | 6 | DECLARE @Columns NVARCHAR(MAX); 7 | SELECT 8 | @Columns = CASE 9 | WHEN @Columns IS NULL 10 | THEN '[' + name + ']' 11 | ELSE @Columns + ',' + '[' + name + ']' 12 | END 13 | FROM sys.columns where object_id = OBJECT_ID(@TableName) 14 | 15 | DECLARE @SQL NVARCHAR(MAX); 16 | SELECT @SQL = ' 17 | SELECT Id INTO ' + @TempTableName + ' 18 | FROM [' + @TableName + '] 19 | -- INSERT WHERE CONDITION HERE 20 | 21 | INSERT INTO [' + @ArchivedTableName + ']( 22 | ' + @Columns + ' 23 | ) 24 | SELECT 25 | '+ @Columns + ' 26 | FROM [' + @TableName + '] 27 | WHERE Id IN (SELECT Id FROM ' + @TempTableName + ') 28 | 29 | DELETE FROM [' + @TableName + '] 30 | WHERE Id IN (SELECT Id FROM ' + @TempTableName + ') 31 | 32 | DROP TABLE ' + @TempTableName + ' 33 | ' 34 | 35 | SELECT @SQL 36 | -------------------------------------------------------------------------------- /Utilities/Search Potential Unused Tables.sql: -------------------------------------------------------------------------------- 1 | SELECT t.NAME 2 | FROM sys.tables t 3 | WHERE t.type = 'U' 4 | AND t.object_id NOT IN ( 5 | SELECT object_id 6 | FROM sys.dm_db_index_usage_stats 7 | WHERE database_id = Db_id(Db_name()) 8 | ) 9 | ORDER BY NAME ASC 10 | 11 | 12 | SELECT * 13 | FROM sys.dm_db_index_usage_stats 14 | WHERE database_id = Db_id(Db_name()) 15 | AND object_id = Object_Id('TableName') 16 | 17 | SELECT * 18 | FROM sys.indexes 19 | WHERE object_id = 754101727 20 | -------------------------------------------------------------------------------- /Utilities/Search Text.sql: -------------------------------------------------------------------------------- 1 | SELECT o.name, o.xtype, m.definition, m.uses_ansi_nulls, m.uses_quoted_identifier 2 | FROM sys.sql_modules m 3 | INNER JOIN sysobjects o ON m.object_id = o.id 4 | WHERE m.definition LIKE '%xxx%' -------------------------------------------------------------------------------- /Utilities/Using tables as Queues.sql: -------------------------------------------------------------------------------- 1 | ---------- 2 | -- http://rusanu.com/2010/03/26/using-tables-as-queues/ 3 | 4 | -- Heap Queues: 5 | create table HeapQueue ( 6 | Payload varbinary(max)); 7 | go 8 | 9 | create procedure usp_enqueueHeap 10 | @payload varbinary(max) 11 | as 12 | set nocount on; 13 | insert into HeapQueue (Payload) values (@Payload); 14 | go 15 | 16 | create procedure usp_dequeueHeap 17 | as 18 | set nocount on; 19 | delete top(1) from HeapQueue with (rowlock, readpast) 20 | output deleted.payload; 21 | go 22 | 23 | -- FIFO Queues: 24 | create table FifoQueue ( 25 | Id bigint not null identity(1,1), 26 | Payload varbinary(max)); 27 | go 28 | 29 | create clustered index cdxFifoQueue on FifoQueue (Id); 30 | go 31 | 32 | create procedure usp_enqueueFifo 33 | @payload varbinary(max) 34 | as 35 | set nocount on; 36 | insert into FifoQueue (Payload) values (@Payload); 37 | go 38 | 39 | create procedure usp_dequeueFifo 40 | as 41 | set nocount on; 42 | with cte as ( 43 | select top(1) Payload 44 | from FifoQueue with (rowlock, readpast) 45 | order by Id) 46 | delete from cte 47 | output deleted.Payload; 48 | go 49 | 50 | -- Subquery deque plan: 51 | delete top(1) from FifoQueue 52 | output deleted.Payload 53 | where Id = ( 54 | select top(1) Id 55 | from FifoQueue with (rowlock, updlock, readpast) 56 | order by Id) 57 | 58 | -- LIFO Stacks: 59 | with cte as ( 60 | select top(1) Payload 61 | from FifoQueue with (rowlock, readpast) 62 | order by Id DESC) 63 | delete from cte 64 | output deleted.Payload; 65 | 66 | -- Pending Queues: 67 | create table PendingQueue ( 68 | DueTime datetime not null, 69 | Payload varbinary(max)); 70 | 71 | create clustered index cdxPendingQueue on PendingQueue (DueTime); 72 | go 73 | 74 | create procedure usp_enqueuePending 75 | @dueTime datetime, 76 | @payload varbinary(max) 77 | as 78 | set nocount on; 79 | insert into PendingQueue (DueTime, Payload) 80 | values (@dueTime, @payload); 81 | go 82 | 83 | create procedure usp_dequeuePending 84 | as 85 | set nocount on; 86 | declare @now datetime; 87 | set @now = getutcdate(); 88 | with cte as ( 89 | select top(1) 90 | Payload 91 | from PendingQueue with (rowlock, readpast) 92 | where DueTime < @now 93 | order by DueTime) 94 | delete from cte 95 | output deleted.Payload; 96 | go 97 | 98 | ---------- 99 | -------------------------------------------------------------------------------- /Wait Statistics/Blocking/Module 4 - Long Term Blocking.sql: -------------------------------------------------------------------------------- 1 | -- Active blocking issues? 2 | SELECT [session_id], 3 | [wait_duration_ms], 4 | [wait_type], 5 | [blocking_session_id] 6 | FROM sys.[dm_os_waiting_tasks] 7 | WHERE [wait_type] LIKE N'LCK%'; 8 | GO 9 | 10 | -- Isolation level of session? 11 | SELECT [session_id], 12 | [transaction_isolation_level] 13 | FROM sys.[dm_exec_sessions] 14 | WHERE [session_id] = 55; 15 | GO 16 | 17 | -- Blocked process threshold 18 | EXEC sp_configure 'blocked process threshold (s)', 10; 19 | RECONFIGURE 20 | GO 21 | 22 | -- Blocked process report 23 | 24 | 25 | -------------------------------------------------------------------------------- /Wait Statistics/Blocking/README.md: -------------------------------------------------------------------------------- 1 | ## LCK_M_XX Wait 2 | 3 | ### What does it mean: 4 | - A thread is waiting for a lock that cannot be granted because another thread is holding an incompatible lock 5 | 6 | ### Avoid knee-jerk response: 7 | - Do not assume that locking is the root cause 8 | 9 | ### Further analysis: 10 | - Follow the blocking chain using sys.dm_os_waiting_tasks to see what the lead blocking thread is waiting for 11 | - Use the blocked process report to capture information on queries waiting too long for locks 12 | 13 | ### Solutions 14 | - Lock escalation from a large update or table scan 15 | + Possibly configure partition-level lock escalation, if applicable 16 | + Consider a different indexing strategy to use nonclustered index seeks 17 | + Consider breaking large updates into smaller transactions 18 | + Consider using snapshot isolation, a different isolation level, or locking hints 19 | + All the general strategies for alleviating blocking problems 20 | - Unnecessary locks for the data being accessed 21 | + Consider using snapshot isolation, a different isolation level, or locking hints 22 | - Something preventing a transaction from releasing its locks quickly 23 | + Determine what the bottleneck is and solve it appropriately 24 | -------------------------------------------------------------------------------- /Wait Statistics/CPU/Module 7 - Compilations.PerfmonCfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Wait Statistics/CPU/Module 7 - Compilations.PerfmonCfg -------------------------------------------------------------------------------- /Wait Statistics/CPU/Module 7 - Observer Overhead.PerfmonCfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Wait Statistics/CPU/Module 7 - Observer Overhead.PerfmonCfg -------------------------------------------------------------------------------- /Wait Statistics/CPU/Module 7 - Uninvited Parallelism Discovery.sql: -------------------------------------------------------------------------------- 1 | -- Identifying potential parallel plans 2 | SELECT [qs].[total_worker_time], 3 | [qs].[total_elapsed_time], 4 | SUBSTRING([qt].[text], [qs].[statement_start_offset] / 2, 5 | (CASE WHEN [qs].[statement_end_offset] = -1 6 | THEN LEN(CONVERT(NVARCHAR(MAX), [qt].[text])) * 2 7 | ELSE [qs].[statement_end_offset] 8 | END - [qs].[statement_start_offset]) / 2) AS query_text, 9 | [qs].[execution_count], 10 | [qs].[sql_handle], 11 | [qs].[plan_handle] 12 | FROM [sys].[dm_exec_query_stats] qs 13 | CROSS APPLY [sys].[dm_exec_sql_text]([qs].[sql_handle]) AS qt 14 | WHERE [qs].[total_worker_time] > [qs].[total_elapsed_time] 15 | ORDER BY [qs].[total_worker_time] DESC; 16 | 17 | -- Another option for identification 18 | SELECT [r].[session_id], 19 | [r].[plan_handle], 20 | MAX(ISNULL([t].[exec_context_id], 0)) AS workers 21 | FROM [sys].[dm_exec_requests] r 22 | INNER JOIN [sys].[dm_os_tasks] t 23 | ON [r].[session_id] = [t].[session_id] 24 | INNER JOIN [sys].[dm_exec_sessions] s 25 | ON [r].[session_id] = [s].[session_id] 26 | WHERE [s].[is_user_process] = 0x1 27 | GROUP BY [r].[session_id], 28 | [r].[plan_handle] 29 | HAVING MAX(ISNULL([t].[exec_context_id], 0)) > 0; 30 | 31 | -- We can check the plan now 32 | SELECT [query_plan] 33 | FROM sys.dm_exec_query_plan 34 | /** PLUG IN NEW plan handle **/(0x0600050036AEA22B007B79EC0100000001000000000000000000000000000000000000000000000000000000) -------------------------------------------------------------------------------- /Wait Statistics/CPU/README.md: -------------------------------------------------------------------------------- 1 | ## CXPACKET Wait 2 | ### What does it mean: 3 | - Parallel operations are taking place 4 | - Accumulating very fast implies skewed work distribution amongst threads or one of the workers is being blocked by something 5 | 6 | ### Avoid knee-jerk response: 7 | - Do not set server-wide MAXDOP to 1, disabling parallelism 8 | 9 | ### Further analysis: 10 | - Correlation with PAGEIOLATCH_SH waits? Implies large scans 11 | + Also may see with ACCESS_METHODS_DATASET_PARENT latch or ACCESS_METHODS_SCAN_RANGE_GENERATOR latch 12 | - Examine query plans of requests that are accruing CXPACKET waits to see if the query plans make sense for the query being performed 13 | - What is the wait type of the parallel thread that is taking too long? (i.e. the thread that does not have CXPACKET as its wait type) 14 | 15 | ### Possible root-causes: 16 | - Just parallelism occurring 17 | - Table scans being performed because of missing nonclustered indexes or incorrect query plan 18 | - Out-of-data statistics causing skewed work distribution 19 | ### If there is actually a problem: 20 | - Make sure statistics are up-to-date and appropriate indexes exist 21 | - Consider MAXDOP for the query 22 | - Consider MAXDOP = physical cores per NUMA node 23 | - Consider MAXDOP for the instance, but beware of mixed-mode workloads 24 | - Consider using Resource Governor for MAX_DOP 25 | - Consider setting ‘cost threshold for parallelism’ higher than the query cost shown in the execution plan 26 | -------------------------------------------------------------------------------- /Wait Statistics/ExaminingLatches.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM sys.dm_os_latch_stats; 2 | GO 3 | 4 | WITH [Latches] AS 5 | (SELECT 6 | [latch_class], 7 | [wait_time_ms] / 1000.0 AS [WaitS], 8 | [waiting_requests_count] AS [WaitCount], 9 | 100.0 * [wait_time_ms] / SUM ([wait_time_ms]) OVER() 10 | AS [Percentage], 11 | ROW_NUMBER() OVER(ORDER BY [wait_time_ms] DESC) 12 | AS [RowNum] 13 | FROM sys.dm_os_latch_stats 14 | WHERE [latch_class] NOT IN ( 15 | 'BUFFER') 16 | ) 17 | SELECT 18 | [W1].[latch_class] AS [LatchClass], 19 | CAST ([W1].[WaitS] AS DECIMAL(14, 2)) AS [Wait_S], 20 | [W1].[WaitCount] AS [WaitCount], 21 | CAST ([W1].[Percentage] AS DECIMAL(14, 2)) AS [Percentage], 22 | CAST (([W1].[WaitS] / [W1].[WaitCount]) AS DECIMAL (14, 4)) 23 | AS [AvgWait_S] 24 | FROM [Latches] AS [W1] 25 | INNER JOIN [Latches] AS [W2] 26 | ON [W2].[RowNum] <= [W1].[RowNum] 27 | GROUP BY [W1].[RowNum], [W1].[latch_class], 28 | [W1].[WaitS], [W1].[WaitCount], [W1].[Percentage] 29 | HAVING 30 | SUM ([W2].[Percentage]) - [W1].[Percentage] < 95; -- percentage 31 | GO 32 | -------------------------------------------------------------------------------- /Wait Statistics/ExaminingSpinlocks.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM sys.dm_os_spinlock_stats 2 | ORDER BY [spins] DESC; 3 | GO 4 | 5 | IF EXISTS (SELECT * FROM [tempdb].[sys].[objects] 6 | WHERE [name] = N'##TempSpinlockStats1') 7 | DROP TABLE [##TempSpinlockStats1]; 8 | 9 | IF EXISTS (SELECT * FROM [tempdb].[sys].[objects] 10 | WHERE [name] = N'##TempSpinlockStats2') 11 | DROP TABLE [##TempSpinlockStats2]; 12 | 13 | -- Baseline 14 | SELECT * INTO [##TempSpinlockStats1] 15 | FROM sys.dm_os_spinlock_stats 16 | WHERE [collisions] > 0 17 | ORDER BY [name]; 18 | GO 19 | 20 | -- Now run a workload 21 | DBCC CHECKDB (N'master') WITH NO_INFOMSGS; 22 | GO 23 | 24 | -- Capture updated stats 25 | SELECT * INTO [##TempSpinlockStats2] 26 | FROM sys.dm_os_spinlock_stats 27 | WHERE [collisions] > 0 28 | ORDER BY [name]; 29 | GO 30 | 31 | -- Diff them 32 | SELECT 33 | '***' AS [New], 34 | [ts2].[name] AS [Spinlock], 35 | [ts2].[collisions] AS [DiffCollisions], 36 | [ts2].[spins] AS [DiffSpins], 37 | [ts2].[spins_per_collision] AS [SpinsPerCollision], 38 | [ts2].[sleep_time] AS [DiffSleepTime], 39 | [ts2].[backoffs] AS [DiffBackoffs] 40 | FROM [##TempSpinlockStats2] [ts2] 41 | LEFT OUTER JOIN [##TempSpinlockStats1] [ts1] 42 | ON [ts2].[name] = [ts1].[name] 43 | WHERE [ts1].[name] IS NULL 44 | UNION 45 | SELECT 46 | '' AS [New], 47 | [ts2].[name] AS [Spinlock], 48 | [ts2].[collisions] - [ts1].[collisions] AS [DiffCollisions], 49 | [ts2].[spins] - [ts1].[spins] AS [DiffSpins], 50 | CASE ([ts2].[spins] - [ts1].[spins]) WHEN 0 THEN 0 51 | ELSE ([ts2].[spins] - [ts1].[spins]) / 52 | ([ts2].[collisions] - [ts1].[collisions]) END 53 | AS [SpinsPerCollision], 54 | [ts2].[sleep_time] - [ts1].[sleep_time] AS [DiffSleepTime], 55 | [ts2].[backoffs] - [ts1].[backoffs] AS [DiffBackoffs] 56 | FROM [##TempSpinlockStats2] [ts2] 57 | LEFT OUTER JOIN [##TempSpinlockStats1] [ts1] 58 | ON [ts2].[name] = [ts1].[name] 59 | WHERE [ts1].[name] IS NOT NULL 60 | AND [ts2].[collisions] - [ts1].[collisions] > 0 61 | ORDER BY [New] DESC, [Spinlock] ASC; 62 | GO 63 | -------------------------------------------------------------------------------- /Wait Statistics/ExaminingWaitingTasks.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM sys.dm_os_waiting_tasks; 2 | GO 3 | 4 | SELECT 5 | [owt].[session_id], 6 | [owt].[exec_context_id], 7 | [owt].[wait_duration_ms], 8 | [owt].[wait_type], 9 | [owt].[blocking_session_id], 10 | [owt].[resource_description], 11 | [es].[program_name], 12 | [est].[text], 13 | [est].[dbid], 14 | [eqp].[query_plan], 15 | [es].[cpu_time], 16 | [es].[memory_usage] 17 | FROM sys.dm_os_waiting_tasks [owt] 18 | INNER JOIN sys.dm_exec_sessions [es] ON 19 | [owt].[session_id] = [es].[session_id] 20 | INNER JOIN sys.dm_exec_requests [er] ON 21 | [es].[session_id] = [er].[session_id] 22 | OUTER APPLY sys.dm_exec_sql_text ([er].[sql_handle]) [est] 23 | OUTER APPLY sys.dm_exec_query_plan ([er].[plan_handle]) [eqp] 24 | WHERE [es].[is_user_process] = 1 25 | ORDER BY [owt].[session_id], [owt].[exec_context_id] 26 | GO -------------------------------------------------------------------------------- /Wait Statistics/IO/Module 3 - Inadequate IO Paths.sql: -------------------------------------------------------------------------------- 1 | -- Wait stats related to I/O? 2 | -- Be sure to compare against total wait time accumulation 3 | -- Be sure to see Paul Randal's 4 | -- "SQL Server- Performance Troubleshooting Using Wait Statistics" 5 | SELECT [wait_type], 6 | [waiting_tasks_count], 7 | [wait_time_ms], 8 | [max_wait_time_ms], 9 | [signal_wait_time_ms] 10 | FROM sys.[dm_os_wait_stats] 11 | ORDER BY [wait_time_ms] DESC; 12 | GO 13 | 14 | 15 | -- Active I/O issues? 16 | SELECT [session_id], 17 | [wait_duration_ms], 18 | [wait_type], 19 | [resource_description] 20 | FROM sys.[dm_os_waiting_tasks] 21 | WHERE [wait_type] LIKE N'PAGEIOLATCH%' OR 22 | [wait_type] IN (N'IO_COMPLETION', N'WRITELOG', N'ASYNC_IO_COMPLETION'); 23 | GO 24 | 25 | -- Triage based on sys.dm_io_virtual_file_stats 26 | SELECT [database_id], 27 | DB_NAME([database_id]) AS [database_nm], 28 | [file_id], 29 | [num_of_reads], 30 | [num_of_bytes_read], 31 | [io_stall_read_ms], 32 | [num_of_writes], 33 | [num_of_bytes_written], 34 | [io_stall_write_ms], 35 | [io_stall], 36 | [size_on_disk_bytes] 37 | FROM sys.[dm_io_virtual_file_stats](NULL, NULL) 38 | ORDER BY [io_stall] DESC; 39 | GO 40 | 41 | -- Top I/O queries 42 | -- Memory pressure? These stats may be evicted 43 | SELECT q.[query_hash], 44 | SUBSTRING(t.text, (q.[statement_start_offset] / 2) + 1, 45 | ((CASE q.[statement_end_offset] 46 | WHEN -1 THEN DATALENGTH(t.[text]) 47 | ELSE q.[statement_end_offset] 48 | END - q.[statement_start_offset]) / 2) + 1), 49 | SUM(q.[total_physical_reads]) AS [total_physical_reads] 50 | FROM sys.[dm_exec_query_stats] AS q 51 | CROSS APPLY sys.[dm_exec_sql_text](q.sql_handle) AS t 52 | GROUP BY q.[query_hash], 53 | SUBSTRING(t.text, (q.[statement_start_offset] / 2) + 1, 54 | ((CASE q.[statement_end_offset] 55 | WHEN -1 THEN DATALENGTH(t.[text]) 56 | ELSE q.[statement_end_offset] 57 | END - q.[statement_start_offset]) / 2) + 1) 58 | ORDER BY SUM(q.[total_physical_reads]) DESC; 59 | GO 60 | 61 | -- What is the query execution plan of the top I/O query? 62 | SELECT p.[query_plan] 63 | FROM sys.[dm_exec_query_stats] AS q 64 | CROSS APPLY sys.[dm_exec_query_plan](q.[plan_handle]) AS p 65 | WHERE q.[query_hash] = 0xEB3F21FCCE406BBE 66 | GO 67 | 68 | 69 | -------------------------------------------------------------------------------- /Wait Statistics/IO/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## PAGEIOLATCH_XX Wait 3 | ### What does it mean: 4 | - Waiting for a data file page to be read from disk into memory 5 | - Common modes to see are SH and EX 6 | + SH mode means the page will be read 7 | + EX mode means the page will be changed 8 | ### Avoid knee-jerk response: 9 | - Do not assume the I/O subsystem or I/O path is the problem 10 | ### Further analysis: 11 | - Determine which tables/indexes are being read 12 | - Analyze I/O subsystem latencies with sys.dm_io_virtual_file_stats and Avg Disk secs/Read performance counters 13 | - Correlate with CXPACKET waits, suggesting parallel scans 14 | - Examine query plans for parallel scans 15 | - Examine query plans for implicit conversions 16 | - Investigate buffer pool memory pressure and Page Life Expectancy 17 | ### Solutions 18 | - Create appropriate nonclustered indexes to reduce scans 19 | - Update statistics to allow efficient query plans 20 | - Move the affected data files to faster I/O subsystem 21 | - If data volume has simply increased, consider increasing memory 22 | -------------------------------------------------------------------------------- /Wait Statistics/Memory/Module 5 - Memory Related Counters.PerfmonCfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Wait Statistics/Memory/Module 5 - Memory Related Counters.PerfmonCfg -------------------------------------------------------------------------------- /Wait Statistics/Memory/Module 5 - Query Execution Memory Issues.sql: -------------------------------------------------------------------------------- 1 | -- Waiting tasks? 2 | SELECT [session_id], 3 | [wait_duration_ms], 4 | [wait_type], 5 | [resource_description] 6 | FROM sys.[dm_os_waiting_tasks]; 7 | GO 8 | 9 | -- Memory Grants information 10 | SELECT [session_id], 11 | [request_id], 12 | [scheduler_id], 13 | [dop], 14 | [request_time], 15 | [grant_time], 16 | [requested_memory_kb], 17 | [granted_memory_kb], 18 | [required_memory_kb], 19 | [used_memory_kb], 20 | [max_used_memory_kb], 21 | [query_cost], 22 | [timeout_sec], 23 | [resource_semaphore_id], 24 | [queue_id], 25 | [wait_order], 26 | [is_next_candidate], 27 | [wait_time_ms], 28 | [plan_handle], 29 | [sql_handle], 30 | [group_id], 31 | [pool_id], 32 | [is_small], 33 | [ideal_memory_kb] 34 | FROM sys.[dm_exec_query_memory_grants]; 35 | GO 36 | 37 | -- What does the plan look like? 38 | SELECT query_plan 39 | FROM sys.dm_exec_query_plan(0x0600050029E9AE037008B9FF0100000001000000000000000000000000000000000000000000000000000000); 40 | GO 41 | 42 | -- The query? 43 | SELECT text 44 | FROM sys.dm_exec_sql_text(0x0200000029E9AE031C52F60A5B44CFF02F982C147520DD180000000000000000000000000000000000000000); 45 | GO 46 | 47 | 48 | -- Semaphores 49 | SELECT [resource_semaphore_id], 50 | [target_memory_kb], 51 | [max_target_memory_kb], 52 | [total_memory_kb], 53 | [available_memory_kb], 54 | [granted_memory_kb], 55 | [used_memory_kb], 56 | [grantee_count], 57 | [waiter_count], 58 | [timeout_error_count], 59 | [forced_grant_count], 60 | [pool_id] 61 | FROM sys.dm_exec_query_resource_semaphores; 62 | GO -------------------------------------------------------------------------------- /Wait Statistics/Memory/Module 5 - Query Execution Memory.PerfmonCfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Wait Statistics/Memory/Module 5 - Query Execution Memory.PerfmonCfg -------------------------------------------------------------------------------- /Wait Statistics/Memory/README.md: -------------------------------------------------------------------------------- 1 | ## PAGELATCH_XX Wait 2 | ### What does it mean: 3 | - Waiting for access to an in-memory data file page 4 | - Common modes to see are SH and EX 5 | + SH mode means the page will be read 6 | + EX mode means the page will be changed 7 | ### Avoid knee-jerk response: 8 | - Do not confuse these with PAGEIOLATCH_XX waits 9 | - Does not mean add more memory or I/O capacity 10 | ### Further analysis: 11 | - Determine the page(s) that the thread is waiting for access to 12 | - Analyze the queries encountering this wait 13 | - Analyze the table and index structures involved 14 | 15 | ## PAGELATCH_XX Wait Solutions 16 | ### Classic tempdb contention 17 | - Add more tempdb data files 18 | - Enable trace flag 1118 19 | - Reduce temp table usage 20 | ### Excessive page splits occurring in indexes 21 | - Change to a non-random index key 22 | - Avoid updating index records to be longer 23 | - Provision an index FILLFACTOR to alleviate page splits 24 | ### Insertion point hotspot in a clustered index with an ever-increasing key 25 | - Spread the insertion points in the index using a random or composite key, plus provision a FILLFACTOR to prevent page splits 26 | - Shard into multiple tables/databases/servers 27 | -------------------------------------------------------------------------------- /Wait Statistics/Network/README.md: -------------------------------------------------------------------------------- 1 | ## ASYNC_NETWORK_IO Wait 2 | 3 | ### What does it mean: 4 | - SQL Server is waiting for a client to acknowledge receipt of sent data 5 | ### Avoid knee-jerk response: 6 | - Do not assume that the problem is network latency 7 | - It is a network delay as far as SQL Server is concerned though 8 | ### Further analysis: 9 | - Analyze client application code 10 | - Analyze network latencies 11 | ### Possible root-causes and solutions: 12 | - Nearly always a poorly-coded application that is processing results one record at a time (RBAR = Row-By-Agonizing-Row) 13 | + Very easy to demonstrate using a large query and SQL Server Management Studio running on the same machine as SQL Server 14 | - Otherwise look for network hardware issues, incorrect duplex settings, or TCP chimney offload problems 15 | -------------------------------------------------------------------------------- /Wait Statistics/Transaction Log/README.md: -------------------------------------------------------------------------------- 1 | ## WRITELOG Wait 2 | 3 | ### What does it mean: 4 | - Waiting for a transaction log block buffer to flush to disk 5 | 6 | ### Avoid knee-jerk response: 7 | - Do not assume that the transaction log file I/O system has a problem (although this is often the case) 8 | - Do not create additional transaction log files 9 | 10 | ### Further analysis: 11 | - Correlate WRITELOG wait time with I/O subsystem latency using sys.dm_io_virtual_file_stats 12 | + Look for LOGBUFFER waits, showing internal contention for log buffers 13 | - Look at average disk write queue length for log drive 14 | + If constantly 31/32 then the internal limit has been reached for outstanding transaction log writes for a single database 15 | - Look at average size of transactions 16 | - Investigate whether frequent page splits are occurring 17 | 18 | ### Solutions 19 | - Move the log to a faster I/O subsystem 20 | - Increase the size of transactions to prevent many minimum-size log block flushes to disk 21 | - Remove unused nonclustered indexes to reduce logging overhead from maintaining unused indexes during DML operations 22 | - Change index keys or introduce FILLFACTORs to reduce page splits 23 | - Potentially split the workload over multiple databases or servers 24 | -------------------------------------------------------------------------------- /Wait Statistics/imgs/scheduler_components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Wait Statistics/imgs/scheduler_components.png -------------------------------------------------------------------------------- /Wait Statistics/imgs/schedulers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Wait Statistics/imgs/schedulers.png -------------------------------------------------------------------------------- /Wait Statistics/imgs/wait_times_definition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phongnguyend/sql-server-kit/d10cc70b0e202f99edb3bb25368695432e7832ab/Wait Statistics/imgs/wait_times_definition.png -------------------------------------------------------------------------------- /Wait Statistics/tempdb/Module 6 - Row Versioning Overhead.sql: -------------------------------------------------------------------------------- 1 | -- How are the databases configured? 2 | SELECT [databases].[name], 3 | [databases].[database_id], 4 | [databases].[snapshot_isolation_state], 5 | [databases].[snapshot_isolation_state_desc], 6 | [databases].[is_read_committed_snapshot_on] 7 | FROM [sys].[databases]; 8 | GO 9 | 10 | -- What does the tempdb allocation look like? 11 | USE tempdb; 12 | GO 13 | 14 | SELECT SUM([dm_db_file_space_usage].[user_object_reserved_page_count]) * 8 AS [user_object_reserved_kb], 15 | SUM([dm_db_file_space_usage].[internal_object_reserved_page_count]) * 8 AS [internal_object_reserved_kb], 16 | SUM([dm_db_file_space_usage].[version_store_reserved_page_count]) * 8 AS [version_store_kb] 17 | FROM [sys].[dm_db_file_space_usage]; 18 | GO 19 | 20 | -- Long transactions? 21 | SELECT [dm_tran_active_snapshot_database_transactions].[transaction_id], 22 | [dm_tran_active_snapshot_database_transactions].[transaction_sequence_num], 23 | [dm_tran_active_snapshot_database_transactions].[commit_sequence_num], 24 | [dm_tran_active_snapshot_database_transactions].[session_id], 25 | [dm_tran_active_snapshot_database_transactions].[is_snapshot], 26 | [dm_tran_active_snapshot_database_transactions].[first_snapshot_sequence_num], 27 | [dm_tran_active_snapshot_database_transactions].[max_version_chain_traversed], 28 | [dm_tran_active_snapshot_database_transactions].[average_version_chain_traversed], 29 | [dm_tran_active_snapshot_database_transactions].[elapsed_time_seconds] 30 | FROM [sys].[dm_tran_active_snapshot_database_transactions] 31 | ORDER BY [dm_tran_active_snapshot_database_transactions].[elapsed_time_seconds] DESC; 32 | GO 33 | 34 | -- What query? What plan? 35 | SELECT [t].[text], 36 | [p].[query_plan] 37 | FROM [sys].[dm_exec_sessions] AS s 38 | LEFT OUTER JOIN [sys].[dm_exec_requests] AS r 39 | ON [s].[session_id] = [r].[session_id] 40 | OUTER APPLY [sys].[dm_exec_sql_text]([r].[sql_handle]) AS t 41 | OUTER APPLY [sys].[dm_exec_query_plan]([r].[plan_handle]) AS p 42 | WHERE [s].[session_id] = 75; 43 | GO 44 | 45 | -- Can you optimize the workloads? 46 | -- Is the snapshot isolation providing concurrency benefits? 47 | -- If so, what about the I/O path for tempdb? 48 | -------------------------------------------------------------------------------- /Wait Statistics/tempdb/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Wait Statistics/tempdb/SQLskills_MonitorTempdbContention_1_CreateXEvent.sql: -------------------------------------------------------------------------------- 1 | IF EXISTS ( 2 | SELECT * 3 | FROM sys.server_event_sessions 4 | WHERE name = 'SQLskills_MonitorTempdbContention' 5 | ) 6 | DROP EVENT SESSION [SQLskills_MonitorTempdbContention] ON SERVER; 7 | GO 8 | 9 | CREATE EVENT SESSION SQLskills_MonitorTempdbContention 10 | ON SERVER 11 | ADD EVENT sqlserver.latch_suspend_end ( 12 | WHERE ( 13 | database_id = 2 14 | AND duration > 0 15 | AND ( 16 | mode = 2 17 | OR mode = 3 18 | ) 19 | AND ( 20 | page_id < 4 21 | OR -- Initial allocation bitmap pages 22 | package0.divides_by_uint64(page_id, 8088) 23 | OR --PFS pages 24 | package0.divides_by_uint64(page_id, 511232) 25 | OR --GAM Pages 26 | page_id = 511233 27 | OR --2nd SGAM page 4GB-8GB 28 | page_id = 1022465 29 | OR --3rd SGAM page 8GB-12GB 30 | page_id = 1533697 31 | OR --4th SGAM page 12GB-16GB 32 | page_id = 2044929 33 | OR --5th SGAM page 16GB-20GB 34 | page_id = 2556161 35 | OR --6th SGAM page 20GB-24GB 36 | page_id = 3067393 37 | OR --7th SGAM page 24GB-28GB 38 | page_id = 3578625 39 | ) --8th SGAM page 28GB-32GB 40 | ) 41 | ) 42 | ADD TARGET package0.histogram ( 43 | SET filtering_event_name = N'sqlserver.latch_suspend_end' 44 | ,source = N'page_id' 45 | ,source_type = 0 46 | ), 47 | ADD TARGET package0.event_file ( 48 | SET filename = 'SQLskills_MonitorTempdbContention.xel' 49 | ,max_file_size = 100 50 | ,max_rollover_files = 10 51 | ,increment = 5 52 | ) 53 | WITH (STARTUP_STATE = ON); 54 | -------------------------------------------------------------------------------- /Wait Statistics/tempdb/SQLskills_MonitorTempdbContention_2_CheckResults.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | n.value('(value)[1]', 'bigint') AS page_id, 3 | n.value('(@count)[1]', 'bigint') AS wait_count 4 | FROM 5 | ( SELECT CAST(target_data AS XML) target_data 6 | FROM sys.dm_xe_sessions AS s 7 | INNER JOIN sys.dm_xe_session_targets AS t 8 | ON s.address = t.event_session_address 9 | WHERE s.name = N'SQLskills_MonitorTempdbContention' 10 | AND t.target_name = N'histogram' ) AS tab 11 | CROSS APPLY target_data.nodes('HistogramTarget/Slot') AS q(n); 12 | 13 | 14 | 15 | 16 | SELECT 17 | SUM(n.value('(data[@name="duration"]/value)[1]', 'int'))/1000000.0 AS duration_seconds 18 | FROM 19 | (SELECT 20 | CAST(event_data AS XML) AS event_data 21 | FROM sys.fn_xe_file_target_read_file( 22 | 'SQLskills_MonitorTempdbContention*xel', 23 | 'See its not used', -- No metadata file required in 2012 24 | NULL, 25 | NULL) 26 | ) AS tab 27 | CROSS APPLY event_data.nodes('event') AS q(n) 28 | 29 | 30 | 31 | SELECT 32 | session_id, 33 | wait_type, 34 | wait_duration_ms, 35 | blocking_session_id, 36 | resource_description, 37 | ResourceType = CASE 38 | WHEN PageID = 1 OR PageID % 8088 = 0 THEN 'Is PFS Page' 39 | WHEN PageID = 2 OR PageID % 511232 = 0 THEN 'Is GAM Page' 40 | WHEN PageID = 3 OR (PageID - 1) % 511232 = 0 THEN 'Is SGAM Page' 41 | ELSE 'Is Not PFS, GAM, or SGAM page' 42 | END 43 | FROM ( SELECT 44 | session_id, 45 | wait_type, 46 | wait_duration_ms, 47 | blocking_session_id, 48 | resource_description, 49 | CAST(RIGHT(resource_description, LEN(resource_description) 50 | - CHARINDEX(':', resource_description, 3)) AS INT) AS PageID 51 | FROM sys.dm_os_waiting_tasks 52 | WHERE wait_type LIKE 'PAGE%LATCH_%' 53 | AND resource_description LIKE '2:%' 54 | ) AS tab; --------------------------------------------------------------------------------