From 2e30a30f2135b73eaf39dea434ccddd945155d70 Mon Sep 17 00:00:00 2001 From: nate-hughes Date: Mon, 18 May 2020 21:48:57 -0400 Subject: [PATCH] Merge Repositories --- ...ig-enable-DAC.sql => DAC-config-enable.sql | 58 +- DAC-connection-info.sql | 28 + Ola-build-backup-script.sql | 18 + Ola-query-CommandLog.sql | 30 + alwayson-ApplicationIntent=ReadOnly.jpg | Bin 0 -> 163829 bytes alwayson-availability-group-detail.sql | 79 + ...yson-availability-group-replica-detail.sql | 106 + alwayson-dashboard.sql | 138 + alwayson-failover-times.sql | 12 + ...-readonly-replica-temporary-statistics.sql | 10 + alwayson-monitor-seeding.sql | 42 + ...-monitoring.sql => alwayson-monitoring.sql | 228 +- ... alwayson-pause-resume-synchronization.sql | 60 +- alwayson-stop-restart-auto-seeding.sql | 7 + alwayson-troubleshoot-hadr-endpoints.sql | 22 + alwayson-wait-stats.sql | 4 + backup-get-bakfile-information.sql | Bin 0 -> 1042 bytes ... backup-get-hist-avg-duration-and-size.sql | 276 +- backup-get-history.sql | 51 + ...ckup-get-most-recent-duration-and-size.sql | 90 +- backup-get-size-and-compression-ratio.sql | 17 + backup-log-truncate-only-or-null.sql | 1 + backup-restore-build-script.sql | 82 + backup-restore-get-estimated-completion.sql | 3 + ...up.sql => backup-restore-helper-script.sql | 78 +- backup-restore-service-master-key.sql | 9 + ...-file.sql => backup-verify-backup-file.sql | Bin cms-get-servers-and-groups.sql | 10 + ...on.sql => database-add-object-metadata.sql | Bin database-attach-files.sql | 11 + ...es.sql => database-detach-attach-files.sql | 163 +- ....sql => database-detangle-nested-views.sql | 183 +- database-enable-query-store-and-rcsi.sql | 28 + database-get-detail-and-config.sql | 207 + database-get-estimated-backup-size.sql | 35 + database-get-file-detail.sql | 58 + ... database-get-file-size-and-space-used.sql | 136 +- ...=> database-get-file-to-volume-mapping.sql | 50 +- ...=> database-get-foreign-keys-for-table.sql | 60 +- ...s-all.sql => database-get-foreign-keys.sql | 28 +- ...sql => database-get-log-file-VLF-count.sql | 84 +- database-get-log-info.sql | 11 + database-get-log-space.sql | 1 + ...ql => database-get-object-dependencies.sql | 78 +- database-get-orphan-logins.sql | 35 + database-get-scoped-configurations.sql | 22 + ... database-get-sparse-column-estimation.sql | 242 +- ...KDB.sql => database-get-status-CHECKDB.sql | 58 +- ...l => database-get-table-and-index-size.sql | 91 +- ...abase-get-table-compression-estimation.sql | 320 +- database-get-table-last-update-date.sql | 12 + database-get-table-size-all-dbs.sql | 80 + ...le-size.sql => database-get-table-size.sql | 75 +- ...database-get-tables-with-triggers-list.sql | 34 +- ...=> database-get-untrusted-foreign-keys.sql | 42 +- database-info/security-find-orphan-users.sql | 34 - database-migrate-encryption-keys.sql | 17 + database-relocate-files.sql | 48 + ...m-remap.sql => database-remap-synonyms.sql | 24 +- ...e.sql => database-resize-log-file-VLFs.sql | 66 +- database-revoke-connect-permissions.sql | 10 + ...> database-script-missing-foreign-keys.sql | 176 +- error-log-query-using-fn_dblog.sql | 5 + ... error-log-query-using-xp_readerrorlog.sql | 46 +- execute-as.sql | 20 + extended-events-get-deadlock-report.sql | 27 + get-blocking-info.sql | 416 ++ get-connected-logins.sql | 14 + get-connection-ip-address.sql | 3 + get-database-column-datatype.sql | 14 + get-session-aggregates.sql | 109 + get-session-details.sql | 19 + get-session-locks.sql | 32 + get-worker-thread-counts.sql | 8 + get-worker-threads.sql | 86 + ...e.sql => index-calc-estimated-row-size.sql | 56 +- ...d-indexes.sql => index-get-bad-indexes.sql | 58 +- ...table.sql => index-get-detail-by-table.sql | 453 +- ...dexes.sql => index-get-missing-indexes.sql | 0 ...ql => index-get-out-of-date-statistics.sql | 70 +- ...s.sql => index-get-overlapping-indexes.sql | 268 +- index-get-statistics-detail.sql | 43 + ...x-get-tables-without-clustered-indexes.sql | 78 +- index-get-usage-detail.sql | 197 + index-get-usage.sql | 12 + linked-server-get-list.sql | 25 + ...d-server-grant-access-to-windows-group.sql | 48 +- performance-tuning/explore-plan-cache.sql | 19 - .../find-CPU-intensive-queries.sql | 27 - performance-tuning/find-CPU-utilization.sql | 64 - performance-tuning/find-IO-latency.sql | 31 - performance-tuning/find-IO-user-tables.sql | 93 - ...find-TempDb-allocation-page-contention.sql | 16 - .../find-active-open-transactions.sql | 15 - .../find-active-orphan-transactions.sql | 13 - performance-tuning/find-blocking-queries.sql | 28 - .../find-buffer-cache-hit-ratio.sql | 9 - performance-tuning/find-cache-hit-ratios.sql | 31 - .../find-cumulative-wait-stats.sql | 41 - performance-tuning/find-memory-usage.sql | 186 - performance-tuning/find-objects-in-memory.sql | 65 - .../find-plan-cache-worst-queries.sql | 125 - .../find-procedure-performance.sql | 100 - .../find-procedure-worst-statement.sql | 20 - performance-tuning/index-get-IO-counts.sql | 96 - performance-tuning/index-plan-cache-usage.sql | 107 - performance-tuning/plan-cache-flush.sql | 93 - plan-cache-find-implicit-conversions.sql | 31 + plan-cache-find-longest-running-queries.sql | 16 + plan-cache-find-query-using-index.sql | 27 + query-default-trace.sql | 59 + query-store-enable.sql | 2 + query-store-find-failed-plan-forcing.sql | 16 + ...values-for-CostThresholdForParallelism.sql | 23 + query-store-find-high-cpu-queries.sql | 14 + query-store-find-most-freq-run-queries.sql | 18 + query-store-find-query-using-index.sql | 31 + query-store-find-query-with-run-stats.sql | 22 + query-store-find-query.sql | 19 + query-store-get-forced-plans.sql | 77 + query-store-get-runtime-intervals.sql | 4 + security-find-ownerships.sql | 22 + ...-permission-changes-from-default-trace.sql | 64 +- ...s.sql => security-get-ad-group-members.sql | 390 +- ...ity-audit.sql => security-get-db-audit.sql | 288 +- ...kdown.sql => security-get-db-breakdown.sql | 350 +- security-get-db-role-membership.sql | 44 + ... => security-get-server-role-dashboard.sql | 210 +- security-get-server-role-membership.sql | 20 + ...te-users.sql => security-migrate-users.sql | 61 +- ....sql => security-script-db-permissions.sql | 182 +- server-config/alert-CHECKDB-error.sql | 88 - ...rt-server-trigger-database-add-or-drop.sql | 59 - .../alert-sql-agent-job-step-failure.sql | 78 - server-config/tempdb-alter-filesize.sql | Bin 1076 -> 0 bytes ...ity-alerts.sql => server-create-alerts.sql | 380 +- ...ql => server-get-available-drive-space.sql | 42 +- server-get-cluster_name.sql | 6 + ...-cpu-count.sql => server-get-cpu-count.sql | 30 +- server-get-detail-and-config.sql | 254 + ...ances.sql => server-get-instances-list.sql | 32 +- server-get-last-restart-date.sql | 1 + server-get-policies.sql | 35 + server-get-principals.sql | 15 + server-get-services.sql | 18 + ...t.sql => server-get-startup-parameters.sql | 42 +- server-get-volumes.sql | 16 + server-info/linked-server-list.sql | 20 - server-info/server-detail-and-config.sql | 148 - ...n.sql => server-migrate-error-messages.sql | 58 +- ...p-MAXDOP-calc.sql => server-set-MAXDOP.sql | 84 +- ...-calc.sql => server-set-min-max-memory.sql | 104 +- ...t.sql => server-set-startup-parameters.sql | 300 +- server-setup-database-mail.sql | 59 + sp_who_is_active-run-as-script.sql | 5175 +++++++++++++++++ sql-agent-get-alerts.sql | 10 + sql-agent-get-failed-jobs.sql | 35 + sql-agent-get-job-schedules.sql | 17 + sql-agent-get-job-steps.sql | 20 + ...job-hist.sql => sql-agent-job-get-hist.sql | 420 +- ...job-list.sql => sql-agent-job-get-list.sql | 516 +- ...ry-powershell-subsystem-failed-to-load.sql | 74 +- ...move.sql => system-database-move-files.sql | 106 +- tempdb-add-alter-files.sql | Bin 0 -> 1242 bytes ...tempdb-get-session-created-that-object.sql | 44 +- trace-flag-enable-disable.sql | 150 + udf_XML2Table.sql | Bin 0 -> 6608 bytes wait-stats-SOS_SCHEDULER_YIELD.sql | 15 + wait-stats-capture-snapshot.sql | 201 + wait-stats-get-waits.sql | 13 + wait-stats-latch-snapshot.sql | 48 + 171 files changed, 12598 insertions(+), 5369 deletions(-) rename server-config/config-enable-DAC.sql => DAC-config-enable.sql (95%) create mode 100644 DAC-connection-info.sql create mode 100644 Ola-build-backup-script.sql create mode 100644 Ola-query-CommandLog.sql create mode 100644 alwayson-ApplicationIntent=ReadOnly.jpg create mode 100644 alwayson-availability-group-detail.sql create mode 100644 alwayson-availability-group-replica-detail.sql create mode 100644 alwayson-dashboard.sql create mode 100644 alwayson-failover-times.sql create mode 100644 alwayson-get-readonly-replica-temporary-statistics.sql create mode 100644 alwayson-monitor-seeding.sql rename server-info/alwayson-availability-group-monitoring.sql => alwayson-monitoring.sql (96%) rename server-config/alwayson-create-pause-and-resume-scripts.sql => alwayson-pause-resume-synchronization.sql (98%) create mode 100644 alwayson-stop-restart-auto-seeding.sql create mode 100644 alwayson-troubleshoot-hadr-endpoints.sql create mode 100644 alwayson-wait-stats.sql create mode 100644 backup-get-bakfile-information.sql rename server-info/backup-hist-avg-duration-and-size.sql => backup-get-hist-avg-duration-and-size.sql (98%) create mode 100644 backup-get-history.sql rename server-info/backup-most-recent-duration-and-size.sql => backup-get-most-recent-duration-and-size.sql (98%) create mode 100644 backup-get-size-and-compression-ratio.sql create mode 100644 backup-log-truncate-only-or-null.sql create mode 100644 backup-restore-build-script.sql create mode 100644 backup-restore-get-estimated-completion.sql rename database-config/backup-restore-db-backup.sql => backup-restore-helper-script.sql (95%) create mode 100644 backup-restore-service-master-key.sql rename database-config/backup-verify-backup-file.sql => backup-verify-backup-file.sql (100%) create mode 100644 cms-get-servers-and-groups.sql rename database-config/ddl-add-column-description.sql => database-add-object-metadata.sql (100%) create mode 100644 database-attach-files.sql rename server-config/detach-and-attach-db-files.sql => database-detach-attach-files.sql (56%) rename database-info/views-detangle-nested.sql => database-detangle-nested-views.sql (94%) create mode 100644 database-enable-query-store-and-rcsi.sql create mode 100644 database-get-detail-and-config.sql create mode 100644 database-get-estimated-backup-size.sql create mode 100644 database-get-file-detail.sql rename database-info/file-size-and-space-used.sql => database-get-file-size-and-space-used.sql (93%) rename database-info/file-to-volume-mapping.sql => database-get-file-to-volume-mapping.sql (97%) rename database-info/foreign-keys-table.sql => database-get-foreign-keys-for-table.sql (98%) rename database-info/foreign-keys-all.sql => database-get-foreign-keys.sql (75%) rename database-info/log-file-VLF-count.sql => database-get-log-file-VLF-count.sql (94%) create mode 100644 database-get-log-info.sql create mode 100644 database-get-log-space.sql rename database-info/object-dependencies.sql => database-get-object-dependencies.sql (92%) create mode 100644 database-get-orphan-logins.sql create mode 100644 database-get-scoped-configurations.sql rename database-config/sparse-column-estimation.sql => database-get-sparse-column-estimation.sql (95%) rename database-info/status-CHECKDB.sql => database-get-status-CHECKDB.sql (96%) rename database-info/table-and-index-size.sql => database-get-table-and-index-size.sql (85%) rename database-config/table-compression-estimation.sql => database-get-table-compression-estimation.sql (96%) create mode 100644 database-get-table-last-update-date.sql create mode 100644 database-get-table-size-all-dbs.sql rename database-info/table-size.sql => database-get-table-size.sql (87%) rename database-info/trigger-table-list.sql => database-get-tables-with-triggers-list.sql (97%) rename database-info/foreign-keys-find-not-trusted.sql => database-get-untrusted-foreign-keys.sql (97%) delete mode 100644 database-info/security-find-orphan-users.sql create mode 100644 database-migrate-encryption-keys.sql create mode 100644 database-relocate-files.sql rename database-config/synonym-remap.sql => database-remap-synonyms.sql (96%) rename database-config/log-file-VLF-resize.sql => database-resize-log-file-VLFs.sql (96%) create mode 100644 database-revoke-connect-permissions.sql rename database-info/foreign-keys-find-and-script-missing.sql => database-script-missing-foreign-keys.sql (97%) create mode 100644 error-log-query-using-fn_dblog.sql rename server-info/error-log-view-using-xp_readerrorlog.sql => error-log-query-using-xp_readerrorlog.sql (95%) create mode 100644 execute-as.sql create mode 100644 extended-events-get-deadlock-report.sql create mode 100644 get-blocking-info.sql create mode 100644 get-connected-logins.sql create mode 100644 get-connection-ip-address.sql create mode 100644 get-database-column-datatype.sql create mode 100644 get-session-aggregates.sql create mode 100644 get-session-details.sql create mode 100644 get-session-locks.sql create mode 100644 get-worker-thread-counts.sql create mode 100644 get-worker-threads.sql rename database-info/index-calc-estimated-row-size.sql => index-calc-estimated-row-size.sql (96%) rename performance-tuning/index-find-bad-indexes.sql => index-get-bad-indexes.sql (97%) rename database-info/index-detail-by-table.sql => index-get-detail-by-table.sql (97%) rename performance-tuning/index-find-missing-indexes.sql => index-get-missing-indexes.sql (100%) rename performance-tuning/statistics-find-out-of-date-statistics.sql => index-get-out-of-date-statistics.sql (93%) rename performance-tuning/index-find-overlapping-indexes.sql => index-get-overlapping-indexes.sql (97%) create mode 100644 index-get-statistics-detail.sql rename performance-tuning/index-find-tables-without-clustered-indexes.sql => index-get-tables-without-clustered-indexes.sql (92%) create mode 100644 index-get-usage-detail.sql create mode 100644 index-get-usage.sql create mode 100644 linked-server-get-list.sql rename server-config/linked-server-grant-access-to-windows-group.sql => linked-server-grant-access-to-windows-group.sql (97%) delete mode 100644 performance-tuning/explore-plan-cache.sql delete mode 100644 performance-tuning/find-CPU-intensive-queries.sql delete mode 100644 performance-tuning/find-CPU-utilization.sql delete mode 100644 performance-tuning/find-IO-latency.sql delete mode 100644 performance-tuning/find-IO-user-tables.sql delete mode 100644 performance-tuning/find-TempDb-allocation-page-contention.sql delete mode 100644 performance-tuning/find-active-open-transactions.sql delete mode 100644 performance-tuning/find-active-orphan-transactions.sql delete mode 100644 performance-tuning/find-blocking-queries.sql delete mode 100644 performance-tuning/find-buffer-cache-hit-ratio.sql delete mode 100644 performance-tuning/find-cache-hit-ratios.sql delete mode 100644 performance-tuning/find-cumulative-wait-stats.sql delete mode 100644 performance-tuning/find-memory-usage.sql delete mode 100644 performance-tuning/find-objects-in-memory.sql delete mode 100644 performance-tuning/find-plan-cache-worst-queries.sql delete mode 100644 performance-tuning/find-procedure-performance.sql delete mode 100644 performance-tuning/find-procedure-worst-statement.sql delete mode 100644 performance-tuning/index-get-IO-counts.sql delete mode 100644 performance-tuning/index-plan-cache-usage.sql delete mode 100644 performance-tuning/plan-cache-flush.sql create mode 100644 plan-cache-find-implicit-conversions.sql create mode 100644 plan-cache-find-longest-running-queries.sql create mode 100644 plan-cache-find-query-using-index.sql create mode 100644 query-default-trace.sql create mode 100644 query-store-enable.sql create mode 100644 query-store-find-failed-plan-forcing.sql create mode 100644 query-store-find-good-values-for-CostThresholdForParallelism.sql create mode 100644 query-store-find-high-cpu-queries.sql create mode 100644 query-store-find-most-freq-run-queries.sql create mode 100644 query-store-find-query-using-index.sql create mode 100644 query-store-find-query-with-run-stats.sql create mode 100644 query-store-find-query.sql create mode 100644 query-store-get-forced-plans.sql create mode 100644 query-store-get-runtime-intervals.sql create mode 100644 security-find-ownerships.sql rename server-info/security-find-permission-changes-in-default-trace.sql => security-find-permission-changes-from-default-trace.sql (98%) rename database-info/security-ad-group-members.sql => security-get-ad-group-members.sql (97%) rename database-info/security-audit.sql => security-get-db-audit.sql (95%) rename database-info/security-db-breakdown.sql => security-get-db-breakdown.sql (96%) create mode 100644 security-get-db-role-membership.sql rename database-info/security-role-breakdown.sql => security-get-server-role-dashboard.sql (97%) create mode 100644 security-get-server-role-membership.sql rename server-config/security-migrate-users.sql => security-migrate-users.sql (85%) rename server-config/security-generate-sql-login-permissions.sql => security-script-db-permissions.sql (97%) delete mode 100644 server-config/alert-CHECKDB-error.sql delete mode 100644 server-config/alert-server-trigger-database-add-or-drop.sql delete mode 100644 server-config/alert-sql-agent-job-step-failure.sql delete mode 100644 server-config/tempdb-alter-filesize.sql rename server-config/alert-create-error-msg-severity-alerts.sql => server-create-alerts.sql (97%) rename server-info/volume-available-drive-space.sql => server-get-available-drive-space.sql (96%) create mode 100644 server-get-cluster_name.sql rename server-info/server-cpu-count.sql => server-get-cpu-count.sql (95%) create mode 100644 server-get-detail-and-config.sql rename server-info/server-list-named-instances.sql => server-get-instances-list.sql (96%) create mode 100644 server-get-last-restart-date.sql create mode 100644 server-get-policies.sql create mode 100644 server-get-principals.sql create mode 100644 server-get-services.sql rename server-config/startup-parameters_get.sql => server-get-startup-parameters.sql (96%) create mode 100644 server-get-volumes.sql delete mode 100644 server-info/linked-server-list.sql delete mode 100644 server-info/server-detail-and-config.sql rename server-config/error-message-migration.sql => server-migrate-error-messages.sql (97%) rename server-config/setup-MAXDOP-calc.sql => server-set-MAXDOP.sql (95%) rename server-config/setup-min-max-memory-calc.sql => server-set-min-max-memory.sql (97%) rename server-config/startup-parameters_set.sql => server-set-startup-parameters.sql (97%) create mode 100644 server-setup-database-mail.sql create mode 100644 sp_who_is_active-run-as-script.sql create mode 100644 sql-agent-get-alerts.sql create mode 100644 sql-agent-get-failed-jobs.sql create mode 100644 sql-agent-get-job-schedules.sql create mode 100644 sql-agent-get-job-steps.sql rename server-info/sql-agent-job-hist.sql => sql-agent-job-get-hist.sql (98%) rename server-info/sql-agent-job-list.sql => sql-agent-job-get-list.sql (91%) rename server-config/sql-agent-syspolicy_purge_history-powershell-subsystem-failed-to-load.sql => sql-agent-syspolicy_purge_history-powershell-subsystem-failed-to-load.sql (97%) rename server-config/system-database-file-move.sql => system-database-move-files.sql (96%) create mode 100644 tempdb-add-alter-files.sql rename database-info/tempdb-what-session-created-that-object.sql => tempdb-get-session-created-that-object.sql (97%) create mode 100644 trace-flag-enable-disable.sql create mode 100644 udf_XML2Table.sql create mode 100644 wait-stats-SOS_SCHEDULER_YIELD.sql create mode 100644 wait-stats-capture-snapshot.sql create mode 100644 wait-stats-get-waits.sql create mode 100644 wait-stats-latch-snapshot.sql diff --git a/server-config/config-enable-DAC.sql b/DAC-config-enable.sql similarity index 95% rename from server-config/config-enable-DAC.sql rename to DAC-config-enable.sql index 2f6c25c..d22b06b 100644 --- a/server-config/config-enable-DAC.sql +++ b/DAC-config-enable.sql @@ -1,29 +1,29 @@ -Use master -GO -/* 0 = Allow Local Connection, 1 = Allow Remote Connections*/ -sp_configure 'remote admin connections', 1 -GO -RECONFIGURE -GO - -/* --- Using DAC with SQLCMD -SQLCMD –S [SQL Server Name] –U [User Name] –P [Password] –A - --- SSMS --- specify “ADMIN:” before the SQL Server Instance name -*/ - -/* Common DAC requests */ --- Active Locks -SELECT * FROM sys.dm_tran_locks -GO --- Cache Status -SELECT * FROM sys.dm_os_memory_cache_counters -GO --- Active Sessions -SELECT * FROM sys.dm_exec_sessions -GO --- Requests Status -SELECT * FROM sys.dm_exec_requests -GO +Use master +GO +/* 0 = Allow Local Connection, 1 = Allow Remote Connections*/ +sp_configure 'remote admin connections', 1 +GO +RECONFIGURE +GO + +/* +-- Using DAC with SQLCMD +SQLCMD –S [SQL Server Name] –U [User Name] –P [Password] –A + +-- SSMS +-- specify “ADMIN:” before the SQL Server Instance name +*/ + +/* Common DAC requests */ +-- Active Locks +SELECT * FROM sys.dm_tran_locks +GO +-- Cache Status +SELECT * FROM sys.dm_os_memory_cache_counters +GO +-- Active Sessions +SELECT * FROM sys.dm_exec_sessions +GO +-- Requests Status +SELECT * FROM sys.dm_exec_requests +GO diff --git a/DAC-connection-info.sql b/DAC-connection-info.sql new file mode 100644 index 0000000..270566c --- /dev/null +++ b/DAC-connection-info.sql @@ -0,0 +1,28 @@ +/* +Who's Using the DAC? +http://www.sqlservercentral.com/articles/Dedicated+Administrator+Connection+(DAC)/174694/ + +Who’s Been Sleeping in My DAC? How to Tell Who’s using the Dedicated Admin Connection. +https://www.brentozar.com/archive/2011/08/dedicated-admin-connection-why-want-when-need-how-tell-whos-using/ +*/ + +-- confirm DAC endpoint exists +select * from sys.endpoints where name = 'Dedicated Admin Connection'; + +-- see who's using it +SELECT CASE WHEN s.session_id= @@SPID THEN 'It''s me! ' + ELSE '' + END + coalesce(s.login_name,'???') as WhosGotTheDAC , + s.session_id , + s.login_name , + s.nt_domain , + s.nt_user_name , + s.login_time , + s.host_name , + s.program_name , + s.status , + s.original_login_name +FROM sys.dm_exec_sessions s + INNER JOIN sys.endpoints e ON e.endpoint_id = s.endpoint_id +WHERE e.name='Dedicated Admin Connection'; + diff --git a/Ola-build-backup-script.sql b/Ola-build-backup-script.sql new file mode 100644 index 0000000..859a112 --- /dev/null +++ b/Ola-build-backup-script.sql @@ -0,0 +1,18 @@ + +DECLARE @SQL NVARCHAR(4000) + ,@DefaultBackup NVARCHAR(512); + +EXEC master.dbo.xp_instance_regread + @rootkey='HKEY_LOCAL_MACHINE', + @key='SOFTWARE\Microsoft\MSSQLServer\MSSQLServer', + @value_name='BackupDirectory', + @value=@DefaultBackup OUTPUT; + +SELECT 'EXECUTE [dbo].[DatabaseBackup] +@Databases = ''' + name + ''', +@Directory = ''' + @DefaultBackup + ''', +@BackupType = ''FULL'', +@Compress = ''Y'', +@LogToTable = ''Y'';' +FROM sys.databases +WHERE database_id > 4 \ No newline at end of file diff --git a/Ola-query-CommandLog.sql b/Ola-query-CommandLog.sql new file mode 100644 index 0000000..2876af2 --- /dev/null +++ b/Ola-query-CommandLog.sql @@ -0,0 +1,30 @@ + +DECLARE @ClusterName VARCHAR(128); + +SELECT @ClusterName = cluster_name +FROM master.sys.dm_hadr_cluster +WHERE LEFT(cluster_name, 1) LIKE '[a-z]'; + +IF EXISTS (SELECT 1 FROM sys.databases WHERE name = 'DBMaint') + IF EXISTS (SELECT 1 FROM DBMaint.sys.tables WHERE name = 'CommandLog') + SELECT @ClusterName AS clustername + ,@@SERVERNAME AS ServerName + ,DEFAULT_DOMAIN() AS Domain + ,DatabaseName + ,SchemaName + ,ObjectName + ,ObjectType + ,IndexName + ,IndexType + ,PartitionNumber + ,ExtendedInfo.value('(/ExtendedInfo/PageCount)[1]', 'int') AS PageCount + ,ExtendedInfo.value('(/ExtendedInfo/Fragmentation)[1]', 'numeric(9,4)') AS Fragmentation + ,TRY_CONVERT(VARCHAR(2000),Command) AS Command + ,CommandType + ,StartTime + ,EndTime + ,ErrorNumber + ,TRY_CONVERT(VARCHAR(2000),ErrorMessage) AS ErrorMessage + FROM dbo.CommandLog + WHERE CommandType IN ('ALTER_INDEX', 'DBCC_CHECKDB', 'BACKUP_DATABASE') + AND EndTime IS NOT NULL; diff --git a/alwayson-ApplicationIntent=ReadOnly.jpg b/alwayson-ApplicationIntent=ReadOnly.jpg new file mode 100644 index 0000000000000000000000000000000000000000..22276a03ce8fb9181b726eed0b365b7fa35c4e78 GIT binary patch literal 163829 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�paB*h; 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 literal 0 HcmV?d00001 diff --git a/alwayson-availability-group-detail.sql b/alwayson-availability-group-detail.sql new file mode 100644 index 0000000..71ec17e --- /dev/null +++ b/alwayson-availability-group-detail.sql @@ -0,0 +1,79 @@ + +-- RUN ON PRIMARY -- + +DECLARE @IsHadrEnabled TINYINT = CONVERT(TINYINT,SERVERPROPERTY ('IsHadrEnabled')) + ,@ServerName NVARCHAR(256) = @@SERVERNAME + ,@RoleDesc NVARCHAR(60) = 'PRIMARY' + ,@AG_SQL NVARCHAR(MAX) + ,@Version VARCHAR(50) = LEFT(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR(128)),2); + +DECLARE @AGs TABLE ( + domain VARCHAR(128) NOT NULL + ,primaryreplicaservername VARCHAR(128) NOT NULL + ,availabilitygroupname VARCHAR(128) NOT NULL + ,failure_condition_level INT NOT NULL + ,health_check_timeout INT NOT NULL + ,automated_backup_preference TINYINT NOT NULL + ,listener_name VARCHAR(63) NULL + ,listener_port INT NULL + ,listener_ip VARCHAR(200) NULL + ,dtc_support BIT NULL + ,db_failover BIT NULL +); + +IF (@IsHadrEnabled = 1) +AND EXISTS ( + SELECT 1 + FROM sys.dm_hadr_availability_replica_states AS a + JOIN sys.availability_replicas AS b + ON b.replica_id = a.replica_id + WHERE b.replica_server_name = @ServerName + AND a.role_desc = @RoleDesc +) +BEGIN + SELECT * + INTO #availability_groups + FROM sys.availability_groups; + + SELECT group_id, dns_name, port, ip_configuration_string_from_cluster + INTO #availability_group_listeners + FROM sys.availability_group_listeners; + + SET @AG_SQL = ' + SELECT DEFAULT_DOMAIN() as domain + ,''' + @ServerName + ''' as primaryreplicaservername + ,ag.name + ,ag.failure_condition_level + ,ag.health_check_timeout + ,ag.automated_backup_preference + ,l.dns_name + ,l.port + ,l.ip_configuration_string_from_cluster' + + CASE WHEN @Version > 11 THEN ' ,ag.dtc_support' ELSE ' ,NULL' END + + CASE WHEN @Version > 11 THEN ' ,ag.db_failover' ELSE ' ,NULL' END + ' + FROM #availability_groups ag + JOIN #availability_group_listeners l ON ag.group_id = l.group_id' + + INSERT @AGs ( + domain + ,primaryreplicaservername + ,availabilitygroupname + ,failure_condition_level + ,health_check_timeout + ,automated_backup_preference + ,listener_name + ,listener_port + ,listener_ip + ,dtc_support + ,db_failover + ) + EXEC sp_executesql @AG_SQL; +END; + +SELECT * FROM @AGs; + +IF OBJECT_ID('tempdb..#availability_groups') IS NOT NULL + DROP TABLE #availability_groups; + +IF OBJECT_ID('tempdb..#availability_group_listeners') IS NOT NULL + DROP TABLE #availability_group_listeners; diff --git a/alwayson-availability-group-replica-detail.sql b/alwayson-availability-group-replica-detail.sql new file mode 100644 index 0000000..ec179a2 --- /dev/null +++ b/alwayson-availability-group-replica-detail.sql @@ -0,0 +1,106 @@ + +-- RUN ON PRIMARY -- + +DECLARE @IsHadrEnabled TINYINT = CONVERT(TINYINT,SERVERPROPERTY ('IsHadrEnabled')) + ,@ServerName NVARCHAR(256) = @@SERVERNAME + ,@RoleDesc NVARCHAR(60) = 'PRIMARY' + ,@AG_SQL NVARCHAR(MAX) + ,@Version VARCHAR(50) = LEFT(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR(128)),2); + +DECLARE @AGs TABLE ( + domain VARCHAR(128) NOT NULL + ,availabilitygroupname VARCHAR(128) NOT NULL + ,replicaservername VARCHAR(128) NOT NULL + ,endpoint_url VARCHAR(128) NULL + ,availability_mode TINYINT NOT NULL + ,failover_mode TINYINT NOT NULL + ,session_timeout INT NOT NULL + ,primary_role_allow_connections TINYINT NOT NULL + ,secondary_role_allow_connections TINYINT NOT NULL + ,backup_priority INT NOT NULL + ,read_only_routing_url VARCHAR(256) NULL + ,seeding_mode TINYINT NULL + ,read_only_routing_lists VARCHAR(1000) NULL +); + +IF (@IsHadrEnabled = 1) +AND EXISTS ( + SELECT 1 + FROM sys.dm_hadr_availability_replica_states AS a + JOIN sys.availability_replicas AS b + ON b.replica_id = a.replica_id + WHERE b.replica_server_name = @ServerName + AND a.role_desc = @RoleDesc +) +BEGIN + SELECT * + INTO #availability_read_only_routing_lists + FROM sys.availability_read_only_routing_lists; + + SELECT * + INTO #availability_replicas + FROM sys.availability_replicas; + + SELECT group_id, name + INTO #availability_groups + FROM sys.availability_groups; + + SET @AG_SQL = ' + WITH read_only_routing_lists AS ( + + SELECT r.replica_id + ,STUFF(( + SELECT '','' + ror.replica_server_name + FROM #availability_read_only_routing_lists l + JOIN #availability_replicas ror ON l.read_only_replica_id = ror.replica_id + WHERE r.replica_id = l.replica_id + ORDER BY l.routing_priority + FOR XML PATH(''''),TYPE).value(''.'',''VARCHAR(MAX)''),1,1,'''') AS read_only_replicas + FROM #availability_replicas r + ) + +SELECT DEFAULT_DOMAIN() as domain + ,ag.name + ,r.replica_server_name + ,r.endpoint_url + ,r.availability_mode + ,r.failover_mode + ,r.session_timeout + ,r.primary_role_allow_connections + ,r.secondary_role_allow_connections + ,r.backup_priority + ,r.read_only_routing_url' + + CASE WHEN @Version > 11 THEN ' ,r.seeding_mode' ELSE ' ,NULL' END + ' + ,ro.read_only_replicas +FROM #availability_groups ag + JOIN #availability_replicas r on ag.group_id = r.group_id + LEFT JOIN read_only_routing_lists ro ON r.replica_id = ro.replica_id' + + INSERT @AGs ( + domain + ,availabilitygroupname + ,replicaservername + ,endpoint_url + ,availability_mode + ,failover_mode + ,session_timeout + ,primary_role_allow_connections + ,secondary_role_allow_connections + ,backup_priority + ,read_only_routing_url + ,seeding_mode + ,read_only_routing_lists + ) + EXEC sp_executesql @AG_SQL; +END; + +SELECT * FROM @AGs; + +IF OBJECT_ID('tempdb..#availability_read_only_routing_lists') IS NOT NULL + DROP TABLE #availability_read_only_routing_lists; + +IF OBJECT_ID('tempdb..#availability_replicas') IS NOT NULL + DROP TABLE #availability_replicas; + +IF OBJECT_ID('tempdb..#availability_groups') IS NOT NULL + DROP TABLE #availability_groups; diff --git a/alwayson-dashboard.sql b/alwayson-dashboard.sql new file mode 100644 index 0000000..3ee011b --- /dev/null +++ b/alwayson-dashboard.sql @@ -0,0 +1,138 @@ +/***** +7 ways to Query Always On Availability Groups using SQL +https://sqlundercover.com/2017/09/19/7-ways-to-query-always-on-availability-groups-using-sql/ +*****/ + +SET NOCOUNT ON; + +DECLARE @AGname NVARCHAR(128) = NULL --SET AGname for a specific AG or NULL for ALL AG's + ,@SecondaryReplicasOnly BIT; + +IF OBJECT_ID('TempDB..#tmpag_availability_groups') IS NOT NULL + DROP TABLE [#tmpag_availability_groups]; + +SELECT * +INTO [#tmpag_availability_groups] +FROM [master].[sys].[availability_groups]; + +IF @AGname IS NULL +OR EXISTS ( + SELECT [Name] + FROM [#tmpag_availability_groups] + WHERE [Name] = @AGname +) +BEGIN + IF OBJECT_ID('TempDB..#tmpdbr_availability_replicas') IS NOT NULL + DROP TABLE [#tmpdbr_availability_replicas]; + + IF OBJECT_ID('TempDB..#tmpdbr_database_replica_cluster_states') IS NOT NULL + DROP TABLE [#tmpdbr_database_replica_cluster_states]; + + IF OBJECT_ID('TempDB..#tmpdbr_database_replica_states') IS NOT NULL + DROP TABLE [#tmpdbr_database_replica_states]; + + IF OBJECT_ID('TempDB..#tmpdbr_database_replica_states_primary_LCT') IS NOT NULL + DROP TABLE [#tmpdbr_database_replica_states_primary_LCT]; + + IF OBJECT_ID('TempDB..#tmpdbr_availability_replica_states') IS NOT NULL + DROP TABLE [#tmpdbr_availability_replica_states]; + + SELECT [group_id] + ,[replica_id] + ,[replica_server_name] + ,[availability_mode] + ,[availability_mode_desc] + INTO [#tmpdbr_availability_replicas] + FROM [master].[sys].[availability_replicas]; + + SELECT [replica_id] + ,[group_database_id] + ,[database_name] + ,[is_database_joined] + ,[is_failover_ready] + INTO [#tmpdbr_database_replica_cluster_states] + FROM [master].[sys].[dm_hadr_database_replica_cluster_states]; + + SELECT * + INTO [#tmpdbr_database_replica_states] + FROM [master].[sys].[dm_hadr_database_replica_states]; + + SELECT [replica_id] + ,[role] + ,[role_desc] + ,[is_local] + INTO [#tmpdbr_availability_replica_states] + FROM [master].[sys].[dm_hadr_availability_replica_states]; + + SELECT [ars].[role] + ,[drs].[database_id] + ,[drs].[replica_id] + ,[drs].[last_commit_time] + INTO [#tmpdbr_database_replica_states_primary_LCT] + FROM [#tmpdbr_database_replica_states] AS [drs] + LEFT JOIN [#tmpdbr_availability_replica_states] [ars] + ON [drs].[replica_id] = [ars].[replica_id] + WHERE [ars].[role] = 1; + + SELECT [AG].[name] AS [AvailabilityGroupName] + ,[AR].[replica_server_name] AS [AvailabilityReplicaServerName] + ,[dbcs].[database_name] AS [AvailabilityDatabaseName] + ,ISNULL([dbcs].[is_failover_ready], 0) AS [IsFailoverReady] + ,ISNULL([arstates].[role_desc], 3) AS [ReplicaRole] + ,[AR].[availability_mode_desc] AS [AvailabilityMode] + ,CASE [dbcs].[is_failover_ready] + WHEN 1 THEN 0 + ELSE ISNULL(DATEDIFF([ss], [dbr].[last_commit_time], [dbrp].[last_commit_time]), 0) + END AS [EstimatedDataLoss_(Seconds)] + ,ISNULL(CASE [dbr].[redo_rate] + WHEN 0 THEN -1 + ELSE CAST([dbr].[redo_queue_size] AS FLOAT) / NULLIF([dbr].[redo_rate] ,0) + END, -1) AS [EstimatedRecoveryTime_(Seconds)] + ,ISNULL([dbr].[is_suspended], 0) AS [IsSuspended] + ,ISNULL([dbr].[suspend_reason_desc], '-') AS [SuspendReason] + ,ISNULL([dbr].[synchronization_health_desc], 0) AS [SynchronizationHealth] + ,ISNULL([dbr].[synchronization_state_desc], 0) AS [SynchronizationState] + ,ISNULL([dbr].[last_received_time], 0) AS [LastReceivedTime] + ,ISNULL([dbr].[last_redone_time], 0) AS [LastRedoneTime] + ,ISNULL([dbr].[last_sent_time], 0) AS [LastSentTime] + ,ISNULL([dbr].[log_send_queue_size], -1) + /1024 AS [LogSendQueueSize_MB] + ,ISNULL([dbr].[log_send_rate], -1) + /1024 AS [LogSendRate_MB/S] + ,ISNULL([dbr].[redo_queue_size], -1) AS [RedoQueueSize_KB] + ,ISNULL([dbr].[redo_rate], -1) AS [RedoRate_KB/S] + ,ISNULL(CASE [dbr].[log_send_rate] + WHEN 0 THEN -1 + ELSE Cast([dbr].[log_send_queue_size] AS FLOAT) / NULLIF([dbr].[log_send_rate] ,0) + END, -1) AS [SynchronizationPerformance] + ,ISNULL([dbr].[filestream_send_rate], -1) AS [FileStreamSendRate] + ,ISNULL([dbcs].[is_database_joined], 0) AS [IsJoined] + ,[arstates].[is_local] AS [IsLocal] + ,ISNULL([dbr].[last_commit_lsn], 0) AS [LastCommitLSN] + ,ISNULL([dbr].[last_commit_time], 0) AS [LastCommitTime] + ,ISNULL([dbr].[last_hardened_lsn], 0) AS [LastHardenedLSN] + ,ISNULL([dbr].[last_hardened_time], 0) AS [LastHardenedTime] + ,ISNULL([dbr].[last_received_lsn], 0) AS [LastReceivedLSN] + ,ISNULL([dbr].[last_redone_lsn], 0) AS [LastRedoneLSN] + FROM [#tmpag_availability_groups] AS [AG] + INNER JOIN [#tmpdbr_availability_replicas] AS [AR] + ON [AR].[group_id] = [AG].[group_id] + INNER JOIN [#tmpdbr_database_replica_cluster_states] AS [dbcs] + ON [dbcs].[replica_id] = [AR].[replica_id] + LEFT OUTER JOIN [#tmpdbr_database_replica_states] AS [dbr] + ON [dbcs].[replica_id] = [dbr].[replica_id] + AND [dbcs].[group_database_id] = [dbr].[group_database_id] + LEFT OUTER JOIN [#tmpdbr_database_replica_states_primary_LCT] AS [dbrp] + ON [dbr].[database_id] = [dbrp].[database_id] + INNER JOIN [#tmpdbr_availability_replica_states] AS [arstates] + ON [arstates].[replica_id] = [AR].[replica_id] + WHERE [AG].[name] = ISNULL(@AGname, [AG].[name]) + ORDER BY [LogSendQueueSize_MB] DESC + , [EstimatedDataLoss_(Seconds)] DESC + , [AvailabilityDatabaseName] ASC + , [AvailabilityReplicaServerName] ASC +END; +ELSE +BEGIN + RAISERROR('Invalid AG name supplied, please correct and try again',12,0); +END; diff --git a/alwayson-failover-times.sql b/alwayson-failover-times.sql new file mode 100644 index 0000000..34f073b --- /dev/null +++ b/alwayson-failover-times.sql @@ -0,0 +1,12 @@ +-- Script to determine failover times in Availability Group + +;WITH cte_HADR AS (SELECT object_name, CONVERT(XML, event_data) AS data +FROM sys.fn_xe_file_target_read_file('AlwaysOn*.xel', null, null, null) +WHERE object_name = 'error_reported' +) + +SELECT data.value('(/event/@timestamp)[1]','datetime') AS [timestamp], + data.value('(/event/data[@name=''error_number''])[1]','int') AS [error_number], + data.value('(/event/data[@name=''message''])[1]','varchar(max)') AS [message] +FROM cte_HADR +WHERE data.value('(/event/data[@name=''error_number''])[1]','int') = 1480 diff --git a/alwayson-get-readonly-replica-temporary-statistics.sql b/alwayson-get-readonly-replica-temporary-statistics.sql new file mode 100644 index 0000000..20300ba --- /dev/null +++ b/alwayson-get-readonly-replica-temporary-statistics.sql @@ -0,0 +1,10 @@ +USE tempdb; +GO + +SELECT OBJECT_NAME(s.object_id) AS ObjectName + ,COL_NAME(sc.object_id, sc.column_id) AS ColumnName + ,s.name AS StatisticsName +FROM sys.stats s + JOIN sys.stats_columns sc ON s.stats_id = sc.stats_id AND s.object_id = sc.object_id +WHERE s.is_temporary <> 0 +ORDER BY s.name; diff --git a/alwayson-monitor-seeding.sql b/alwayson-monitor-seeding.sql new file mode 100644 index 0000000..f6f3496 --- /dev/null +++ b/alwayson-monitor-seeding.sql @@ -0,0 +1,42 @@ +DECLARE @DatabaseName VARCHAR(128) = NULL; -- leave NULL for all + +SELECT ag.name AS ag_name + ,adc.database_name + ,r.replica_server_name AS replica_name + ,dhas.start_time + ,dhas.completion_time + ,dhas.current_state + ,dhas.failure_state_desc + ,dhas.number_of_attempts + ,dhpss.transfer_rate_bytes_per_second + ,dhpss.transferred_size_bytes + ,dhpss.database_size_bytes + ,dhpss.start_time_utc + ,dhpss.end_time_utc + ,dhpss.estimate_time_complete_utc + ,dhpss.total_disk_io_wait_time_ms + ,dhpss.total_network_wait_time_ms + ,dhpss.failure_code + ,dhpss.failure_message + ,dhpss.failure_time_utc + ,dhpss.is_compression_enabled +FROM sys.availability_groups ag + JOIN sys.availability_replicas r ON ag.group_id = r.group_id + JOIN sys.availability_databases_cluster adc ON ag.group_id=adc.group_id + JOIN sys.dm_hadr_automatic_seeding AS dhas ON dhas.ag_id = ag.group_id + LEFT JOIN sys.dm_hadr_physical_seeding_stats AS dhpss ON adc.database_name = dhpss.local_database_name +WHERE (adc.database_name = @DatabaseName OR @DatabaseName IS NULL) +ORDER BY dhas.start_time DESC; + + +SELECT r.session_id + ,r.status + ,r.command + ,r.wait_type + ,r.percent_complete + ,r.estimated_completion_time +FROM sys.dm_exec_requests r + JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id +WHERE r.session_id <> @@SPID +AND s.is_user_process = 0 +AND r.command like 'VDI%'; diff --git a/server-info/alwayson-availability-group-monitoring.sql b/alwayson-monitoring.sql similarity index 96% rename from server-info/alwayson-availability-group-monitoring.sql rename to alwayson-monitoring.sql index f0ec914..af54a0f 100644 --- a/server-info/alwayson-availability-group-monitoring.sql +++ b/alwayson-monitoring.sql @@ -1,114 +1,114 @@ -USE master; -GO - --- WSFC cluster node configuration: reports status of each member node of the cluster -SELECT member_name - ,member_type - ,member_type_desc - ,member_state - ,member_state_desc - ,number_of_quorum_votes -FROM sys.dm_hadr_cluster_members; -GO - --- WSFC cluster network: contains one row for each network adapter in the cluster -SELECT member_name - ,network_subnet_ip - ,network_subnet_ipv4_mask - ,network_subnet_prefix_length - ,is_public - ,is_ipv4 -FROM sys.dm_hadr_cluster_networks; -GO - --- Availability groups --- reports current health statuses -SELECT primary_replica - ,primary_recovery_health_desc - ,synchronization_health_desc -FROM sys.dm_hadr_availability_group_states; -GO --- reports metadata cached in SQL Server process space -SELECT group_id - ,name - ,resource_id - ,resource_group_id - ,failure_condition_level - ,health_check_timeout - ,automated_backup_preference - ,automated_backup_preference_desc -FROM sys.availability_groups; -GO --- reports metadata stored in WSFC Cluster -SELECT group_id - ,name - ,resource_id - ,resource_group_id - ,failure_condition_level - ,health_check_timeout - ,automated_backup_preference - ,automated_backup_preference_desc -FROM sys.availability_groups_cluster; -GO - --- Availability replicas --- reports current health statuses -SELECT replica_id - ,role_desc - ,recovery_health_desc - ,synchronization_health_desc -FROM sys.dm_hadr_availability_replica_states; -GO --- reports state information locally cached in SQL Server -SELECT replica_id - ,role_desc - ,connected_state_desc - ,synchronization_health_desc -FROM sys.dm_hadr_availability_replica_states; -GO --- reports configuration data cached locally in SQL Server -SELECT replica_server_name - ,replica_id - ,availability_mode_desc - ,endpoint_url -FROM sys.availability_replicas; -GO --- reports state information from WSFC cluster -SELECT replica_server_name - ,join_state_desc -FROM sys.dm_hadr_availability_replica_cluster_states; -GO - --- Availability databases --- reports current health statuses -SELECT dc.database_name - ,dr.database_id - ,dr.synchronization_state_desc - ,dr.suspend_reason_desc - ,dr.synchronization_health_desc -FROM sys.dm_hadr_database_replica_states dr - JOIN sys.availability_databases_cluster dc - ON dr.group_database_id = dc.group_database_id -WHERE dr.is_local = 1; -GO --- reports configuration information from WSFC cluster -SELECT group_id - ,group_database_id - ,database_name -FROM sys.availability_databases_cluster; -GO --- reports state information locally cached in SQL Server -SELECT group_database_id - ,database_name - ,is_failover_ready -FROM sys.dm_hadr_database_replica_cluster_states; -GO --- reports identity and state information, such as LSN progress information for logs of primary and secondary replicas -SELECT database_id - ,synchronization_state_desc - ,synchronization_health_desc - ,last_hardened_lsn - ,redo_queue_size - ,log_send_queue_size -FROM sys.dm_hadr_database_replica_states; -GO +USE master; +GO + +-- WSFC cluster node configuration: reports status of each member node of the cluster +SELECT member_name + ,member_type + ,member_type_desc + ,member_state + ,member_state_desc + ,number_of_quorum_votes +FROM sys.dm_hadr_cluster_members; +GO + +-- WSFC cluster network: contains one row for each network adapter in the cluster +SELECT member_name + ,network_subnet_ip + ,network_subnet_ipv4_mask + ,network_subnet_prefix_length + ,is_public + ,is_ipv4 +FROM sys.dm_hadr_cluster_networks; +GO + +-- Availability groups +-- reports current health statuses +SELECT primary_replica + ,primary_recovery_health_desc + ,synchronization_health_desc +FROM sys.dm_hadr_availability_group_states; +GO +-- reports metadata cached in SQL Server process space +SELECT group_id + ,name + ,resource_id + ,resource_group_id + ,failure_condition_level + ,health_check_timeout + ,automated_backup_preference + ,automated_backup_preference_desc +FROM sys.availability_groups; +GO +-- reports metadata stored in WSFC Cluster +SELECT group_id + ,name + ,resource_id + ,resource_group_id + ,failure_condition_level + ,health_check_timeout + ,automated_backup_preference + ,automated_backup_preference_desc +FROM sys.availability_groups_cluster; +GO + +-- Availability replicas +-- reports current health statuses +SELECT replica_id + ,role_desc + ,recovery_health_desc + ,synchronization_health_desc +FROM sys.dm_hadr_availability_replica_states; +GO +-- reports state information locally cached in SQL Server +SELECT replica_id + ,role_desc + ,connected_state_desc + ,synchronization_health_desc +FROM sys.dm_hadr_availability_replica_states; +GO +-- reports configuration data cached locally in SQL Server +SELECT replica_server_name + ,replica_id + ,availability_mode_desc + ,endpoint_url +FROM sys.availability_replicas; +GO +-- reports state information from WSFC cluster +SELECT replica_server_name + ,join_state_desc +FROM sys.dm_hadr_availability_replica_cluster_states; +GO + +-- Availability databases +-- reports current health statuses +SELECT dc.database_name + ,dr.database_id + ,dr.synchronization_state_desc + ,dr.suspend_reason_desc + ,dr.synchronization_health_desc +FROM sys.dm_hadr_database_replica_states dr + JOIN sys.availability_databases_cluster dc + ON dr.group_database_id = dc.group_database_id +WHERE dr.is_local = 1; +GO +-- reports configuration information from WSFC cluster +SELECT group_id + ,group_database_id + ,database_name +FROM sys.availability_databases_cluster; +GO +-- reports state information locally cached in SQL Server +SELECT group_database_id + ,database_name + ,is_failover_ready +FROM sys.dm_hadr_database_replica_cluster_states; +GO +-- reports identity and state information, such as LSN progress information for logs of primary and secondary replicas +SELECT database_id + ,synchronization_state_desc + ,synchronization_health_desc + ,last_hardened_lsn + ,redo_queue_size + ,log_send_queue_size +FROM sys.dm_hadr_database_replica_states; +GO diff --git a/server-config/alwayson-create-pause-and-resume-scripts.sql b/alwayson-pause-resume-synchronization.sql similarity index 98% rename from server-config/alwayson-create-pause-and-resume-scripts.sql rename to alwayson-pause-resume-synchronization.sql index e4ec90e..e51f93a 100644 --- a/server-config/alwayson-create-pause-and-resume-scripts.sql +++ b/alwayson-pause-resume-synchronization.sql @@ -1,30 +1,30 @@ -USE master; -GO - -/* -Suspend an Availability Database -https://docs.microsoft.com/en-us/sql/database-engine/availability-groups/windows/suspend-an-availability-database-sql-server - -The effect of a suspend command depends on whether you suspend a secondary database or a primary database, as follows: - -Secondary database: Only the local secondary database is suspended and its synchronization state becomes NOT SYNCHRONIZING. Other secondary databases - are not affected. The suspended database stops receiving and applying data (log records) and begins to fall behind the primary - database. Existing connections on the readable secondary remain usable. New connections to the suspended database on the readable - secondary are not allowed until data movement is resumed. - - The primary database remains available. If you suspend each of the corresponding secondary databases, the primary database runs exposed. - - ** Important ** While a secondary database is suspended, the send queue of the corresponding primary database will accumulate unsent - transaction log records. Connections to the secondary replica return data that was available at the time the data movement was suspended. - -Primary database: The primary database stops data movement to every connected secondary database. The primary database continues running, in an exposed - mode. The primary database remains available to clients, and existing connections on a readable secondary remain usable and new connections - can be made. -*/ - -SELECT database_name - ,'ALTER DATABASE ' + database_name + ' SET HADR SUSPEND;' AS PauseStmt - ,'ALTER DATABASE ' + database_name + ' SET HADR RESUME;' AS ResumeStmt -FROM sys.availability_databases_cluster; -GO - +USE master; +GO + +/* +Suspend an Availability Database +https://docs.microsoft.com/en-us/sql/database-engine/availability-groups/windows/suspend-an-availability-database-sql-server + +The effect of a suspend command depends on whether you suspend a secondary database or a primary database, as follows: + +Secondary database: Only the local secondary database is suspended and its synchronization state becomes NOT SYNCHRONIZING. Other secondary databases + are not affected. The suspended database stops receiving and applying data (log records) and begins to fall behind the primary + database. Existing connections on the readable secondary remain usable. New connections to the suspended database on the readable + secondary are not allowed until data movement is resumed. + + The primary database remains available. If you suspend each of the corresponding secondary databases, the primary database runs exposed. + + ** Important ** While a secondary database is suspended, the send queue of the corresponding primary database will accumulate unsent + transaction log records. Connections to the secondary replica return data that was available at the time the data movement was suspended. + +Primary database: The primary database stops data movement to every connected secondary database. The primary database continues running, in an exposed + mode. The primary database remains available to clients, and existing connections on a readable secondary remain usable and new connections + can be made. +*/ + +SELECT database_name + ,'ALTER DATABASE ' + database_name + ' SET HADR SUSPEND;' AS PauseStmt + ,'ALTER DATABASE ' + database_name + ' SET HADR RESUME;' AS ResumeStmt +FROM sys.availability_databases_cluster; +GO + diff --git a/alwayson-stop-restart-auto-seeding.sql b/alwayson-stop-restart-auto-seeding.sql new file mode 100644 index 0000000..68f2f87 --- /dev/null +++ b/alwayson-stop-restart-auto-seeding.sql @@ -0,0 +1,7 @@ +ALTER AVAILABILITY GROUP [AGName] +MODIFY REPLICA ON 'Replica_Name' WITH (SEEDING_MODE = MANUAL); +GO + +ALTER AVAILABILITY GROUP [AGName] +MODIFY REPLICA ON 'Replica_Name' WITH (SEEDING_MODE = AUTOMATIC); +GO diff --git a/alwayson-troubleshoot-hadr-endpoints.sql b/alwayson-troubleshoot-hadr-endpoints.sql new file mode 100644 index 0000000..0a535c3 --- /dev/null +++ b/alwayson-troubleshoot-hadr-endpoints.sql @@ -0,0 +1,22 @@ + +:Connect TargetReplica +SELECT e.name, e.principal_id, p.name as principal, e.protocol_desc, e.type_desc, e.state_desc + ,dm.role_desc, dm.connection_auth_desc, dm.encryption_algorithm_desc + ,t.port +FROM sys.endpoints e + LEFT JOIN sys.database_mirroring_endpoints dm ON e.endpoint_id = dm.endpoint_id + LEFT JOIN sys.tcp_endpoints t ON e.endpoint_id = t.endpoint_id + JOIN sys.server_principals p ON e.principal_id = p.principal_id; + + +:Connect TargetReplica +CREATE ENDPOINT [Hadr_endpoint] + STATE=STARTED AS TCP (LISTENER_PORT = 5022, LISTENER_IP = ALL) + FOR DATA_MIRRORING (ROLE = ALL, AUTHENTICATION = WINDOWS NEGOTIATE , ENCRYPTION = REQUIRED ALGORITHM AES) +GO +ALTER AUTHORIZATION ON ENDPOINT::Hadr_Endpoint TO SA +GO +GRANT CONNECT ON ENDPOINT::Hadr_endpoint TO [domain\SvcAcct]; +GO +--ALTER ENDPOINT Hadr_Endpoint STATE = STARTED +--GO diff --git a/alwayson-wait-stats.sql b/alwayson-wait-stats.sql new file mode 100644 index 0000000..ad1c3e2 --- /dev/null +++ b/alwayson-wait-stats.sql @@ -0,0 +1,4 @@ +SELECT * +FROM sys.dm_os_wait_stats +WHERE wait_type LIKE '%hadr%' +ORDER BY wait_time_ms DESC; \ No newline at end of file diff --git a/backup-get-bakfile-information.sql b/backup-get-bakfile-information.sql new file mode 100644 index 0000000000000000000000000000000000000000..21e6e4c50fdf817ea1302f0af53e46d91af592a0 GIT binary patch literal 1042 zcmb_b%Sr=55UjJ{Kg=x(M)WL#n->Xc7V?rnE_rNpG1-x167c8Ms?LVsl8X8+6_!YMH z9??ti2G89Tfp&#=#!M{xJkNfaf0uBBQ=Hf;qs*Kg-VWICR>lmDSW?A7G!{eED|F5-W7t1bsh;zOTw8*~B)yntV^oP9HU_^{ZdNn({rzf_> z3LQtjBHqMmA@ssJCMwm(@gyTEPfu^{jEQzZD;85$f5XZ-;}eX%=M6;_Bb0H=d{bK0 zugI=RW)bn%jm!TqJM`qhL-qGWt^Vvg^PS6*2xmkp4!>n1l~$}*F;)4uE)A>~si`Be z8Xw0k)j8JJW67RqA_CVzWm361s|xJqWs=un#yh*r89h}-vC^=5t{j>Rbxn#dc5Yxj pYf*(ms_>_59iFJ!9w%1w8>4R-V$;F}_cQ?!SC_stt%=_0_zPzCqCx-w literal 0 HcmV?d00001 diff --git a/server-info/backup-hist-avg-duration-and-size.sql b/backup-get-hist-avg-duration-and-size.sql similarity index 98% rename from server-info/backup-hist-avg-duration-and-size.sql rename to backup-get-hist-avg-duration-and-size.sql index 97c84ef..1483790 100644 --- a/server-info/backup-hist-avg-duration-and-size.sql +++ b/backup-get-hist-avg-duration-and-size.sql @@ -1,138 +1,138 @@ -SET NOCOUNT ON; - -/* --- CHECK ON/OFF STATUS OF TRACE FLAG 3226 -- --- SUPPRESSES BACKUP SUCCESS MESSAGES TO ERRORLOG AND SYSTEM EVENT LOG -- -DBCC TRACESTATUS (3226, -1) WITH NO_INFOMSGS; - --- ENABLE TRACE FLAG 3226 -DBCC TRACEON(3226,-1) - --- DISABLE TRACE FLAG 3226 -DBCC TRACEOFF (3226,-1) -*/ - -DECLARE @RunDate DATETIME = GETDATE(); - --- RETRIEVE BACKUP INFO -- -WITH BackupInfo (backup_start_date, backup_finish_date, backup_type, backup_size, database_name, has_backup_checksums - ,is_damaged, compressed_backup_size, logical_device_name, physical_device_name, device_type -) AS ( - SELECT bs.backup_start_date - ,bs.backup_finish_date - ,CASE bs.type - WHEN 'D' THEN 'Full backup' - WHEN 'I' THEN 'Differential' - WHEN 'L' THEN 'Log' - WHEN 'F' THEN 'File/Filegroup' - WHEN 'G' THEN 'Differential file' - WHEN 'P' THEN 'Partial' - WHEN 'Q' THEN 'Differential partial' - WHEN NULL THEN 'No backups' - ELSE 'Unknown (' + bs.type + ')' - END - ,bs.backup_size - ,bs.database_name - ,bs.has_backup_checksums - ,bs.is_damaged - ,bs.compressed_backup_size - ,bmf.logical_device_name - ,bmf.physical_device_name - ,CASE WHEN bmf.device_type IN (2, 102) THEN 'DISK' - WHEN bmf.device_type IN (5, 105) THEN 'TAPE' - END - FROM msdb..backupset bs - LEFT OUTER JOIN msdb..backupmediafamily bmf - ON bs.media_set_id = bmf.media_set_id -) - --- REPORT ON DATABASE / BACKUP INFO -- -SELECT d.database_id AS DatabaseId - ,d.name AS DatabaseName - ,CASE d.compatibility_level - WHEN 70 THEN '7' - WHEN 80 THEN '2000' - WHEN 90 THEN '2005' - WHEN 100 THEN '2008' - WHEN 110 THEN '2012' - WHEN NULL THEN 'OFFLINE' - END AS SQLVersion - ,d.recovery_model_desc AS RecoveryModel - ,d.state_desc AS DatabaseState - ,CASE d.state - WHEN 0 THEN 'N/A' - ELSE CASE d.is_cleanly_shutdown - WHEN 1 THEN 'NO RECOVERY' - WHEN 0 THEN 'RECOVERY' - END - END AS RecoveryState - ,mx.backup_last_30 AS BackupsLast30Days - ,bak.backup_start_date AS MostRecentBackup - ,bak.backup_type AS MostRecentType - ,SUM(CONVERT(INT, bak.compressed_backup_size / 1024 /*KB*/ / 1024 /*MB*/)) AS MostRecentSize_MB - ,AVG(CONVERT(NUMERIC(4, 1), (1 - (bak.compressed_backup_size * 1.0 / NULLIF(bak.backup_size, 0))) * 100)) AS CompressionRatio - ,SUM(CONVERT(INT, mx.backup_avg_size / 1024 /*KB*/ / 1024 /*MB*/)) AS Last30AvgSize_MB - ,DATEDIFF(SS, bak.backup_start_date, bak.backup_finish_date) AS MostRecentDuration_sec - ,mx.backup_avg_duration AS Last30AvgDuration_sec - ,bak.logical_device_name AS MostRecentLogicalDevice - ,CASE WHEN COUNT(bak.physical_device_name) > 1 THEN 'MULTIPLE' - ELSE MAX(bak.physical_device_name) - END AS MostRecentPhysicalDevice - ,bak.device_type AS MostRecentDeviceType - ,bak.has_backup_checksums AS UsedCHECKSUM - ,bak.is_damaged AS BackupDamaged - ,CASE WHEN d.recovery_model = 3 /*SIMPLE*/ THEN 0 - ELSE 1 - END AS LogBackupCheck -FROM sys.databases d - LEFT OUTER JOIN ( - SELECT DB_ID(BackupInfo.database_name) AS database_id - ,BackupInfo.backup_type - ,MAX(BackupInfo.backup_start_date) AS backup_start_date - ,SUM( CASE WHEN BackupInfo.backup_start_date BETWEEN DATEADD(DD, -30, @RunDate) AND @RunDate THEN - 1 - ELSE 0 - END - ) AS backup_last_30 - ,AVG(DATEDIFF(SS, BackupInfo.backup_start_date, BackupInfo.backup_finish_date)) AS backup_avg_duration - ,AVG(BackupInfo.compressed_backup_size) AS backup_avg_size - FROM BackupInfo - GROUP BY DB_ID(BackupInfo.database_name) - ,BackupInfo.backup_type - ) mx - ON d.database_id = mx.database_id - LEFT OUTER JOIN BackupInfo bak - ON mx.database_id = DB_ID(bak.database_name) - AND mx.backup_start_date = bak.backup_start_date -GROUP BY d.database_id - ,d.name - ,CASE d.compatibility_level - WHEN 70 THEN '7' - WHEN 80 THEN '2000' - WHEN 90 THEN '2005' - WHEN 100 THEN '2008' - WHEN 110 THEN '2012' - WHEN NULL THEN 'OFFLINE' - END - ,d.recovery_model_desc - ,d.state_desc - ,CASE d.state - WHEN 0 THEN 'N/A' - ELSE CASE d.is_cleanly_shutdown - WHEN 1 THEN 'NO RECOVERY' - WHEN 0 THEN 'RECOVERY' - END - END - ,mx.backup_last_30 - ,bak.backup_start_date - ,bak.backup_type - ,DATEDIFF(SS, bak.backup_start_date, bak.backup_finish_date) - ,mx.backup_avg_duration - ,bak.logical_device_name - ,bak.device_type - ,bak.has_backup_checksums - ,bak.is_damaged - ,CASE WHEN d.recovery_model = 3 /*SIMPLE*/ THEN 0 - ELSE 1 - END -ORDER BY d.name; +SET NOCOUNT ON; + +/* +-- CHECK ON/OFF STATUS OF TRACE FLAG 3226 -- +-- SUPPRESSES BACKUP SUCCESS MESSAGES TO ERRORLOG AND SYSTEM EVENT LOG -- +DBCC TRACESTATUS (3226, -1) WITH NO_INFOMSGS; + +-- ENABLE TRACE FLAG 3226 +DBCC TRACEON(3226,-1) + +-- DISABLE TRACE FLAG 3226 +DBCC TRACEOFF (3226,-1) +*/ + +DECLARE @RunDate DATETIME = GETDATE(); + +-- RETRIEVE BACKUP INFO -- +WITH BackupInfo (backup_start_date, backup_finish_date, backup_type, backup_size, database_name, has_backup_checksums + ,is_damaged, compressed_backup_size, logical_device_name, physical_device_name, device_type +) AS ( + SELECT bs.backup_start_date + ,bs.backup_finish_date + ,CASE bs.type + WHEN 'D' THEN 'Full backup' + WHEN 'I' THEN 'Differential' + WHEN 'L' THEN 'Log' + WHEN 'F' THEN 'File/Filegroup' + WHEN 'G' THEN 'Differential file' + WHEN 'P' THEN 'Partial' + WHEN 'Q' THEN 'Differential partial' + WHEN NULL THEN 'No backups' + ELSE 'Unknown (' + bs.type + ')' + END + ,bs.backup_size + ,bs.database_name + ,bs.has_backup_checksums + ,bs.is_damaged + ,bs.compressed_backup_size + ,bmf.logical_device_name + ,bmf.physical_device_name + ,CASE WHEN bmf.device_type IN (2, 102) THEN 'DISK' + WHEN bmf.device_type IN (5, 105) THEN 'TAPE' + END + FROM msdb..backupset bs + LEFT OUTER JOIN msdb..backupmediafamily bmf + ON bs.media_set_id = bmf.media_set_id +) + +-- REPORT ON DATABASE / BACKUP INFO -- +SELECT d.database_id AS DatabaseId + ,d.name AS DatabaseName + ,CASE d.compatibility_level + WHEN 70 THEN '7' + WHEN 80 THEN '2000' + WHEN 90 THEN '2005' + WHEN 100 THEN '2008' + WHEN 110 THEN '2012' + WHEN NULL THEN 'OFFLINE' + END AS SQLVersion + ,d.recovery_model_desc AS RecoveryModel + ,d.state_desc AS DatabaseState + ,CASE d.state + WHEN 0 THEN 'N/A' + ELSE CASE d.is_cleanly_shutdown + WHEN 1 THEN 'NO RECOVERY' + WHEN 0 THEN 'RECOVERY' + END + END AS RecoveryState + ,mx.backup_last_30 AS BackupsLast30Days + ,bak.backup_start_date AS MostRecentBackup + ,bak.backup_type AS MostRecentType + ,SUM(CONVERT(INT, bak.compressed_backup_size / 1024 /*KB*/ / 1024 /*MB*/)) AS MostRecentSize_MB + ,AVG(CONVERT(NUMERIC(4, 1), (1 - (bak.compressed_backup_size * 1.0 / NULLIF(bak.backup_size, 0))) * 100)) AS CompressionRatio + ,SUM(CONVERT(INT, mx.backup_avg_size / 1024 /*KB*/ / 1024 /*MB*/)) AS Last30AvgSize_MB + ,DATEDIFF(SS, bak.backup_start_date, bak.backup_finish_date) AS MostRecentDuration_sec + ,mx.backup_avg_duration AS Last30AvgDuration_sec + ,bak.logical_device_name AS MostRecentLogicalDevice + ,CASE WHEN COUNT(bak.physical_device_name) > 1 THEN 'MULTIPLE' + ELSE MAX(bak.physical_device_name) + END AS MostRecentPhysicalDevice + ,bak.device_type AS MostRecentDeviceType + ,bak.has_backup_checksums AS UsedCHECKSUM + ,bak.is_damaged AS BackupDamaged + ,CASE WHEN d.recovery_model = 3 /*SIMPLE*/ THEN 0 + ELSE 1 + END AS LogBackupCheck +FROM sys.databases d + LEFT OUTER JOIN ( + SELECT DB_ID(BackupInfo.database_name) AS database_id + ,BackupInfo.backup_type + ,MAX(BackupInfo.backup_start_date) AS backup_start_date + ,SUM( CASE WHEN BackupInfo.backup_start_date BETWEEN DATEADD(DD, -30, @RunDate) AND @RunDate THEN + 1 + ELSE 0 + END + ) AS backup_last_30 + ,AVG(DATEDIFF(SS, BackupInfo.backup_start_date, BackupInfo.backup_finish_date)) AS backup_avg_duration + ,AVG(BackupInfo.compressed_backup_size) AS backup_avg_size + FROM BackupInfo + GROUP BY DB_ID(BackupInfo.database_name) + ,BackupInfo.backup_type + ) mx + ON d.database_id = mx.database_id + LEFT OUTER JOIN BackupInfo bak + ON mx.database_id = DB_ID(bak.database_name) + AND mx.backup_start_date = bak.backup_start_date +GROUP BY d.database_id + ,d.name + ,CASE d.compatibility_level + WHEN 70 THEN '7' + WHEN 80 THEN '2000' + WHEN 90 THEN '2005' + WHEN 100 THEN '2008' + WHEN 110 THEN '2012' + WHEN NULL THEN 'OFFLINE' + END + ,d.recovery_model_desc + ,d.state_desc + ,CASE d.state + WHEN 0 THEN 'N/A' + ELSE CASE d.is_cleanly_shutdown + WHEN 1 THEN 'NO RECOVERY' + WHEN 0 THEN 'RECOVERY' + END + END + ,mx.backup_last_30 + ,bak.backup_start_date + ,bak.backup_type + ,DATEDIFF(SS, bak.backup_start_date, bak.backup_finish_date) + ,mx.backup_avg_duration + ,bak.logical_device_name + ,bak.device_type + ,bak.has_backup_checksums + ,bak.is_damaged + ,CASE WHEN d.recovery_model = 3 /*SIMPLE*/ THEN 0 + ELSE 1 + END +ORDER BY d.name; diff --git a/backup-get-history.sql b/backup-get-history.sql new file mode 100644 index 0000000..f595f89 --- /dev/null +++ b/backup-get-history.sql @@ -0,0 +1,51 @@ + +DECLARE @ClusterName VARCHAR(128); + +SELECT @ClusterName = cluster_name +FROM master.sys.dm_hadr_cluster +WHERE LEFT(cluster_name, 1) LIKE '[a-z]'; + +WITH BakOrder AS ( + SELECT database_name + ,type + ,backup_start_date + ,DENSE_RANK() OVER (PARTITION BY database_name, type ORDER BY backup_start_date DESC) AS BakOrder + FROM msdb.dbo.backupset + WHERE backup_finish_date IS NOT NULL +) +SELECT @ClusterName AS clustername + ,@@SERVERNAME AS servername + ,DEFAULT_DOMAIN() as domain + ,d.name as dbname + ,bs.backup_set_uuid + ,bs.position + ,bs.expiration_date + ,bs.name + ,bs.description + ,bs.user_name + ,bs.first_lsn + ,bs.last_lsn + ,bs.backup_start_date + ,bs.backup_finish_date + ,bs.type + ,bs.backup_size + ,bs.compatibility_level + ,bs.is_password_protected + ,bs.recovery_model + ,bs.has_bulk_logged_data + ,bs.is_snapshot + ,bs.is_readonly + ,bs.is_single_user + ,bs.has_backup_checksums + ,bs.is_damaged + ,bs.is_copy_only + ,bs.compressed_backup_size + ,bmf.family_sequence_number + ,bmf.logical_device_name + ,bmf.physical_device_name + ,bmf.device_type +FROM master.sys.databases d + LEFT OUTER JOIN BakOrder o ON o.database_name = d.name and o.BakOrder = 1 + LEFT OUTER JOIN msdb.dbo.backupset bs ON bs.database_name = o.database_name AND bs.type = o.type AND bs.backup_start_date = o.backup_start_date + LEFT OUTER JOIN msdb.dbo.backupmediafamily bmf ON bs.media_set_id = bmf.media_set_id +WHERE d.name <> 'tempdb'; diff --git a/server-info/backup-most-recent-duration-and-size.sql b/backup-get-most-recent-duration-and-size.sql similarity index 98% rename from server-info/backup-most-recent-duration-and-size.sql rename to backup-get-most-recent-duration-and-size.sql index 8d3af13..ed345ee 100644 --- a/server-info/backup-most-recent-duration-and-size.sql +++ b/backup-get-most-recent-duration-and-size.sql @@ -1,45 +1,45 @@ - -SELECT bak.database_name - , COALESCE(CASE WHEN SUM(bak.BakOrder) > 1 THEN 'FULL+DIFF'END - ,MAX(CASE WHEN bak.backup_type <> 'No backups' THEN 'FULL' END)) AS backup_type - , MAX(CASE WHEN bak.backup_type <> 'No backups' AND bak.CompressionRatio < 100.0 THEN 1 - WHEN bak.backup_type <> 'No backups' THEN 0 - END) AS UsedCompression - , MAX(bak.has_backup_checksums) AS UsedChecksum - , MAX(CASE WHEN bak.backup_type = 'Full backup' OR bak.backup_type = 'Partial' THEN bak.backup_start_date END) AS MostRecentFull_Date - , MAX(CASE WHEN bak.backup_type = 'Full backup' OR bak.backup_type = 'Partial' THEN DATEDIFF(SECOND,bak.backup_start_date,bak.backup_finish_date) END) AS MostRecentFull_Sec - , SUM(CASE WHEN bak.backup_type = 'Full backup' OR bak.backup_type = 'Partial' THEN bak.MostRecentSize_MB END) AS MostRecentFull_MB - , MAX(CASE WHEN bak.backup_type <> 'Full backup' AND bak.backup_type <> 'Partial' THEN bak.backup_type END) AS MostRecentOther - , MAX(CASE WHEN bak.backup_type <> 'Full backup' AND bak.backup_type <> 'Partial' THEN bak.backup_start_date END) AS MostRecentOther_Date - , MAX(CASE WHEN bak.backup_type <> 'Full backup' AND bak.backup_type <> 'Partial' THEN DATEDIFF(SECOND,bak.backup_start_date,bak.backup_finish_date) END) AS MostRecentOther_Sec - , SUM(CASE WHEN bak.backup_type <> 'Full backup' AND bak.backup_type <> 'Partial' THEN bak.MostRecentSize_MB END) AS MostRecentOther_MB -FROM ( - SELECT d.name AS database_name - , CASE bs.type - WHEN 'D' THEN 'Full backup' - WHEN 'I' THEN 'Differential' - WHEN 'L' THEN 'Log' - WHEN 'F' THEN 'File/Filegroup' - WHEN 'G' THEN 'Differential file' - WHEN 'P' THEN 'Partial' - WHEN 'Q' THEN 'Differential partial' - WHEN NULL THEN 'No backups' - ELSE 'Unknown (' + bs.[type] + ')' - END AS backup_type - , (CONVERT(INT, bs.compressed_backup_size / 1024 /*KB*/ / 1024 /*MB*/)) AS [MostRecentSize_MB] - , bmf.physical_device_name - , CASE WHEN bmf.device_type IN (2, 102) THEN 'DISK' - WHEN bmf.device_type IN (5, 105) THEN 'TAPE' - END AS device_type - , DENSE_RANK() OVER (PARTITION BY bs.database_name, bs.type ORDER BY bs.backup_start_date DESC) AS BakOrder - ,bs.backup_start_date - ,bs.backup_finish_date - ,CONVERT(NUMERIC(4,1), (1 - (bs.compressed_backup_size * 1.0 / NULLIF(bs.backup_size, 0))) * 100) AS CompressionRatio - ,CAST(bs.has_backup_checksums AS TINYINT) AS has_backup_checksums - FROM master.sys.databases d - LEFT OUTER JOIN msdb.dbo.backupset bs ON bs.database_name = d.name - LEFT OUTER JOIN msdb.dbo.backupmediafamily bmf ON bs.media_set_id = bmf.media_set_id - ) bak -WHERE bak.BakOrder = 1 -GROUP BY bak.database_name -ORDER BY bak.database_name; + +SELECT bak.database_name + , COALESCE(CASE WHEN SUM(bak.BakOrder) > 1 THEN 'FULL+DIFF'END + ,MAX(CASE WHEN bak.backup_type <> 'No backups' THEN 'FULL' END)) AS backup_type + , MAX(CASE WHEN bak.backup_type <> 'No backups' AND bak.CompressionRatio < 100.0 THEN 1 + WHEN bak.backup_type <> 'No backups' THEN 0 + END) AS UsedCompression + , MAX(bak.has_backup_checksums) AS UsedChecksum + , MAX(CASE WHEN bak.backup_type = 'Full backup' OR bak.backup_type = 'Partial' THEN bak.backup_start_date END) AS MostRecentFull_Date + , MAX(CASE WHEN bak.backup_type = 'Full backup' OR bak.backup_type = 'Partial' THEN DATEDIFF(SECOND,bak.backup_start_date,bak.backup_finish_date) END) AS MostRecentFull_Sec + , SUM(CASE WHEN bak.backup_type = 'Full backup' OR bak.backup_type = 'Partial' THEN bak.MostRecentSize_MB END) AS MostRecentFull_MB + , MAX(CASE WHEN bak.backup_type <> 'Full backup' AND bak.backup_type <> 'Partial' THEN bak.backup_type END) AS MostRecentOther + , MAX(CASE WHEN bak.backup_type <> 'Full backup' AND bak.backup_type <> 'Partial' THEN bak.backup_start_date END) AS MostRecentOther_Date + , MAX(CASE WHEN bak.backup_type <> 'Full backup' AND bak.backup_type <> 'Partial' THEN DATEDIFF(SECOND,bak.backup_start_date,bak.backup_finish_date) END) AS MostRecentOther_Sec + , SUM(CASE WHEN bak.backup_type <> 'Full backup' AND bak.backup_type <> 'Partial' THEN bak.MostRecentSize_MB END) AS MostRecentOther_MB +FROM ( + SELECT d.name AS database_name + , CASE bs.type + WHEN 'D' THEN 'Full backup' + WHEN 'I' THEN 'Differential' + WHEN 'L' THEN 'Log' + WHEN 'F' THEN 'File/Filegroup' + WHEN 'G' THEN 'Differential file' + WHEN 'P' THEN 'Partial' + WHEN 'Q' THEN 'Differential partial' + WHEN NULL THEN 'No backups' + ELSE 'Unknown (' + bs.[type] + ')' + END AS backup_type + , (CONVERT(INT, bs.compressed_backup_size / 1024 /*KB*/ / 1024 /*MB*/)) AS [MostRecentSize_MB] + , bmf.physical_device_name + , CASE WHEN bmf.device_type IN (2, 102) THEN 'DISK' + WHEN bmf.device_type IN (5, 105) THEN 'TAPE' + END AS device_type + , DENSE_RANK() OVER (PARTITION BY bs.database_name, bs.type ORDER BY bs.backup_start_date DESC) AS BakOrder + ,bs.backup_start_date + ,bs.backup_finish_date + ,CONVERT(NUMERIC(4,1), (1 - (bs.compressed_backup_size * 1.0 / NULLIF(bs.backup_size, 0))) * 100) AS CompressionRatio + ,CAST(bs.has_backup_checksums AS TINYINT) AS has_backup_checksums + FROM master.sys.databases d + LEFT OUTER JOIN msdb.dbo.backupset bs ON bs.database_name = d.name + LEFT OUTER JOIN msdb.dbo.backupmediafamily bmf ON bs.media_set_id = bmf.media_set_id + ) bak +WHERE bak.BakOrder = 1 +GROUP BY bak.database_name +ORDER BY bak.database_name; diff --git a/backup-get-size-and-compression-ratio.sql b/backup-get-size-and-compression-ratio.sql new file mode 100644 index 0000000..0104eda --- /dev/null +++ b/backup-get-size-and-compression-ratio.sql @@ -0,0 +1,17 @@ +WITH MaxDate AS ( + SELECT database_name + , MAX(backup_finish_date) AS backup_finish_date + FROM msdb..backupset + GROUP BY database_name +) + +SELECT b.database_name + , b.backup_size/1024/1024/1024 AS backup_size_GB + , b.compressed_backup_size/1024/1024/1024 AS compressed_backup_size_GB + , b.backup_size/b.compressed_backup_size AS CompressedRatio +FROM msdb..backupset b + JOIN MaxDate d ON b.database_name = d.database_name and b.backup_finish_date = d.backup_finish_date +ORDER BY 1; + +--SELECT AVG(backup_size/compressed_backup_size) AS AvgCompressedRatio +--FROM msdb..backupset; diff --git a/backup-log-truncate-only-or-null.sql b/backup-log-truncate-only-or-null.sql new file mode 100644 index 0000000..3474a7e --- /dev/null +++ b/backup-log-truncate-only-or-null.sql @@ -0,0 +1 @@ +BACKUP LOG [dbname] TO DISK='NUL:'; \ No newline at end of file diff --git a/backup-restore-build-script.sql b/backup-restore-build-script.sql new file mode 100644 index 0000000..e388f26 --- /dev/null +++ b/backup-restore-build-script.sql @@ -0,0 +1,82 @@ +DECLARE @database VARCHAR(128) = 'DBName' + ,@DRDataCenter VARCHAR(100) = 'DRDataCenter' + ,@DRRepository VARCHAR(100) = 'DRRepoName'; + +;WITH Baks AS ( + SELECT bs.database_name + ,bs.type + ,bs.media_set_id + ,bs.backup_start_date + ,bmf.physical_device_name + ,SUBSTRING(bmf.physical_device_name,3,CHARINDEX('\',bmf.physical_device_name,3)-3) AS PrimaryDataCenter + ,SUBSTRING(bmf.physical_device_name,CHARINDEX('\',bmf.physical_device_name,3)+1,CHARINDEX('\',bmf.physical_device_name,3)) AS PrimaryRepository + ,ISNULL(@DRDataCenter,SUBSTRING(bmf.physical_device_name,3,CHARINDEX('\',bmf.physical_device_name,3)-3)) AS DRDataCenter + ,ISNULL(@DRRepository,SUBSTRING(bmf.physical_device_name,CHARINDEX('\',bmf.physical_device_name,3)+1,CHARINDEX('\',bmf.physical_device_name,3)-2)) AS DRRepository + FROM msdb.dbo.backupset bs + JOIN msdb.dbo.backupmediafamily bmf ON bs.media_set_id = bmf.media_set_id + WHERE bs.type IN ('D', 'L') -- 'Full backup', 'Log' + AND (bs.database_name = @database OR @database IS NULL) +) +,LatestFull AS ( + SELECT database_name, MAX(backup_start_date) as backup_start_date + FROM Baks + WHERE type = 'D' + GROUP BY database_name +) +,LatestLogs AS ( + SELECT b.database_name + ,b.media_set_id + ,DENSE_RANK() OVER (PARTITION BY b.database_name ORDER BY b.backup_start_date) AS BakOrder + FROM Baks b + JOIN LatestFull f + ON b.database_name = f.database_name + AND b.backup_start_date > f.backup_start_date + WHERE b.type = 'L' +) +SELECT b.database_name + ,'RESTORE DATABASE ' + b.database_name + ' FROM ' + + STUFF(( + SELECT ',' + 'DISK = N''' + bmf.physical_device_name + '''' + FROM Baks bmf + WHERE b.media_set_id = bmf.media_set_id + FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') + + ' WITH NORECOVERY, STATS = 10;' AS PrimaryDataCenterRestore + ,'RESTORE DATABASE ' + b.database_name + ' FROM ' + + STUFF(( + SELECT ',' + 'DISK = N''' + REPLACE(REPLACE(bmf.physical_device_name,bmf.PrimaryDataCenter,DRDataCenter),bmf.PrimaryRepository,DRRepository) + '''' + FROM Baks bmf + WHERE b.media_set_id = bmf.media_set_id + FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') + + ' WITH NORECOVERY, STATS = 10;' AS DRDataCenterRestore + ,0 AS BakOrder +FROM Baks b + JOIN LatestFull f + ON b.database_name = f.database_name + and b.backup_start_date = f.backup_start_date +UNION ALL +SELECT l.database_name + ,'RESTORE LOG ' + l.database_name + ' FROM ' + + STUFF(( + SELECT ',' + 'DISK = N''' + bmf.physical_device_name + '''' + FROM Baks bmf + WHERE l.media_set_id = bmf.media_set_id + FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') + + ' WITH NORECOVERY;' + ,'RESTORE LOG ' + l.database_name + ' FROM ' + + STUFF(( + SELECT ',' + 'DISK = N''' + REPLACE(REPLACE(bmf.physical_device_name,bmf.PrimaryDataCenter,DRDataCenter),bmf.PrimaryRepository,DRRepository) + '''' + FROM Baks bmf + WHERE l.media_set_id = bmf.media_set_id + FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') + + ' WITH NORECOVERY;' + ,l.BakOrder +FROM LatestLogs l +UNION +SELECT database_name + ,'--RESTORE DATABASE ' + database_name + ' WITH RECOVERY;' + ,CONVERT(VARCHAR(50),backup_start_date,100) + ,10000 AS BakOrder +FROM LatestFull +ORDER BY 1,4 + + diff --git a/backup-restore-get-estimated-completion.sql b/backup-restore-get-estimated-completion.sql new file mode 100644 index 0000000..8337270 --- /dev/null +++ b/backup-restore-get-estimated-completion.sql @@ -0,0 +1,3 @@ +SELECT session_id as SPID, command, a.text AS Query, start_time, percent_complete, dateadd(second,estimated_completion_time/1000, getdate()) as estimated_completion_time +FROM sys.dm_exec_requests r CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) a +WHERE r.command in ('BACKUP DATABASE','RESTORE DATABASE') \ No newline at end of file diff --git a/database-config/backup-restore-db-backup.sql b/backup-restore-helper-script.sql similarity index 95% rename from database-config/backup-restore-db-backup.sql rename to backup-restore-helper-script.sql index 7ddaca9..99b2ac0 100644 --- a/database-config/backup-restore-db-backup.sql +++ b/backup-restore-helper-script.sql @@ -1,39 +1,39 @@ --- Set database context to DB to be restored -USE [DB Name]; -GO - -DECLARE @BakFile NVARCHAR(MAX) = N''; - --- Get file list from backup -RESTORE FILELISTONLY FROM DISK = @BakFile; -GO - --- Return database file locations -EXEC sys.sp_helpfile; -GO - --- Set database context to master -USE master; -GO - --- Take tail log back up -BACKUP LOG [DB Name] -TO DISK = N'' -WITH NOFORMAT - ,NOINIT - ,NOSKIP - ,NOREWIND - ,NOUNLOAD - ,STATS = 10; - --- Restore the database -RESTORE DATABASE [DB Name] -FROM DISK = N'' -WITH RECOVERY -- roll back uncommitted transactions - -- NORECOVERY -- use for multi-step restore sequence until desired recovery point is reached, does not roll back uncommitted transactions - ,REPLACE - ,MOVE '' TO '' - ,MOVE '' TO '' - ,STATS = 10; -GO - +-- Set database context to DB to be restored +USE [DB Name]; +GO + +DECLARE @BakFile NVARCHAR(MAX) = N''; + +-- Get file list from backup +RESTORE FILELISTONLY FROM DISK = @BakFile; +GO + +-- Return database file locations +EXEC sys.sp_helpfile; +GO + +-- Set database context to master +USE master; +GO + +-- Take tail log back up +BACKUP LOG [DB Name] +TO DISK = N'' +WITH NOFORMAT + ,NOINIT + ,NOSKIP + ,NOREWIND + ,NOUNLOAD + ,STATS = 10; + +-- Restore the database +RESTORE DATABASE [DB Name] +FROM DISK = N'' +WITH RECOVERY -- roll back uncommitted transactions + -- NORECOVERY -- use for multi-step restore sequence until desired recovery point is reached, does not roll back uncommitted transactions + ,REPLACE + ,MOVE '' TO '' + ,MOVE '' TO '' + ,STATS = 10; +GO + diff --git a/backup-restore-service-master-key.sql b/backup-restore-service-master-key.sql new file mode 100644 index 0000000..93a1ccb --- /dev/null +++ b/backup-restore-service-master-key.sql @@ -0,0 +1,9 @@ +-- BACKUP SERVICE MASTER KEY +BACKUP SERVICE MASTER KEY TO FILE = 'path_to_file' +ENCRYPTION BY PASSWORD = 'password' + +-- RESTORE SERVICE MASTER KEY +RESTORE SERVICE MASTER KEY +FROM FILE = 'c:\temp_backups\keys\service_master_key' +DECRYPTION BY PASSWORD = '3dH85Hhk003GHk2597gheij4'; +GO \ No newline at end of file diff --git a/database-config/backup-verify-backup-file.sql b/backup-verify-backup-file.sql similarity index 100% rename from database-config/backup-verify-backup-file.sql rename to backup-verify-backup-file.sql diff --git a/cms-get-servers-and-groups.sql b/cms-get-servers-and-groups.sql new file mode 100644 index 0000000..a39bd77 --- /dev/null +++ b/cms-get-servers-and-groups.sql @@ -0,0 +1,10 @@ +/* Servers and groups */ +SELECT DISTINCT + groups.name AS 'Server Group Name' + ,svr.server_name AS 'Server Name' +FROM msdb.dbo.sysmanagement_shared_server_groups_internal groups + INNER JOIN msdb.dbo.sysmanagement_shared_registered_servers_internal svr + ON groups.server_group_id = svr.server_group_id +ORDER BY groups.name + ,svr.server_name +GO diff --git a/database-config/ddl-add-column-description.sql b/database-add-object-metadata.sql similarity index 100% rename from database-config/ddl-add-column-description.sql rename to database-add-object-metadata.sql diff --git a/database-attach-files.sql b/database-attach-files.sql new file mode 100644 index 0000000..53a6513 --- /dev/null +++ b/database-attach-files.sql @@ -0,0 +1,11 @@ +USE master; +GO + +EXEC sys.sp_attach_db @dbname = 'DBName' + ,@filename1 = N'H:\SQL\Data\DBName.mdf' + ,@filename2 = N'I:\SQL\Log\DBName_log.ldf' + ,@filename3 = N'H:\SQL\Data\DBName_2.ndf' + ,@filename4 = N'G:\SQL\Data\DBName_indexes.ndf' +GO +ALTER AUTHORIZATION ON DATABASE::[DBName] TO [sa]; +GO diff --git a/server-config/detach-and-attach-db-files.sql b/database-detach-attach-files.sql similarity index 56% rename from server-config/detach-and-attach-db-files.sql rename to database-detach-attach-files.sql index fe69ec9..fb05172 100644 --- a/server-config/detach-and-attach-db-files.sql +++ b/database-detach-attach-files.sql @@ -1,71 +1,92 @@ -USE master; -GO - --- create detach statements -SELECT 'ALTER DATABASE ' + name + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE; EXEC sys.sp_detach_db ''' + name + ''', ''true'';' AS DetachScript -FROM sys.databases -WHERE name NOT IN ('master', 'model', 'msdb', 'tempdb', 'Resource', 'distribution', 'reportserver' - ,'reportservertempdb' - ); - --- create attach statements -DECLARE @tmp_AttachScript TABLE ( - DBName sysname - ,AttachScript VARCHAR(MAX) - ,Processed BIT DEFAULT 0 -); - -INSERT @tmp_AttachScript (DBName, AttachScript) -SELECT name AS DBName - ,'EXEC sys.sp_attach_db @dbname = ''' + name + '''' -FROM sys.databases -WHERE name NOT IN ('master', 'model', 'msdb', 'tempdb', 'Resource', 'distribution', 'reportserver' - ,'reportservertempdb' - ); - -DECLARE @sql NVARCHAR(MAX) - ,@DBName sysname; - -DECLARE @tmp_DBFiles TABLE ( - data_space_id INT - ,physical_name NVARCHAR(260) -); - -WHILE EXISTS (SELECT 1 FROM @tmp_AttachScript WHERE Processed = 0) -BEGIN - SELECT @DBName = DBName - FROM @tmp_AttachScript - WHERE Processed = 0; - - DELETE - FROM @tmp_DBFiles; - - SET @sql = N'SELECT data_space_id, physical_name FROM ' + @DBName + '.sys.database_files;' - - INSERT @tmp_DBFiles (data_space_id, physical_name) - EXEC sys.sp_executesql @sql; - - UPDATE upd - SET upd.AttachScript = upd.AttachScript + f.filelist + ';' - FROM @tmp_AttachScript upd - INNER JOIN ( - SELECT src.DBName - ,STUFF(( - SELECT ',@filename' + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT 100)) AS VARCHAR(10)) + ' = N''' + physical_name + '''' - FROM @tmp_DBFiles tbl - FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,0,'') AS filelist - FROM ( - SELECT * - FROM @tmp_AttachScript - WHERE DBName = @DBName - ) src - ) f ON upd.DBName = f.DBName; - - UPDATE @tmp_AttachScript - SET Processed = 1 - WHERE DBName = @DBName; -END; - -SELECT AttachScript -FROM @tmp_AttachScript; - +USE master; +GO +SET NOCOUNT ON; +GO + +DECLARE @OverrideDB sysname = 'DBName' -- leave NULL if you want to create scripts for ALL user databases + ,@ServerName sysname + ,@RebuildLogFile bit = 1; -- change to 1 to rebuild the log file + +-- create attach statements +DECLARE @tmp_AttachScript TABLE ( + DBName sysname + ,AttachScript VARCHAR(MAX) + ,Processed BIT DEFAULT 0 +); + +INSERT @tmp_AttachScript (DBName, AttachScript) +SELECT name AS DBName + ,'CREATE DATABASE ' + name + ' ON ' +FROM sys.databases +WHERE name NOT IN ('master', 'model', 'msdb', 'tempdb', 'Resource', 'distribution', 'reportserver' + ,'reportservertempdb') +AND (@OverrideDB IS NULL OR name = @OverrideDB); + +DECLARE @sql NVARCHAR(MAX) + ,@DBName sysname; + +DECLARE @tmp_DBFiles TABLE ( + data_space_id INT + ,physical_name NVARCHAR(260) +); + +WHILE EXISTS (SELECT 1 FROM @tmp_AttachScript WHERE Processed = 0) +BEGIN + SELECT @DBName = DBName + FROM @tmp_AttachScript + WHERE Processed = 0; + + DELETE + FROM @tmp_DBFiles; + + SET @sql = N'SELECT data_space_id, physical_name FROM ' + @DBName + '.sys.database_files;' + + INSERT @tmp_DBFiles (data_space_id, physical_name) + EXEC sys.sp_executesql @sql; + + UPDATE upd + SET upd.AttachScript = upd.AttachScript + f.filelist + FROM @tmp_AttachScript upd + INNER JOIN ( + SELECT src.DBName + ,STUFF(( + SELECT ',( filename' + ' = N''' + physical_name + ''' )' + FROM @tmp_DBFiles tbl + FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') AS filelist + FROM ( + SELECT * + FROM @tmp_AttachScript + WHERE DBName = @DBName + ) src + ) f ON upd.DBName = f.DBName; + + IF @RebuildLogFile = 1 + UPDATE @tmp_AttachScript + SET AttachScript += ' FOR ATTACH_REBUILD_LOG' + WHERE DBName = @DBName; + + UPDATE @tmp_AttachScript + SET AttachScript += '; + GO + ALTER AUTHORIZATION ON DATABASE::[' + @DBName + '] TO [sa]; + ALTER DATABASE ' + @DBName + ' SET TRUSTWORTHY ON; + GO' + ,Processed = 1 + WHERE DBName = @DBName; +END; + +-- create detach statements +SELECT 'ALTER DATABASE ' + name + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE; EXEC sys.sp_detach_db ''' + name + ''', ''true''; + GO' AS DetachScript + ,name AS DBName +FROM sys.databases +WHERE name NOT IN ('master', 'model', 'msdb', 'tempdb', 'Resource', 'distribution', 'reportserver' + ,'reportservertempdb') +AND (@OverrideDB IS NULL OR name = @OverrideDB) +UNION ALL +SELECT AttachScript + ,DBName +FROM @tmp_AttachScript +ORDER BY 2, 1; + + diff --git a/database-info/views-detangle-nested.sql b/database-detangle-nested-views.sql similarity index 94% rename from database-info/views-detangle-nested.sql rename to database-detangle-nested-views.sql index c7a564a..b9b655f 100644 --- a/database-info/views-detangle-nested.sql +++ b/database-detangle-nested-views.sql @@ -1,93 +1,92 @@ ----------------------------------------------------------------------------- --- Create temp table, variables ----------------------------------------------------------------------------- --- Create a temp table to hold the view/table hierarchy -CREATE TABLE #viewHierarchy -( id INT IDENTITY(1,1) -, parent_view_id INT -, referenced_schema_name NVARCHAR(255) -, referenced_entity_name NVARCHAR(255) -, join_clause NVARCHAR(MAX) -, [LEVEL] TINYINT -, lineage NVARCHAR(MAX) -); -DECLARE @count INT -- Current ID -, @viewname NVARCHAR(1000); --- Set the name of the top level view you want to detangle -SET @viewName = N'' -SET @count = 1; ----------------------------------------------------------------------------- --- Seed the table with the root view, and the root view's referenced tables. ----------------------------------------------------------------------------- -INSERT INTO #viewHierarchy -SELECT NULL parent_view_id -, 'dbo' referenced_schema_name -, @viewName referenced_entity_name -, NULL join_clause -, 0 [LEVEL] -, '/' lineage; -INSERT INTO #viewHierarchy -SELECT DISTINCT @count parent_view_id -, referenced_schema_name -, referenced_entity_name -, '' join_clause -, 1 [LEVEL] -, '/1/' lineage -FROM sys.dm_sql_referenced_entities(@viewName,'OBJECT'); -GO ----------------------------------------------------------------------------- --- Loop through the nested views. ----------------------------------------------------------------------------- -DECLARE @count INT -- Current ID -, @maxCount INT -- Max ID of the temp table -, @viewname NVARCHAR(1000) -SET @count = 1; -SELECT @maxCount = MAX(id) -FROM #viewHierarchy; -WHILE (@count < @maxCount) -- While there are still rows to process... -BEGIN -SET @count = @count + 1; - -- Get the name of the current view (that we'd like references for) -SELECT @viewName = referenced_entity_name -FROM #viewHierarchy -WHERE id = @count; - -- If it's a view (not a table), insert referenced objects into temp table. -IF (EXISTS (SELECT name FROM sys.objects WHERE name = @viewName AND TYPE = 'v') -OR EXISTS (SELECT name FROM sys.objects WHERE name = @viewName AND TYPE = 'TF') -OR EXISTS (SELECT name FROM sys.objects WHERE name = @viewName AND TYPE = 'FN')) -AND @viewName NOT IN ('Geography','Geography_to_Company','StatisticalArea','StatisticalArea_to_Company') -BEGIN -SET @viewName = N'dbo.' + @viewName; -INSERT INTO #viewHierarchy -SELECT DISTINCT @count parent_view_id -, referenced_schema_name -, referenced_entity_name -, '' join_clause -, NULL [LEVEL] -, '' lineage -FROM sys.dm_sql_referenced_entities(@viewName,'OBJECT'); -SELECT @maxCount = MAX(id) -FROM #viewHierarchy; -END -END --------------------------------------- --------------------------------------- -WHILE EXISTS (SELECT 1 FROM #viewHierarchy WHERE [LEVEL] IS NULL) -UPDATE T -SET T.[Level] = P.[Level] + 1, -T.Lineage = P.Lineage + LTRIM(STR(T.parent_view_id,6,0)) + '/' -FROM #viewHierarchy AS T -INNER JOIN #viewHierarchy AS P ON (T.parent_view_id=P.ID) -WHERE P.[Level]>=0 -AND P.Lineage IS NOT NULL -AND T.[Level] IS NULL -SELECT parent.* -,child.id -,child.referenced_entity_name ChildName -FROM #viewHierarchy parent -RIGHT OUTER JOIN #viewHierarchy child ON child.parent_view_id = parent.id -ORDER BY parent.id, child.id - ---SELECT * FROM #viewHierarchy - +---------------------------------------------------------------------------- +-- Create temp table, variables +---------------------------------------------------------------------------- +-- Create a temp table to hold the view/table hierarchy +CREATE TABLE #viewHierarchy +( id INT IDENTITY(1,1) +, parent_view_id INT +, referenced_schema_name NVARCHAR(255) +, referenced_entity_name NVARCHAR(255) +, join_clause NVARCHAR(MAX) +, [LEVEL] TINYINT +, lineage NVARCHAR(MAX) +); +DECLARE @count INT -- Current ID +, @viewname NVARCHAR(1000); +-- Set the name of the top level view you want to detangle +SET @viewName = N'' +SET @count = 1; +---------------------------------------------------------------------------- +-- Seed the table with the root view, and the root view's referenced tables. +---------------------------------------------------------------------------- +INSERT INTO #viewHierarchy +SELECT NULL parent_view_id +, 'dbo' referenced_schema_name +, @viewName referenced_entity_name +, NULL join_clause +, 0 [LEVEL] +, '/' lineage; +INSERT INTO #viewHierarchy +SELECT DISTINCT @count parent_view_id +, referenced_schema_name +, referenced_entity_name +, '' join_clause +, 1 [LEVEL] +, '/1/' lineage +FROM sys.dm_sql_referenced_entities(@viewName,'OBJECT'); +GO +---------------------------------------------------------------------------- +-- Loop through the nested views. +---------------------------------------------------------------------------- +DECLARE @count INT -- Current ID +, @maxCount INT -- Max ID of the temp table +, @viewname NVARCHAR(1000) +SET @count = 1; +SELECT @maxCount = MAX(id) +FROM #viewHierarchy; +WHILE (@count < @maxCount) -- While there are still rows to process... +BEGIN +SET @count = @count + 1; + -- Get the name of the current view (that we'd like references for) +SELECT @viewName = referenced_entity_name +FROM #viewHierarchy +WHERE id = @count; + -- If it's a view (not a table), insert referenced objects into temp table. +IF (EXISTS (SELECT name FROM sys.objects WHERE name = @viewName AND TYPE = 'v') +OR EXISTS (SELECT name FROM sys.objects WHERE name = @viewName AND TYPE = 'TF') +OR EXISTS (SELECT name FROM sys.objects WHERE name = @viewName AND TYPE = 'FN')) +BEGIN +SET @viewName = N'dbo.' + @viewName; +INSERT INTO #viewHierarchy +SELECT DISTINCT @count parent_view_id +, referenced_schema_name +, referenced_entity_name +, '' join_clause +, NULL [LEVEL] +, '' lineage +FROM sys.dm_sql_referenced_entities(@viewName,'OBJECT'); +SELECT @maxCount = MAX(id) +FROM #viewHierarchy; +END +END +-------------------------------------- +-------------------------------------- +WHILE EXISTS (SELECT 1 FROM #viewHierarchy WHERE [LEVEL] IS NULL) +UPDATE T +SET T.[Level] = P.[Level] + 1, +T.Lineage = P.Lineage + LTRIM(STR(T.parent_view_id,6,0)) + '/' +FROM #viewHierarchy AS T +INNER JOIN #viewHierarchy AS P ON (T.parent_view_id=P.ID) +WHERE P.[Level]>=0 +AND P.Lineage IS NOT NULL +AND T.[Level] IS NULL +SELECT parent.* +,child.id +,child.referenced_entity_name ChildName +FROM #viewHierarchy parent +RIGHT OUTER JOIN #viewHierarchy child ON child.parent_view_id = parent.id +ORDER BY parent.id, child.id + +--SELECT * FROM #viewHierarchy + drop table #viewHierarchy \ No newline at end of file diff --git a/database-enable-query-store-and-rcsi.sql b/database-enable-query-store-and-rcsi.sql new file mode 100644 index 0000000..ce2026a --- /dev/null +++ b/database-enable-query-store-and-rcsi.sql @@ -0,0 +1,28 @@ +USE [master]; +GO +SELECT name, is_query_store_on, is_read_committed_snapshot_on FROM sys.databases; +GO + +-- Change The Isolation Level Of An Availability Group Database +-- http://www.sqlnuggets.com/blog/change-the-isolation-level-of-an-availability-group-database/ + +ALTER DATABASE [DBName] SET QUERY_STORE = ON +GO +ALTER DATABASE [DBName] SET QUERY_STORE (OPERATION_MODE = READ_WRITE, INTERVAL_LENGTH_MINUTES = 5, MAX_STORAGE_SIZE_MB = 2000) +GO +ALTER AVAILABILITY GROUP [AGName] REMOVE DATABASE [DBName]; +GO +ALTER DATABASE [DBName] SET SINGLE_USER WITH ROLLBACK IMMEDIATE +GO +ALTER DATABASE [DBName] SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE +GO +ALTER DATABASE [DBName] SET MULTI_USER +GO +ALTER AVAILABILITY GROUP [AGName] ADD DATABASE [DBName]; +GO + +-- run on each of the secondaries +:CONNECT [SecondaryReplica] +ALTER DATABASE [DBName] SET HADR AVAILABILITY GROUP = aagLaunchpad; +GO + diff --git a/database-get-detail-and-config.sql b/database-get-detail-and-config.sql new file mode 100644 index 0000000..2cb1bcd --- /dev/null +++ b/database-get-detail-and-config.sql @@ -0,0 +1,207 @@ + +DECLARE @tmp_ExtProperties TABLE (DatabaseName VARCHAR(128), name NVARCHAR(60), value SQL_VARIANT); + +INSERT INTO @tmp_ExtProperties (DatabaseName, name, value) +EXEC sp_MSForEachDB 'Use [?]; +SELECT DB_NAME() AS DatabaseName, name, value FROM sys.extended_properties WHERE name = ''Confluence Description'''; + +DECLARE @tmp_FileStream TABLE (DatabaseName VARCHAR(128), non_transacted_access TINYINT, directory_name NVARCHAR(255)); + +INSERT @tmp_FileStream (DatabaseName, non_transacted_access, directory_name) +EXEC sp_MSForEachDB 'Use [?]; +SELECT DB_NAME() AS DatabaseName, non_transacted_access, directory_name FROM sys.database_filestream_options'; + +DECLARE @tmp_QueryStore TABLE ( + DatabaseName VARCHAR(128) + ,querystore_desired_state SMALLINT + ,querystore_actual_state SMALLINT + ,querystore_readonly_reason INT + ,querystore_current_storage_size_mb BIGINT + ,querystore_flush_interval_seconds BIGINT + ,querystore_interval_length_minutes BIGINT + ,querystore_max_storage_size_mb BIGINT + ,querystore_stale_query_threshold_days BIGINT + ,querystore_max_plans_per_query BIGINT + ,querystore_query_capture_mode SMALLINT + ,querystore_size_based_cleanup_mode SMALLINT + ,querystore_wait_stats_capture_mode SMALLINT +); + +DECLARE @QS_SQL NVARCHAR(MAX) + ,@Version VARCHAR(50) = LEFT(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR(128)),2); + +IF @Version > 12 +BEGIN +SET @QS_SQL = 'Use [?]; +SELECT DB_NAME() AS DatabaseName + ,desired_state + ,actual_state + ,readonly_reason + ,current_storage_size_mb + ,flush_interval_seconds + ,interval_length_minutes + ,max_storage_size_mb + ,stale_query_threshold_days + ,max_plans_per_query + ,query_capture_mode + ,size_based_cleanup_mode' ++ CASE WHEN @Version > 13 THEN ' ,wait_stats_capture_mode' ELSE ' ,NULL' END + ' +FROM sys.database_query_store_options'; + +INSERT @tmp_QueryStore ( + DatabaseName + ,querystore_desired_state + ,querystore_actual_state + ,querystore_readonly_reason + ,querystore_current_storage_size_mb + ,querystore_flush_interval_seconds + ,querystore_interval_length_minutes + ,querystore_max_storage_size_mb + ,querystore_stale_query_threshold_days + ,querystore_max_plans_per_query + ,querystore_query_capture_mode + ,querystore_size_based_cleanup_mode + ,querystore_wait_stats_capture_mode +) +EXEC sp_MSForEachDB @QS_SQL; +END; + +SELECT * +INTO #databases +FROM sys.databases; + +IF @Version < 12 +BEGIN + ALTER TABLE #databases ADD + is_auto_create_stats_incremental_on BIT + ,delayed_durability INT + ,is_query_store_on BIT; +END; + +IF @Version < 13 +BEGIN + ALTER TABLE #databases ADD + is_mixed_page_allocation_on BIT;; +END; + +CREATE TABLE #dm_hadr_database_replica_states ( + database_id INT + ,group_id UNIQUEIDENTIFIER + ,is_primary_replica BIT +); + +IF @Version > 12 + INSERT #dm_hadr_database_replica_states (database_id, group_id, is_primary_replica) + SELECT c.database_id + ,b.group_id + ,sys.fn_hadr_is_primary_replica (DB_Name(c.database_id)) AS is_primary_replica + FROM sys.availability_replicas AS b + JOIN sys.dm_hadr_database_replica_states AS c ON b.replica_id = c.replica_id + WHERE b.replica_server_name = @@SERVERNAME; +ELSE + INSERT #dm_hadr_database_replica_states (database_id, group_id, is_primary_replica) + SELECT c.database_id, a.group_id + ,CASE a.role_desc + WHEN 'PRIMARY' THEN 1 + WHEN 'SECONDARY' THEN 0 + WHEN 'RESOLVING' THEN 0 + ELSE NULL + END AS is_primary_replica + FROM sys.dm_hadr_availability_replica_states AS a + JOIN sys.availability_replicas AS b ON b.replica_id = a.replica_id + JOIN sys.dm_hadr_database_replica_states AS c ON a.replica_id = c.replica_id + WHERE b.replica_server_name = @@SERVERNAME; + +SELECT ag_id, ag_name +INTO #dm_hadr_name_id_map +FROM sys.dm_hadr_name_id_map; + +SELECT sid, name +INTO #server_principals +FROM sys.server_principals; + +select distinct + @@SERVERNAME as servername + ,sd.name as databasename + ,grp.ag_name as agname + ,hdrs.is_primary_replica + ,ep.value as description + ,ISNULL(u.name, '') as databaseowner + ,sd.collation_name as collation + ,sd.recovery_model_desc as recoverymodel + ,sd.compatibility_level as compatibilitylevel + ,sd.containment_desc as containmenttype + ,sd.is_auto_close_on + ,sd.is_auto_create_stats_incremental_on + ,sd.is_auto_create_stats_on + ,sd.is_auto_shrink_on + ,sd.is_auto_update_stats_on + ,sd.is_auto_update_stats_async_on + ,sd.is_cursor_close_on_commit_on + ,sd.is_local_cursor_default + ,sd.snapshot_isolation_state + ,sd.is_ansi_null_default_on + ,sd.is_ansi_nulls_on + ,sd.is_ansi_padding_on + ,sd.is_ansi_warnings_on + ,sd.is_arithabort_on + ,sd.is_concat_null_yields_null_on + ,sd.is_db_chaining_on + ,sd.is_date_correlation_on + ,sd.delayed_durability + ,sd.is_mixed_page_allocation_on + ,sd.is_read_committed_snapshot_on + ,sd.is_numeric_roundabort_on + ,sd.is_parameterization_forced + ,sd.is_quoted_identifier_on + ,sd.is_recursive_triggers_on + ,sd.is_nested_triggers_on + ,sd.is_trustworthy_on + ,sd.page_verify_option + ,sd.target_recovery_time_in_seconds + ,sd.is_broker_enabled + ,sd.is_honor_broker_priority_on + ,sd.service_broker_guid + ,sd.is_read_only + ,sd.state + ,sd.is_in_standby + ,sd.is_encrypted + ,sd.is_master_key_encrypted_by_server + ,sd.user_access + ,sd.is_cdc_enabled + ,sd.is_fulltext_enabled + ,fs.non_transacted_access + ,fs.directory_name + ,sd.is_query_store_on + ,qs.querystore_desired_state + ,qs.querystore_actual_state + ,qs.querystore_readonly_reason + ,qs.querystore_current_storage_size_mb + ,qs.querystore_flush_interval_seconds + ,qs.querystore_interval_length_minutes + ,qs.querystore_max_storage_size_mb + ,qs.querystore_stale_query_threshold_days + ,qs.querystore_max_plans_per_query + ,qs.querystore_query_capture_mode + ,qs.querystore_size_based_cleanup_mode + ,qs.querystore_wait_stats_capture_mode +from #databases as sd + left outer join #dm_hadr_database_replica_states as hdrs on hdrs.database_id = sd.database_id + left outer join #dm_hadr_name_id_map as grp on grp.ag_id = hdrs.group_id + left outer join @tmp_ExtProperties ep on ep.DatabaseName = sd.name + left outer join #server_principals u on sd.owner_sid = u.sid + left outer join @tmp_FileStream fs on fs.DatabaseName = sd.name + left outer join @tmp_QueryStore qs on qs.DatabaseName = sd.name +where sd.name not in ('master','msdb','model','tempdb', 'ReportServer', 'ReportServerTempDB'); + +IF OBJECT_ID('tempdb..#databases') IS NOT NULL + DROP TABLE #databases; + +IF OBJECT_ID('tempdb..#dm_hadr_database_replica_states') IS NOT NULL + DROP TABLE #dm_hadr_database_replica_states; + +IF OBJECT_ID('tempdb..#dm_hadr_name_id_map') IS NOT NULL + DROP TABLE #dm_hadr_name_id_map; + +IF OBJECT_ID('tempdb..#server_principals') IS NOT NULL + DROP TABLE #server_principals; diff --git a/database-get-estimated-backup-size.sql b/database-get-estimated-backup-size.sql new file mode 100644 index 0000000..c63aa92 --- /dev/null +++ b/database-get-estimated-backup-size.sql @@ -0,0 +1,35 @@ +DECLARE @SQL NVARCHAR(4000); + +DROP TABLE IF EXISTS #tmp_SpaceUsed; + +CREATE TABLE #tmp_SpaceUsed ( + database_name nvarchar(128) + ,database_size varchar(18) + ,unallocated varchar(18) + ,reserved varchar(18) + ,data varchar(18) + ,index_size varchar(18) + ,unused varchar(18) +); + +SET @SQL = N'USE [?]; +INSERT #tmp_SpaceUsed +EXEC sp_spaceused @updateusage = ''true'', @oneresultset = 1'; + +EXEC sp_MSforeachdb @SQL; + +-- Backup Size (MB) = ((Reserved (KB) – Unused (KB))/1024)/1024 +SELECT database_name + ,((CONVERT(BIGINT,TRIM(REPLACE(reserved,'KB',''))) - CONVERT(BIGINT,TRIM(REPLACE(unused,'KB','')))) / 1024) / 1024 AS ForecastSize_GB + ,1 AS RowId +FROM #tmp_SpaceUsed +UNION +SELECT 'TOTAL' AS database_name + ,SUM(((CONVERT(BIGINT,TRIM(REPLACE(reserved,'KB',''))) - CONVERT(BIGINT,TRIM(REPLACE(unused,'KB',''))))) / 1024) / 1024 AS ForecastSize_GB + ,0 AS RowId +FROM #tmp_SpaceUsed +ORDER BY 3, 1 + + +--BACKUP DATABASE ema TO DISK = 'NUL' WITH COMPRESSION +--SELECT * FROM msdb.dbo.backupset diff --git a/database-get-file-detail.sql b/database-get-file-detail.sql new file mode 100644 index 0000000..bbfc101 --- /dev/null +++ b/database-get-file-detail.sql @@ -0,0 +1,58 @@ + +declare @sql_used nvarchar(max) = N'USE [?]; INSERT #DbUsed (DatabaseId, Used, Name) SELECT DB_ID(), CONVERT(BIGINT, FILEPROPERTY(name, ''SpaceUsed'')) * 8 / 1024, name from sys.database_files' + ,@sql_log nvarchar(max) = N'USE [?]; INSERT #LogInfo (RecoveryUnitId, FileId, FileSize, StartOffset, FSeqNo, [Status], Parity, CreateLSN) EXEC(''DBCC LOGINFO'')' + ,@Version VARCHAR(50) = LEFT(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR(128)),2); + +if OBJECT_ID('tempdb..#DbUsed') is not null drop table #DbUsed; +create table #DbUsed (DatabaseId INT, Used BIGINT, name VARCHAR(128)); + +if OBJECT_ID('tempdb..#LogInfo') is not null drop table #LogInfo; +create table #LogInfo (DatabaseName NVARCHAR(128) default DB_NAME(), RecoveryUnitId INT, FileId INT, FileSize BIGINT, StartOffset BIGINT, FSeqNo INT, [Status] TINYINT, Parity TINYINT, CreateLSN NUMERIC(25,0)); + +if OBJECT_ID('tempdb..#dm_hadr_database_replica_states') is not null drop table #dm_hadr_database_replica_states; +CREATE TABLE #dm_hadr_database_replica_states (database_id INT, is_primary_replica BIT); + +exec sp_msforeachdb @sql_used; +exec sp_msforeachdb @sql_log; + +IF @Version > 12 + INSERT #dm_hadr_database_replica_states (database_id, is_primary_replica) + SELECT c.database_id + ,sys.fn_hadr_is_primary_replica (DB_Name(c.database_id)) AS is_primary_replica + FROM sys.availability_replicas AS b + JOIN sys.dm_hadr_database_replica_states AS c ON b.replica_id = c.replica_id + WHERE b.replica_server_name = @@SERVERNAME; +ELSE + INSERT #dm_hadr_database_replica_states (database_id, is_primary_replica) + SELECT c.database_id + ,CASE a.role_desc + WHEN 'PRIMARY' THEN 1 + WHEN 'SECONDARY' THEN 0 + WHEN 'RESOLVING' THEN 0 + ELSE NULL + END AS is_primary_replica + FROM sys.dm_hadr_availability_replica_states AS a + JOIN sys.availability_replicas AS b ON b.replica_id = a.replica_id + JOIN sys.dm_hadr_database_replica_states AS c ON a.replica_id = c.replica_id + WHERE b.replica_server_name = @@SERVERNAME; + +SELECT @@SERVERNAME as servername + , DB_NAME(f.database_id) as databasename + , UPPER(LEFT(f.physical_name, 3)) as volume + , f.name + , f.physical_name + , CASE WHEN DB_NAME(f.database_id) = 'tempdb' THEN CONVERT(NVARCHAR(15), CONVERT(BIGINT, tmpdb.size) * 8 / 1024) + ELSE CONVERT(NVARCHAR(15), CONVERT(BIGINT, f.size) * 8 / 1024) + END as filesize_mb + , tmp.Used + , CASE f.max_size WHEN -1 THEN N'Unlimited' ELSE CONVERT(NVARCHAR(15), CONVERT(BIGINT, f.max_size) * 8 / 1024) END as maxfilesize_mb + , CASE f.is_percent_growth WHEN 1 THEN NULL ELSE (f.growth * 8 / 1024) END as filegrowth_mb + , CASE f.is_percent_growth WHEN 1 THEN f.growth ELSE NULL END as filegrowth_pct + , li.VLFs + , rs.is_primary_replica + , DEFAULT_DOMAIN() as domain +FROM sys.master_files f + LEFT OUTER JOIN #DbUsed tmp on f.database_id = tmp.DatabaseId and f.name = tmp.name + LEFT OUTER JOIN (select DatabaseName, COUNT(FileId) as VLFs from #LogInfo group by DatabaseName) li on DB_NAME(f.database_id) = li.DatabaseName and f.name like '%log' + LEFT OUTER JOIN #dm_hadr_database_replica_states rs on f.database_id = rs.database_id + LEFT OUTER JOIN tempdb.sys.database_files tmpdb ON f.name = tmpdb.name AND DB_NAME(f.database_id) = 'tempdb'; \ No newline at end of file diff --git a/database-info/file-size-and-space-used.sql b/database-get-file-size-and-space-used.sql similarity index 93% rename from database-info/file-size-and-space-used.sql rename to database-get-file-size-and-space-used.sql index f330d1b..fa10b34 100644 --- a/database-info/file-size-and-space-used.sql +++ b/database-get-file-size-and-space-used.sql @@ -1,66 +1,70 @@ -USE master; -GO - -IF EXISTS ( - SELECT 1 - FROM tempdb.sys.objects - WHERE [type] = 'U' - AND [object_id] = OBJECT_ID(N'tempdb..#DB_FILE_INFO') -) - DROP TABLE #DB_FILE_INFO; - -SET NOCOUNT ON; - -CREATE TABLE #DB_FILE_INFO ( - DBName NVARCHAR(128) - , FileGroupName NVARCHAR(128) - , [Size] BIGINT - , Used BIGINT - , [type] TINYINT - , FileId INT -); - -DECLARE @l_sql NVARCHAR(4000); - -SET @l_sql = -'USE [?]; -IF DB_NAME() <> N''?'' GOTO Error_Exit; - -INSERT INTO #DB_FILE_INFO ( - DBName - , FileGroupName - , [Size] - , Used - , [type] - , FileId -) -SELECT DB_NAME() - , FileGroupName = CASE WHEN f.data_space_id = 0 THEN ''LOG'' - ELSE s.name - END - , [Size] = CONVERT(BIGINT, f.size) * 8 / 1024 -- MB - , Used = CONVERT(BIGINT, FILEPROPERTY(f.name, ''SpaceUsed'')) * 8 / 1024 -- MB - , [type] = f.[type] - , FileId = f.[file_id] -FROM sys.database_files f - LEFT OUTER JOIN sys.data_spaces s - ON f.data_space_id = s.data_space_id; - -Error_Exit: - -'; - -EXEC sp_msforeachdb @l_sql; - -SELECT DBName - , FileGroupName - , FileSize = [Size] - , FileSizeUsed = Used - , FileSizeUsedPct = CONVERT(NUMERIC(4,1), Used * 1.0 / [Size] * 100) - , FileSizeUnused = [Size] - Used - , FileSizeUnusedPct = CONVERT(NUMERIC(4,1), ([Size] - Used) * 1.0 / [Size] * 100) -FROM #DB_FILE_INFO -ORDER BY DBName - , [type] - , FileId; - +USE master; +GO + +IF EXISTS ( + SELECT 1 + FROM tempdb.sys.objects + WHERE [type] = 'U' + AND [object_id] = OBJECT_ID(N'tempdb..#DB_FILE_INFO') +) + DROP TABLE #DB_FILE_INFO; + +SET NOCOUNT ON; + +CREATE TABLE #DB_FILE_INFO ( + DBName NVARCHAR(128) + , FileGroupName NVARCHAR(128) + , [Size] BIGINT + , Used BIGINT + , [type] TINYINT + , FileId INT + , physical_name NVARCHAR(260) +); + +DECLARE @l_sql NVARCHAR(4000); + +SET @l_sql = +'USE [?]; +IF DB_NAME() <> N''?'' GOTO Error_Exit; + +INSERT INTO #DB_FILE_INFO ( + DBName + , FileGroupName + , [Size] + , Used + , [type] + , FileId + , physical_name +) +SELECT DB_NAME() + , FileGroupName = CASE WHEN f.data_space_id = 0 THEN ''LOG'' + ELSE s.name + END + , [Size] = CONVERT(BIGINT, f.size) * 8 / 1024 -- MB + , Used = CONVERT(BIGINT, FILEPROPERTY(f.name, ''SpaceUsed'')) * 8 / 1024 -- MB + , [type] = f.[type] + , FileId = f.[file_id] + , f.physical_name +FROM sys.database_files f + LEFT OUTER JOIN sys.data_spaces s + ON f.data_space_id = s.data_space_id; + +Error_Exit: + +'; + +EXEC sp_msforeachdb @l_sql; + +SELECT DBName + , FileGroupName + , FileSize = [Size] + , FileSizeUsed = Used + , FileSizeUsedPct = CONVERT(NUMERIC(4,1), Used * 1.0 / [Size] * 100) + , FileSizeUnused = [Size] - Used + , FileSizeUnusedPct = CONVERT(NUMERIC(4,1), ([Size] - Used) * 1.0 / [Size] * 100) + , physical_name +FROM #DB_FILE_INFO +ORDER BY DBName + , [type] + , FileId; + diff --git a/database-info/file-to-volume-mapping.sql b/database-get-file-to-volume-mapping.sql similarity index 97% rename from database-info/file-to-volume-mapping.sql rename to database-get-file-to-volume-mapping.sql index a2bd861..49618f9 100644 --- a/database-info/file-to-volume-mapping.sql +++ b/database-get-file-to-volume-mapping.sql @@ -1,25 +1,25 @@ - -SELECT DatabaseName = DB_NAME(f.database_id) - , VolumeLetter = UPPER(LEFT(f.physical_name, 3)) - , LogicalFileName = f.name - --, FileId = f.[file_id] - --, FilegroupId = f.data_space_id - , PhysicalFileName = f.physical_name - , FileGroup = CASE WHEN f.data_space_id = 0 THEN 'LOG' - ELSE s.name - END - , DefaultFilegroup = CASE WHEN s.is_default = 1 THEN 'Y' - ELSE '' - END - , [Size] = CONVERT(NVARCHAR(15), CONVERT(BIGINT, f.size) * 8 / 1024) + N' MB' - , [MaxSize] = CASE f.max_size WHEN -1 THEN N'Unlimited' - ELSE CONVERT(NVARCHAR(15), CONVERT(BIGINT, f.max_size) * 8 / 1024) + N' MB' - END - , [Growth] = CASE f.is_percent_growth WHEN 1 THEN CONVERT(NVARCHAR(15), f.growth) + N'%' - ELSE CONVERT(NVARCHAR(15), CONVERT(BIGINT, f.growth) * 8 / 1024) + N' MB' - END -FROM sys.master_files f - LEFT OUTER JOIN sys.data_spaces s - ON f.data_space_id = s.data_space_id -ORDER BY DB_NAME(f.database_id) - , f.file_id; + +SELECT DatabaseName = DB_NAME(f.database_id) + , VolumeLetter = UPPER(LEFT(f.physical_name, 3)) + , LogicalFileName = f.name + --, FileId = f.[file_id] + --, FilegroupId = f.data_space_id + , PhysicalFileName = f.physical_name + , FileGroup = CASE WHEN f.data_space_id = 0 THEN 'LOG' + ELSE s.name + END + , DefaultFilegroup = CASE WHEN s.is_default = 1 THEN 'Y' + ELSE '' + END + , [Size] = CONVERT(NVARCHAR(15), CONVERT(BIGINT, f.size) * 8 / 1024) + N' MB' + , [MaxSize] = CASE f.max_size WHEN -1 THEN N'Unlimited' + ELSE CONVERT(NVARCHAR(15), CONVERT(BIGINT, f.max_size) * 8 / 1024) + N' MB' + END + , [Growth] = CASE f.is_percent_growth WHEN 1 THEN CONVERT(NVARCHAR(15), f.growth) + N'%' + ELSE CONVERT(NVARCHAR(15), CONVERT(BIGINT, f.growth) * 8 / 1024) + N' MB' + END +FROM sys.master_files f + LEFT OUTER JOIN sys.data_spaces s + ON f.data_space_id = s.data_space_id +ORDER BY DB_NAME(f.database_id) + , f.file_id; diff --git a/database-info/foreign-keys-table.sql b/database-get-foreign-keys-for-table.sql similarity index 98% rename from database-info/foreign-keys-table.sql rename to database-get-foreign-keys-for-table.sql index 45a93dd..01114d8 100644 --- a/database-info/foreign-keys-table.sql +++ b/database-get-foreign-keys-for-table.sql @@ -1,31 +1,31 @@ -DECLARE @TableName AS VARCHAR(250) = ''; - --- FOREIGN KEYS ON TARGET TABLE -SELECT fk.name AS ForeignKey - ,CASE WHEN fk.is_not_for_replication = 0 THEN 'No' - ELSE 'yes' - END AS IsNotForReplication - ,OBJECT_NAME(fk.parent_object_id) AS TableName - ,COL_NAME(fkc.parent_object_id, fkc.parent_column_id) AS ColumnName - ,OBJECT_NAME(fk.referenced_object_id) AS ReferenceTableName - ,COL_NAME(fkc.referenced_object_id, fkc.referenced_column_id) AS ReferenceColumnName -FROM sys.foreign_keys AS fk - INNER JOIN sys.foreign_key_columns AS fkc - ON fk.object_id = fkc.constraint_object_id -WHERE fkc.parent_object_id = OBJECT_ID(@TableName) -ORDER BY IsNotForReplication; - --- FOREIGN KEYS REFERENCING TARGET TABLE -SELECT fk.name AS ForeignKey - ,CASE WHEN fk.is_not_for_replication = 0 THEN 'No' - ELSE 'yes' - END AS IsNotForReplication - ,OBJECT_NAME(fk.parent_object_id) AS TableName - ,COL_NAME(fkc.parent_object_id, fkc.parent_column_id) AS ColumnName - ,OBJECT_NAME(fk.referenced_object_id) AS ReferenceTableName - ,COL_NAME(fkc.referenced_object_id, fkc.referenced_column_id) AS ReferenceColumnName -FROM sys.foreign_keys AS fk - INNER JOIN sys.foreign_key_columns AS fkc - ON fk.object_id = fkc.constraint_object_id -WHERE fkc.referenced_object_id = OBJECT_ID(@TableName) +DECLARE @TableName AS VARCHAR(250) = ''; + +-- FOREIGN KEYS ON TARGET TABLE +SELECT fk.name AS ForeignKey + ,CASE WHEN fk.is_not_for_replication = 0 THEN 'No' + ELSE 'yes' + END AS IsNotForReplication + ,OBJECT_NAME(fk.parent_object_id) AS TableName + ,COL_NAME(fkc.parent_object_id, fkc.parent_column_id) AS ColumnName + ,OBJECT_NAME(fk.referenced_object_id) AS ReferenceTableName + ,COL_NAME(fkc.referenced_object_id, fkc.referenced_column_id) AS ReferenceColumnName +FROM sys.foreign_keys AS fk + INNER JOIN sys.foreign_key_columns AS fkc + ON fk.object_id = fkc.constraint_object_id +WHERE fkc.parent_object_id = OBJECT_ID(@TableName) +ORDER BY IsNotForReplication; + +-- FOREIGN KEYS REFERENCING TARGET TABLE +SELECT fk.name AS ForeignKey + ,CASE WHEN fk.is_not_for_replication = 0 THEN 'No' + ELSE 'yes' + END AS IsNotForReplication + ,OBJECT_NAME(fk.parent_object_id) AS TableName + ,COL_NAME(fkc.parent_object_id, fkc.parent_column_id) AS ColumnName + ,OBJECT_NAME(fk.referenced_object_id) AS ReferenceTableName + ,COL_NAME(fkc.referenced_object_id, fkc.referenced_column_id) AS ReferenceColumnName +FROM sys.foreign_keys AS fk + INNER JOIN sys.foreign_key_columns AS fkc + ON fk.object_id = fkc.constraint_object_id +WHERE fkc.referenced_object_id = OBJECT_ID(@TableName) ORDER BY IsNotForReplication; \ No newline at end of file diff --git a/database-info/foreign-keys-all.sql b/database-get-foreign-keys.sql similarity index 75% rename from database-info/foreign-keys-all.sql rename to database-get-foreign-keys.sql index 7206dd3..81e0ff3 100644 --- a/database-info/foreign-keys-all.sql +++ b/database-get-foreign-keys.sql @@ -1,12 +1,18 @@ -SELECT fk.name AS ForeignKey - ,CASE WHEN fk.is_not_for_replication = 0 THEN 'No' - ELSE 'yes' - END AS IsNotForReplication - ,OBJECT_NAME(fk.parent_object_id) AS TableName - ,COL_NAME(fkc.parent_object_id, fkc.parent_column_id) AS ColumnName - ,OBJECT_NAME(fk.referenced_object_id) AS ReferenceTableName - ,COL_NAME(fkc.referenced_object_id, fkc.referenced_column_id) AS ReferenceColumnName -FROM sys.foreign_keys AS fk - INNER JOIN sys.foreign_key_columns AS fkc - ON fk.object_id = fkc.constraint_object_id +SELECT fk.name AS ForeignKey + ,CASE WHEN fk.is_not_for_replication = 0 THEN 'No' + ELSE 'Yes' + END AS IsNotForReplication + ,CASE WHEN fk.delete_referential_action = 0 THEN 'No' + ELSE 'Yes' + END AS IsDeleteCascade + ,CASE WHEN fk.update_referential_action = 0 THEN 'No' + ELSE 'Yes' + END AS IsUpdateCascade + ,OBJECT_NAME(fk.parent_object_id) AS TableName + ,COL_NAME(fkc.parent_object_id, fkc.parent_column_id) AS ColumnName + ,OBJECT_NAME(fk.referenced_object_id) AS ReferenceTableName + ,COL_NAME(fkc.referenced_object_id, fkc.referenced_column_id) AS ReferenceColumnName +FROM sys.foreign_keys AS fk + INNER JOIN sys.foreign_key_columns AS fkc + ON fk.object_id = fkc.constraint_object_id ORDER BY IsNotForReplication; \ No newline at end of file diff --git a/database-info/log-file-VLF-count.sql b/database-get-log-file-VLF-count.sql similarity index 94% rename from database-info/log-file-VLF-count.sql rename to database-get-log-file-VLF-count.sql index 574a300..6b629dd 100644 --- a/database-info/log-file-VLF-count.sql +++ b/database-get-log-file-VLF-count.sql @@ -1,43 +1,43 @@ -IF EXISTS ( - SELECT 1 - FROM tempdb.sys.objects - WHERE [type] = 'U' - AND [object_id] = OBJECT_ID(N'tempdb..#LogInfo') -) - DROP TABLE #LogInfo; - -DECLARE @l_sql NVARCHAR(4000); - -CREATE TABLE #LogInfo ( - DatabaseName NVARCHAR(128) DEFAULT DB_NAME() - , RecoveryUnitId INT - , FileId INT - , FileSize BIGINT - , StartOffset BIGINT - , FSeqNo INT - , [Status] TINYINT - , Parity TINYINT - , CreateLSN NUMERIC(25,0) -); - -SET @l_sql = -'USE [?]; -INSERT INTO #LogInfo ( - RecoveryUnitId - , FileId - , FileSize - , StartOffset - , FSeqNo - , Status - , Parity - , CreateLSN -) -EXEC(''DBCC LOGINFO'')'; - -EXEC sp_msforeachdb @l_sql; - -SELECT DBName = DatabaseName - , VLFs = COUNT(FileId) -FROM #LogInfo -GROUP BY DatabaseName +IF EXISTS ( + SELECT 1 + FROM tempdb.sys.objects + WHERE [type] = 'U' + AND [object_id] = OBJECT_ID(N'tempdb..#LogInfo') +) + DROP TABLE #LogInfo; + +DECLARE @l_sql NVARCHAR(4000); + +CREATE TABLE #LogInfo ( + DatabaseName NVARCHAR(128) DEFAULT DB_NAME() + , RecoveryUnitId INT + , FileId INT + , FileSize BIGINT + , StartOffset BIGINT + , FSeqNo INT + , [Status] TINYINT + , Parity TINYINT + , CreateLSN NUMERIC(25,0) +); + +SET @l_sql = +'USE [?]; +INSERT INTO #LogInfo ( + RecoveryUnitId + , FileId + , FileSize + , StartOffset + , FSeqNo + , Status + , Parity + , CreateLSN +) +EXEC(''DBCC LOGINFO'')'; + +EXEC sp_msforeachdb @l_sql; + +SELECT DBName = DatabaseName + , VLFs = COUNT(FileId) +FROM #LogInfo +GROUP BY DatabaseName ORDER BY DatabaseName; \ No newline at end of file diff --git a/database-get-log-info.sql b/database-get-log-info.sql new file mode 100644 index 0000000..da3951d --- /dev/null +++ b/database-get-log-info.sql @@ -0,0 +1,11 @@ +DECLARE @DatabaseName NVARCHAR(128) = 'DBName' + ,@DatabaseId INT; + +SET @DatabaseId = DB_ID(@DatabaseName); + +SELECT name, recovery_model_desc, log_reuse_wait_desc +FROM sys.databases +WHERE name = @DatabaseName; + +SELECT * +FROM sys.dm_db_log_info (@DatabaseId); diff --git a/database-get-log-space.sql b/database-get-log-space.sql new file mode 100644 index 0000000..7f648b0 --- /dev/null +++ b/database-get-log-space.sql @@ -0,0 +1 @@ +DBCC SQLPERF(logspace) diff --git a/database-info/object-dependencies.sql b/database-get-object-dependencies.sql similarity index 92% rename from database-info/object-dependencies.sql rename to database-get-object-dependencies.sql index 2dbafa1..0db3e89 100644 --- a/database-info/object-dependencies.sql +++ b/database-get-object-dependencies.sql @@ -1,39 +1,39 @@ - -SELECT OBJECT_SCHEMA_NAME(d.referencing_id) AS srcschema -- Schema in which the referencing entity belongs. - ,OBJECT_NAME(d.referencing_id) AS srcname -- Name of the referencing entity. - ,srcc.name AS srccolumn -- Column name when the referencing entity is a column. - ,d.referenced_server_name AS tgtserver -- Name of the server of the referenced entity. - ,d.referenced_database_name AS tgtdatabase -- Name of the database of the referenced entity. - ,d.referenced_schema_name AS tgtschema -- Schema in which the referenced entity belongs. - ,d.referenced_entity_name AS tgtname -- Name of the referenced entity. Is not nullable. - ,srct.name AS tgtcolumn -- Name of the referenced column when the referencing entity is a column. -FROM sys.sql_expression_dependencies d - LEFT OUTER JOIN sys.columns srcc - ON d.referencing_id = srcc.object_id - AND d.referencing_minor_id = srcc.column_id - LEFT OUTER JOIN sys.columns srct - ON d.referenced_id = srct.object_id - AND d.referenced_minor_id = srct.column_id; - - -SELECT e.referenced_server_name AS objserver - ,e.referenced_database_name AS objdatabase - ,e.referenced_schema_name AS objschema - ,e.referenced_entity_name AS objname - ,e.referenced_minor_name AS objcolumn - ,o.type_desc AS objtype - ,e.is_selected AS objselected -- 1 = The object or column is selected. - ,e.is_select_all AS objselectstar -- 1 = The object is used in a SELECT * clause (object-level only). - ,e.is_updated AS objupdated -- 1 = The object or column is modified. - ,e.is_all_columns_found AS objcolumnfound -- 0 = Column dependencies for the object could not be found. -FROM sys.dm_sql_referenced_entities('dbo.P_OSAR_SAVE_Fin_File', 'OBJECT') e - LEFT OUTER JOIN sys.objects o - ON e.referenced_id = o.object_id; - - -SELECT e.referencing_schema_name AS objschema - ,e.referencing_entity_name AS objname - ,o.type_desc AS objtype -FROM sys.dm_sql_referencing_entities('dbo.T_OSAR_REPORT_SIZES', 'OBJECT') e - LEFT OUTER JOIN sys.objects o - ON e.referencing_id = o.object_id; + +SELECT OBJECT_SCHEMA_NAME(d.referencing_id) AS srcschema -- Schema in which the referencing entity belongs. + ,OBJECT_NAME(d.referencing_id) AS srcname -- Name of the referencing entity. + ,srcc.name AS srccolumn -- Column name when the referencing entity is a column. + ,d.referenced_server_name AS tgtserver -- Name of the server of the referenced entity. + ,d.referenced_database_name AS tgtdatabase -- Name of the database of the referenced entity. + ,d.referenced_schema_name AS tgtschema -- Schema in which the referenced entity belongs. + ,d.referenced_entity_name AS tgtname -- Name of the referenced entity. Is not nullable. + ,srct.name AS tgtcolumn -- Name of the referenced column when the referencing entity is a column. +FROM sys.sql_expression_dependencies d + LEFT OUTER JOIN sys.columns srcc + ON d.referencing_id = srcc.object_id + AND d.referencing_minor_id = srcc.column_id + LEFT OUTER JOIN sys.columns srct + ON d.referenced_id = srct.object_id + AND d.referenced_minor_id = srct.column_id; + + +SELECT e.referenced_server_name AS objserver + ,e.referenced_database_name AS objdatabase + ,e.referenced_schema_name AS objschema + ,e.referenced_entity_name AS objname + ,e.referenced_minor_name AS objcolumn + ,o.type_desc AS objtype + ,e.is_selected AS objselected -- 1 = The object or column is selected. + ,e.is_select_all AS objselectstar -- 1 = The object is used in a SELECT * clause (object-level only). + ,e.is_updated AS objupdated -- 1 = The object or column is modified. + ,e.is_all_columns_found AS objcolumnfound -- 0 = Column dependencies for the object could not be found. +FROM sys.dm_sql_referenced_entities('schema.referencing_entity_name', 'OBJECT') e + LEFT OUTER JOIN sys.objects o + ON e.referenced_id = o.object_id; + + +SELECT e.referencing_schema_name AS objschema + ,e.referencing_entity_name AS objname + ,o.type_desc AS objtype +FROM sys.dm_sql_referencing_entities('schema.referenced_entity_name', 'OBJECT') e + LEFT OUTER JOIN sys.objects o + ON e.referencing_id = o.object_id; diff --git a/database-get-orphan-logins.sql b/database-get-orphan-logins.sql new file mode 100644 index 0000000..cbcb7e5 --- /dev/null +++ b/database-get-orphan-logins.sql @@ -0,0 +1,35 @@ +/* +List the users and corresponding security identifiers (SID) in the current database that are not linked to any login. +User, login, and password must be NULL or not specified. +*/ +USE [?] +GO +EXEC sys.sp_change_users_login @Action = 'report'; +GO + +/* +Links a user entry in the sys.database_principals system catalog view in the current database to a SQL Server login of the same name. If a login with the same name does not exist, +one will be created. Examine the result from the Auto_Fix statement to confirm that the correct link is in fact made. Avoid using Auto_Fix in security-sensitive situations. + +When you use Auto_Fix, you must specify user and password if the login does not already exist, otherwise you must specify user but password will be ignored. Login must be NULL. +User must be a valid user in the current database. The login cannot have another user mapped to it. +*/ +USE [?] +GO +EXEC sys.sp_change_users_login + @Action = 'auto_fix' + ,@UserNamePattern = 'database_user' -- name of a user in the current database + ,@LoginName = 'sql_login' -- name of a SQL Server login + ,@Password = 'new_pwd'; -- if a matching login does not exist, sp creates a new login and assigns this password +GO + +/* +Links the specified user in the current database to an existing SQL Server login. +*/ +USE [?] +GO +EXEC sys.sp_change_users_login + @Action = 'update_one' + ,@UserNamePattern = 'database_user' -- name of a user in the current database + ,@LoginName = 'sql_login'; -- name of a SQL Server login +GO diff --git a/database-get-scoped-configurations.sql b/database-get-scoped-configurations.sql new file mode 100644 index 0000000..74f0bca --- /dev/null +++ b/database-get-scoped-configurations.sql @@ -0,0 +1,22 @@ + +DECLARE @Version VARCHAR(50) = LEFT(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR(128)),2) + ,@SQL NVARCHAR(MAX); + +IF @Version = 13 + SET @SQL = N' + SELECT DB_NAME() + ,name + ,value + ,value_for_secondary + ,NULL AS is_value_default + FROM sys.database_scoped_configurations;' +ELSE IF @Version > 13 + SET @SQL = N' + SELECT DB_NAME() + ,name + ,value + ,value_for_secondary + ,is_value_default + FROM sys.database_scoped_configurations;' + +EXEC (@SQL); \ No newline at end of file diff --git a/database-config/sparse-column-estimation.sql b/database-get-sparse-column-estimation.sql similarity index 95% rename from database-config/sparse-column-estimation.sql rename to database-get-sparse-column-estimation.sql index a1cc523..35048a3 100644 --- a/database-config/sparse-column-estimation.sql +++ b/database-get-sparse-column-estimation.sql @@ -1,121 +1,121 @@ -USE rp_prod; -GO - -SET NOCOUNT ON; - -DECLARE @TblName NVARCHAR(128) = 'tranche' - ,@ColList NVARCHAR(MAX) = '' - ,@sql NVARCHAR(MAX); - -DECLARE @DataTypeNullPct TABLE (DataType NVARCHAR(128), Pct NUMERIC(3, 2), PrecisionLength INT); - -DECLARE @IndxCols TABLE (ColumnId INT); - -DECLARE @Cols TABLE ( - ColName NVARCHAR(128) - ,DataType NVARCHAR(128) - ,SparseCol BIT - ,TargetPct NUMERIC(3, 2) - ,ColLength SMALLINT -); - -INSERT INTO @DataTypeNullPct (DataType, Pct, PrecisionLength) -VALUES ('bit', .98, NULL) - ,('tinyint', .86, NULL) - ,('smallint', .76, NULL) - ,('int', .64, NULL) - ,('bigint', .52, NULL) - ,('real', .64, NULL) - ,('float', .52, NULL) - ,('smallmoney', .64, NULL) - ,('money', .52, NULL) - ,('smalldatetime', .64, NULL) - ,('datetime', .52, NULL) - ,('uniqueidentifier', .43, NULL) - ,('date', .69, NULL) - ,('varchar', .6, NULL) - ,('char', .6, NULL) - ,('nvarchar', .6, NULL) - ,('nchar', .6, NULL) - ,('varbinary', .6, NULL) - ,('binary', .6, NULL) - ,('xml', .6, NULL) - ,('hierarchyid', .6, NULL) - ,('datetime2', .57, 0) - ,('datetime2', .52, 7) - ,('time', .69, 0) - ,('time', .6, 7) - ,('datetimeoffset', .52, 0) - ,('datetimeoffset', .49, 7) - ,('decimal', .6, 1) - ,('decimal', .42, 38) - ,('numeric', .6, 1) - ,('numeric', .42, 38) - ,('vardecimal', .6, 1) - ,('vardecimal', .42, 38); - -INSERT INTO @IndxCols (ColumnId) -SELECT c.column_id -FROM sys.indexes i - INNER JOIN sys.index_columns c - ON i.object_id = c.object_id - AND i.index_id = c.index_id -WHERE i.object_id = OBJECT_ID(@TblName) --- clustered, unique or primary key index -AND (i.index_id = 1 OR i.is_primary_key = 1 OR i.is_unique_constraint = 1); - -INSERT INTO @Cols (ColName, DataType, SparseCol, TargetPct, ColLength) -SELECT c.name AS ColName - ,t.name AS DataType - ,c.is_sparse AS SparseCol - ,np.Pct AS TargetPct - ,c.max_length AS ColLength -FROM sys.columns c - INNER JOIN sys.types t - ON c.system_type_id = t.system_type_id - INNER JOIN @DataTypeNullPct np - ON t.name = np.DataType - AND c.precision <= ISNULL(np.PrecisionLength, c.precision) -WHERE c.object_id = OBJECT_ID(@TblName) --- data types cannot be specified as SPARSE -AND t.name NOT IN ('geography', 'geometry', 'image', 'ntext', 'text', 'timestamp') --- data types cannot be specified as SPARSE: user-defined data types -AND t.is_user_defined = 0 --- column must be nullable and cannot have the ROWGUIDCOL or IDENTITY properties -AND c.is_nullable = 1 -AND c.is_rowguidcol = 0 -AND c.is_identity = 0 --- sparse column cannot have the FILESTREAM attribute -AND c.is_filestream = 0 --- column cannot have a default value -AND c.default_object_id = 0 --- column cannot be bound to a rule -AND c.rule_object_id = 0 --- a computed column cannot be marked as SPARSE -AND c.is_computed = 0 --- cannot be part of a clustered index or a unique primary key index -AND NOT EXISTS (SELECT 1 FROM @IndxCols WHERE ColumnId = c.column_id) --- cannot be used as a partition key of a clustered index or heap --- cannot be part of a user-defined table type -; - -SELECT @ColList = - @ColList + N'[' + ColName + N']=' + N'CASE WHEN ' + N'SUM(CASE WHEN ' + N'[' + ColName + N']' - + N' IS NULL THEN 1 ELSE 0 END' + N')*1.0/COUNT(*)' + N' >= ' + CONVERT(VARCHAR(10), TargetPct) - + N' THEN ''Y'' ELSE ''N'' END' - + N',' -FROM @Cols; - -SELECT @sql = N'SELECT ' + LEFT(@ColList, LEN(@ColList) - 1) + N' FROM ' + @TblName; - -EXEC sys.sp_executesql @sql; - -DBCC SHOWCONTIG(@TblName) WITH TABLERESULTS; - -SELECT ColName - ,DataType - ,SparseCol - ,TargetPct - ,ColLength - ,', ' + ColName + ' = SUM(CASE WHEN ' + ColName + ' IS NULL THEN 1 ELSE 0 END) * 1.0 / COUNT(*)' -FROM @Cols; +USE [?]; +GO + +SET NOCOUNT ON; + +DECLARE @TblName NVARCHAR(128) = 'TblName' + ,@ColList NVARCHAR(MAX) = '' + ,@sql NVARCHAR(MAX); + +DECLARE @DataTypeNullPct TABLE (DataType NVARCHAR(128), Pct NUMERIC(3, 2), PrecisionLength INT); + +DECLARE @IndxCols TABLE (ColumnId INT); + +DECLARE @Cols TABLE ( + ColName NVARCHAR(128) + ,DataType NVARCHAR(128) + ,SparseCol BIT + ,TargetPct NUMERIC(3, 2) + ,ColLength SMALLINT +); + +INSERT INTO @DataTypeNullPct (DataType, Pct, PrecisionLength) +VALUES ('bit', .98, NULL) + ,('tinyint', .86, NULL) + ,('smallint', .76, NULL) + ,('int', .64, NULL) + ,('bigint', .52, NULL) + ,('real', .64, NULL) + ,('float', .52, NULL) + ,('smallmoney', .64, NULL) + ,('money', .52, NULL) + ,('smalldatetime', .64, NULL) + ,('datetime', .52, NULL) + ,('uniqueidentifier', .43, NULL) + ,('date', .69, NULL) + ,('varchar', .6, NULL) + ,('char', .6, NULL) + ,('nvarchar', .6, NULL) + ,('nchar', .6, NULL) + ,('varbinary', .6, NULL) + ,('binary', .6, NULL) + ,('xml', .6, NULL) + ,('hierarchyid', .6, NULL) + ,('datetime2', .57, 0) + ,('datetime2', .52, 7) + ,('time', .69, 0) + ,('time', .6, 7) + ,('datetimeoffset', .52, 0) + ,('datetimeoffset', .49, 7) + ,('decimal', .6, 1) + ,('decimal', .42, 38) + ,('numeric', .6, 1) + ,('numeric', .42, 38) + ,('vardecimal', .6, 1) + ,('vardecimal', .42, 38); + +INSERT INTO @IndxCols (ColumnId) +SELECT c.column_id +FROM sys.indexes i + INNER JOIN sys.index_columns c + ON i.object_id = c.object_id + AND i.index_id = c.index_id +WHERE i.object_id = OBJECT_ID(@TblName) +-- clustered, unique or primary key index +AND (i.index_id = 1 OR i.is_primary_key = 1 OR i.is_unique_constraint = 1); + +INSERT INTO @Cols (ColName, DataType, SparseCol, TargetPct, ColLength) +SELECT c.name AS ColName + ,t.name AS DataType + ,c.is_sparse AS SparseCol + ,np.Pct AS TargetPct + ,c.max_length AS ColLength +FROM sys.columns c + INNER JOIN sys.types t + ON c.system_type_id = t.system_type_id + INNER JOIN @DataTypeNullPct np + ON t.name = np.DataType + AND c.precision <= ISNULL(np.PrecisionLength, c.precision) +WHERE c.object_id = OBJECT_ID(@TblName) +-- data types cannot be specified as SPARSE +AND t.name NOT IN ('geography', 'geometry', 'image', 'ntext', 'text', 'timestamp') +-- data types cannot be specified as SPARSE: user-defined data types +AND t.is_user_defined = 0 +-- column must be nullable and cannot have the ROWGUIDCOL or IDENTITY properties +AND c.is_nullable = 1 +AND c.is_rowguidcol = 0 +AND c.is_identity = 0 +-- sparse column cannot have the FILESTREAM attribute +AND c.is_filestream = 0 +-- column cannot have a default value +AND c.default_object_id = 0 +-- column cannot be bound to a rule +AND c.rule_object_id = 0 +-- a computed column cannot be marked as SPARSE +AND c.is_computed = 0 +-- cannot be part of a clustered index or a unique primary key index +AND NOT EXISTS (SELECT 1 FROM @IndxCols WHERE ColumnId = c.column_id) +-- cannot be used as a partition key of a clustered index or heap +-- cannot be part of a user-defined table type +; + +SELECT @ColList = + @ColList + N'[' + ColName + N']=' + N'CASE WHEN ' + N'SUM(CASE WHEN ' + N'[' + ColName + N']' + + N' IS NULL THEN 1 ELSE 0 END' + N')*1.0/COUNT(*)' + N' >= ' + CONVERT(VARCHAR(10), TargetPct) + + N' THEN ''Y'' ELSE ''N'' END' + + N',' +FROM @Cols; + +SELECT @sql = N'SELECT ' + LEFT(@ColList, LEN(@ColList) - 1) + N' FROM ' + @TblName; + +EXEC sys.sp_executesql @sql; + +DBCC SHOWCONTIG(@TblName) WITH TABLERESULTS; + +SELECT ColName + ,DataType + ,SparseCol + ,TargetPct + ,ColLength + ,', ' + ColName + ' = SUM(CASE WHEN ' + ColName + ' IS NULL THEN 1 ELSE 0 END) * 1.0 / COUNT(*)' +FROM @Cols; diff --git a/database-info/status-CHECKDB.sql b/database-get-status-CHECKDB.sql similarity index 96% rename from database-info/status-CHECKDB.sql rename to database-get-status-CHECKDB.sql index 5894031..d1080de 100644 --- a/database-info/status-CHECKDB.sql +++ b/database-get-status-CHECKDB.sql @@ -1,29 +1,29 @@ -DECLARE @session_id INT; - -SELECT @session_id = session_id -FROM sys.dm_exec_requests -WHERE command LIKE '%DBCC%'; - -SELECT session_id - ,start_time - ,command - ,percent_complete - ,total_elapsed_time - ,estimated_completion_time - ,database_id - ,user_id - ,last_wait_type -FROM sys.dm_exec_requests -WHERE session_id = @session_id; - --- NOTE: for Enterprise Edition, CHECKDB respects the MAXDOP setting configured for the instance --- https://www.sqlskills.com/blogs/erin/dbcc-checkdb-parallel-checks-and-sql-server-edition/ -SELECT o.name - ,o.schema_id - ,o.type_desc -FROM sys.dm_tran_locks l - INNER JOIN sys.objects o - ON l.resource_associated_entity_id = o.object_id -WHERE l.request_session_id = @session_id -AND l.resource_type = 'OBJECT' -AND l.resource_associated_entity_id > 50; +DECLARE @session_id INT; + +SELECT @session_id = session_id +FROM sys.dm_exec_requests +WHERE command LIKE '%DBCC%'; + +SELECT session_id + ,start_time + ,command + ,percent_complete + ,total_elapsed_time + ,estimated_completion_time + ,database_id + ,user_id + ,last_wait_type +FROM sys.dm_exec_requests +WHERE session_id = @session_id; + +-- NOTE: for Enterprise Edition, CHECKDB respects the MAXDOP setting configured for the instance +-- https://www.sqlskills.com/blogs/erin/dbcc-checkdb-parallel-checks-and-sql-server-edition/ +SELECT o.name + ,o.schema_id + ,o.type_desc +FROM sys.dm_tran_locks l + INNER JOIN sys.objects o + ON l.resource_associated_entity_id = o.object_id +WHERE l.request_session_id = @session_id +AND l.resource_type = 'OBJECT' +AND l.resource_associated_entity_id > 50; diff --git a/database-info/table-and-index-size.sql b/database-get-table-and-index-size.sql similarity index 85% rename from database-info/table-and-index-size.sql rename to database-get-table-and-index-size.sql index 7a5c4c7..0e47a8a 100644 --- a/database-info/table-and-index-size.sql +++ b/database-get-table-and-index-size.sql @@ -1,46 +1,45 @@ - -DBCC UPDATEUSAGE(0); - -DECLARE @pgsz NUMERIC(19,10); - -SELECT @pgsz = [low] * 0.0009765625 /*KB*/ * 0.0009765625 /*MB*/ -FROM [master].dbo.spt_values -WHERE number = 1 -AND type = 'E'; - -/* -exec sp_spaceused 'ZipCode'; -exec sp_spaceused 'StatisticalArea_to_Zip'; -*/ - -DECLARE @l_DBId INT; - -SET @l_DBId = DB_ID(); - -SELECT TblId = o.object_id - , TblName = o.name - , IndxId = i.index_id - , IndxName = i.name - , DataSpaceType = d.[type] - , DataSpaceName = d.name - , [Partition] = p.partition_number - , [Compression] = p.data_compression_desc - , [Rows] = p.[rows] - , Reserved = CONVERT(NUMERIC(9,1),a.total_pages * @pgsz) - , Data = CONVERT(NUMERIC(9,1),CASE WHEN i.index_id IN(0,1) THEN a.data_pages END * @pgsz) - , Indx = CONVERT(NUMERIC(9,1),ISNULL(CASE WHEN i.index_id > 1 THEN a.data_pages END,0) * @pgsz) - , Unused = CONVERT(NUMERIC(9,1),(a.total_pages - a.used_pages) * @pgsz) -FROM sys.objects o - INNER JOIN sys.indexes i - ON o.object_id = i.object_id - INNER JOIN sys.partitions p - ON i.object_id = p.OBJECT_ID - AND i.index_id = p.index_id - INNER JOIN sys.allocation_units a - ON p.partition_id = a.container_id - INNER JOIN sys.data_spaces d - ON i.data_space_id = d.data_space_id -WHERE o.type = 'U' -AND o.is_ms_shipped = 0 -ORDER BY o.name - , i.index_id; + +--DBCC UPDATEUSAGE(0); + +DECLARE @pgsz NUMERIC(19,10); + +SELECT @pgsz = [low] * 0.0009765625 /*KB*/ * 0.0009765625 /*MB*/ +FROM [master].dbo.spt_values +WHERE number = 1 +AND type = 'E'; + +/* +exec sp_spaceused 'ZipCode'; +exec sp_spaceused 'StatisticalArea_to_Zip'; +*/ + +DECLARE @l_DBId INT; + +SET @l_DBId = DB_ID(); + +SELECT TblId = o.object_id + , TblName = o.name + , IndxId = i.index_id + , IndxName = i.name + , DataSpaceType = d.[type] + , DataSpaceName = d.name + , [Partition] = p.partition_number + , [Compression] = p.data_compression_desc + , [Rows] = p.[rows] + , Reserved = CONVERT(NUMERIC(9,1),a.total_pages * @pgsz) + , Data = CONVERT(NUMERIC(9,1),CASE WHEN i.index_id IN(0,1) THEN a.data_pages END * @pgsz) + , Indx = CONVERT(NUMERIC(9,1),ISNULL(CASE WHEN i.index_id > 1 THEN a.data_pages END,0) * @pgsz) + , Unused = CONVERT(NUMERIC(9,1),(a.total_pages - a.used_pages) * @pgsz) +FROM sys.objects o + INNER JOIN sys.indexes i + ON o.object_id = i.object_id + INNER JOIN sys.partitions p + ON i.object_id = p.OBJECT_ID + AND i.index_id = p.index_id + INNER JOIN sys.allocation_units a + ON p.partition_id = a.container_id + INNER JOIN sys.data_spaces d + ON i.data_space_id = d.data_space_id +WHERE o.type = 'U' +AND o.is_ms_shipped = 0 +ORDER BY CONVERT(NUMERIC(9,1),CASE WHEN i.index_id IN(0,1) THEN a.data_pages END * @pgsz) + CONVERT(NUMERIC(9,1),ISNULL(CASE WHEN i.index_id > 1 THEN a.data_pages END,0) * @pgsz) desc diff --git a/database-config/table-compression-estimation.sql b/database-get-table-compression-estimation.sql similarity index 96% rename from database-config/table-compression-estimation.sql rename to database-get-table-compression-estimation.sql index d749c64..d85cb3d 100644 --- a/database-config/table-compression-estimation.sql +++ b/database-get-table-compression-estimation.sql @@ -1,160 +1,160 @@ -SET NOCOUNT ON; - -DECLARE @l_Table VARCHAR(256); - ---\/\/\/ comment out to do ALL tables in db \/\/\/-- -SET @l_Table = 'ZipCode'; - -DECLARE @printOnly BIT = 0 -- change to 1 if you don't want to execute, just print commands - , @tableName VARCHAR(256) - , @schemaName VARCHAR(100) - , @sqlStatement NVARCHAR(1000) - , @tableCount INT - , @statusMsg VARCHAR(1000) - , @indexid INT - , @compressiontype CHAR(4); - -IF EXISTS(SELECT * FROM tempdb.sys.tables WHERE name LIKE '%#tables%') - DROP TABLE #tables; - -CREATE TABLE #tables -( - database_name sysname - , schemaName sysname NULL - , tableName sysname NULL - , processed bit - , reads bigint - , writes bigint - , index_id int - , indexname sysname NULL - , compressiontype AS CASE WHEN writes = 0 THEN 'PAGE' - WHEN (reads + writes) * .1 / writes < .1 THEN 'PAGE' - WHEN (reads + writes) * .1 / writes < .2 THEN 'ROW' - END -); - -IF EXISTS(SELECT * FROM tempdb.sys.tables WHERE name LIKE '%#compression%') - DROP TABLE #compressionResults; - -IF NOT EXISTS(SELECT * FROM tempdb.sys.tables WHERE name LIKE '%#compression%') -BEGIN - - CREATE TABLE #compressionResults - ( - objectName varchar(100) - , schemaName varchar(50) - , index_id int - , partition_number int - , size_current_compression bigint - , size_requested_compression bigint - , sample_current_compression bigint - , sample_requested_compression bigint - ); - -END; - -IF @l_Table IS NULL - INSERT INTO #tables - SELECT DB_NAME() - , SCHEMA_NAME(t.[schema_id]) - , t.name - , 0 -- unprocessed - , ISNULL(SUM(s.user_seeks + s.user_scans + s.user_lookups),0) - , ISNULL(SUM(s.user_updates),0) - , i.index_id - , i.name - FROM sys.tables t - INNER JOIN sys.indexes i ON t.[object_id] = i.[object_id] - INNER JOIN sys.dm_db_index_usage_stats s WITH (NOLOCK) ON i.[object_id] = s.[object_id] AND i.index_id = s.index_id - GROUP BY t.[schema_id] - , t.name - , i.index_id - , i.name; -ELSE - INSERT INTO #tables - SELECT DB_NAME() - , SCHEMA_NAME(t.[schema_id]) - , t.name - , 0 -- unprocessed - , ISNULL(SUM(s.user_seeks + s.user_scans + s.user_lookups),0) - , ISNULL(SUM(s.user_updates),0) - , i.index_id - , i.name - FROM sys.tables t - INNER JOIN sys.indexes i ON t.[object_id] = i.[object_id] - LEFT OUTER JOIN sys.dm_db_index_usage_stats s WITH (NOLOCK) ON i.[object_id] = s.[object_id] AND i.index_id = s.index_id - WHERE t.name = @l_Table - GROUP BY t.[schema_id] - , t.name - , i.index_id - , i.name; - -DELETE FROM #tables WHERE compressiontype IS NULL; - -SELECT @tableCount = COUNT(*) FROM #tables; - -WHILE EXISTS(SELECT * FROM #tables WHERE processed = 0) -BEGIN - - SELECT TOP 1 @tableName = tableName - , @schemaName = schemaName - , @indexid = index_id - , @compressiontype = compressiontype - FROM #tables WHERE processed = 0; - - SELECT @statusMsg = 'Working on ' + CAST(((@tableCount - COUNT(*)) + 1) AS VARCHAR(10)) - + ' of ' + CAST(@tableCount AS VARCHAR(10)) - FROM #tables - WHERE processed = 0; - - RAISERROR(@statusMsg, 0, 42) WITH NOWAIT; - - SET @sqlStatement = 'EXECUTE sp_estimate_data_compression_savings ''' - + @schemaName + ''', ''' + @tableName + ''', ''' + CONVERT(VARCHAR,@indexid) + ''', NULL, ''' + @compressiontype + ''';' -- ROW, PAGE, or NONE - - IF @printOnly = 1 - BEGIN - - SELECT @sqlStatement; - - END - ELSE - BEGIN - - INSERT INTO #compressionResults - EXECUTE sp_executesql @sqlStatement; - - END; - - UPDATE #tables - SET processed = 1 - WHERE tableName = @tableName - AND schemaName = @schemaName - AND @indexid = index_id; - -END; - ---SELECT * FROM #compressionResults; - -SELECT r.objectName - , t.indexname - , t.compressiontype - , r.size_current_compression / 1024.0 AS size_current_compression_MB - , r.size_requested_compression / 1024.0 AS size_requested_compression_MB - , reclaimed_MB = (r.size_current_compression-r.size_requested_compression) / 1024.0 - , t.reads - , t.writes - , CASE WHEN t.index_id < 2 THEN 'ALTER TABLE ' + '[' + t.schemaName + ']'+'.' + '[' + t.tableName + ']' + ' REBUILD WITH (DATA_COMPRESSION='+compressiontype+');' - ELSE 'ALTER INDEX '+ '[' + t.indexname + ']' + ' ON ' + '[' + t.schemaName + ']' + '.' + '[' + t.tableName + ']' + ' REBUILD WITH (DATA_COMPRESSION='+compressiontype+');' - END -FROM #compressionResults r - INNER JOIN #tables t - ON r.objectName = t.tableName - AND r.index_id = t.index_id -WHERE r.size_current_compression > r.size_requested_compression -ORDER BY r.objectName - , t.index_id; - - - - +SET NOCOUNT ON; + +DECLARE @l_Table VARCHAR(256); + +--\/\/\/ comment out to do ALL tables in db \/\/\/-- +SET @l_Table = 'TblName'; + +DECLARE @printOnly BIT = 0 -- change to 1 if you don't want to execute, just print commands + , @tableName VARCHAR(256) + , @schemaName VARCHAR(100) + , @sqlStatement NVARCHAR(1000) + , @tableCount INT + , @statusMsg VARCHAR(1000) + , @indexid INT + , @compressiontype CHAR(4); + +IF EXISTS(SELECT * FROM tempdb.sys.tables WHERE name LIKE '%#tables%') + DROP TABLE #tables; + +CREATE TABLE #tables +( + database_name sysname + , schemaName sysname NULL + , tableName sysname NULL + , processed bit + , reads bigint + , writes bigint + , index_id int + , indexname sysname NULL + , compressiontype AS CASE WHEN writes = 0 THEN 'PAGE' + WHEN (reads + writes) * .1 / writes < .1 THEN 'PAGE' + WHEN (reads + writes) * .1 / writes < .2 THEN 'ROW' + END +); + +IF EXISTS(SELECT * FROM tempdb.sys.tables WHERE name LIKE '%#compression%') + DROP TABLE #compressionResults; + +IF NOT EXISTS(SELECT * FROM tempdb.sys.tables WHERE name LIKE '%#compression%') +BEGIN + + CREATE TABLE #compressionResults + ( + objectName varchar(100) + , schemaName varchar(50) + , index_id int + , partition_number int + , size_current_compression bigint + , size_requested_compression bigint + , sample_current_compression bigint + , sample_requested_compression bigint + ); + +END; + +IF @l_Table IS NULL + INSERT INTO #tables + SELECT DB_NAME() + , SCHEMA_NAME(t.[schema_id]) + , t.name + , 0 -- unprocessed + , ISNULL(SUM(s.user_seeks + s.user_scans + s.user_lookups),0) + , ISNULL(SUM(s.user_updates),0) + , i.index_id + , i.name + FROM sys.tables t + INNER JOIN sys.indexes i ON t.[object_id] = i.[object_id] + INNER JOIN sys.dm_db_index_usage_stats s WITH (NOLOCK) ON i.[object_id] = s.[object_id] AND i.index_id = s.index_id + GROUP BY t.[schema_id] + , t.name + , i.index_id + , i.name; +ELSE + INSERT INTO #tables + SELECT DB_NAME() + , SCHEMA_NAME(t.[schema_id]) + , t.name + , 0 -- unprocessed + , ISNULL(SUM(s.user_seeks + s.user_scans + s.user_lookups),0) + , ISNULL(SUM(s.user_updates),0) + , i.index_id + , i.name + FROM sys.tables t + INNER JOIN sys.indexes i ON t.[object_id] = i.[object_id] + LEFT OUTER JOIN sys.dm_db_index_usage_stats s WITH (NOLOCK) ON i.[object_id] = s.[object_id] AND i.index_id = s.index_id + WHERE t.name = @l_Table + GROUP BY t.[schema_id] + , t.name + , i.index_id + , i.name; + +DELETE FROM #tables WHERE compressiontype IS NULL; + +SELECT @tableCount = COUNT(*) FROM #tables; + +WHILE EXISTS(SELECT * FROM #tables WHERE processed = 0) +BEGIN + + SELECT TOP 1 @tableName = tableName + , @schemaName = schemaName + , @indexid = index_id + , @compressiontype = compressiontype + FROM #tables WHERE processed = 0; + + SELECT @statusMsg = 'Working on ' + CAST(((@tableCount - COUNT(*)) + 1) AS VARCHAR(10)) + + ' of ' + CAST(@tableCount AS VARCHAR(10)) + FROM #tables + WHERE processed = 0; + + RAISERROR(@statusMsg, 0, 42) WITH NOWAIT; + + SET @sqlStatement = 'EXECUTE sp_estimate_data_compression_savings ''' + + @schemaName + ''', ''' + @tableName + ''', ''' + CONVERT(VARCHAR,@indexid) + ''', NULL, ''' + @compressiontype + ''';' -- ROW, PAGE, or NONE + + IF @printOnly = 1 + BEGIN + + SELECT @sqlStatement; + + END + ELSE + BEGIN + + INSERT INTO #compressionResults + EXECUTE sp_executesql @sqlStatement; + + END; + + UPDATE #tables + SET processed = 1 + WHERE tableName = @tableName + AND schemaName = @schemaName + AND @indexid = index_id; + +END; + +--SELECT * FROM #compressionResults; + +SELECT r.objectName + , t.indexname + , t.compressiontype + , r.size_current_compression / 1024.0 AS size_current_compression_MB + , r.size_requested_compression / 1024.0 AS size_requested_compression_MB + , reclaimed_MB = (r.size_current_compression-r.size_requested_compression) / 1024.0 + , t.reads + , t.writes + , CASE WHEN t.index_id < 2 THEN 'ALTER TABLE ' + '[' + t.schemaName + ']'+'.' + '[' + t.tableName + ']' + ' REBUILD WITH (DATA_COMPRESSION='+compressiontype+');' + ELSE 'ALTER INDEX '+ '[' + t.indexname + ']' + ' ON ' + '[' + t.schemaName + ']' + '.' + '[' + t.tableName + ']' + ' REBUILD WITH (DATA_COMPRESSION='+compressiontype+');' + END +FROM #compressionResults r + INNER JOIN #tables t + ON r.objectName = t.tableName + AND r.index_id = t.index_id +WHERE r.size_current_compression > r.size_requested_compression +ORDER BY r.objectName + , t.index_id; + + + + diff --git a/database-get-table-last-update-date.sql b/database-get-table-last-update-date.sql new file mode 100644 index 0000000..e3ae932 --- /dev/null +++ b/database-get-table-last-update-date.sql @@ -0,0 +1,12 @@ +DECLARE @DBName NVARCHAR(128) = N'DBName' + ,@TblName NVARCHAR(128) = N'TblName'; + +SELECT sqlserver_start_time +FROM sys.dm_os_sys_info; + +SELECT OBJECT_NAME(OBJECT_ID) AS TableName + ,last_user_update + ,* +FROM sys.dm_db_index_usage_stats +WHERE database_id = DB_ID(@DBName) +AND OBJECT_ID=OBJECT_ID(@TblName); diff --git a/database-get-table-size-all-dbs.sql b/database-get-table-size-all-dbs.sql new file mode 100644 index 0000000..7154726 --- /dev/null +++ b/database-get-table-size-all-dbs.sql @@ -0,0 +1,80 @@ + +DECLARE @sql_tbls VARCHAR(4000) + ,@IsHadrEnabled TINYINT = CONVERT(TINYINT,SERVERPROPERTY ('IsHadrEnabled')) + ,@RoleDesc NVARCHAR(60) = 'PRIMARY'; + +CREATE TABLE #Tbl_DataDictionary ( + DBName VARCHAR(128) + ,SchemaName VARCHAR(128) + ,TblName VARCHAR(128) + ,Rows BIGINT + ,Reserved NUMERIC(9,1) + ,Data NUMERIC(9,1) + ,Indx NUMERIC(9,1) + ,Unused NUMERIC(9,1) +); + +SET @sql_tbls = 'USE [?]; +IF DB_ID() > 4 +BEGIN +DECLARE @pgsz NUMERIC(19,10); + +SELECT @pgsz = [low] * 0.0009765625 /*KB*/ * 0.0009765625 /*MB*/ +FROM [master].dbo.spt_values +WHERE number = 1 +AND type = ''E''; + +INSERT #Tbl_DataDictionary +SELECT DBName = DB_Name() + ,SCHEMA_NAME(o.schema_id) + ,TblName = o.name + ,[Rows] = MAX(CASE WHEN i.index_id IN(0,1) THEN p.rows END) + ,Reserved = CONVERT(NUMERIC(9,1),SUM(a.total_pages) * @pgsz) + ,Data = CONVERT(NUMERIC(9,1),SUM(CASE WHEN i.index_id IN(0,1) THEN a.data_pages END) * @pgsz) + ,Indx = CONVERT(NUMERIC(9,1),ISNULL(SUM(CASE WHEN i.index_id > 1 THEN a.data_pages END),0) * @pgsz) + ,Unused = CONVERT(NUMERIC(9,1),(SUM(a.total_pages) - SUM(a.used_pages)) * @pgsz) +FROM sys.objects o + INNER JOIN sys.indexes i + ON o.object_id = i.object_id + INNER JOIN sys.partitions p + ON i.object_id = p.OBJECT_ID + AND i.index_id = p.index_id + INNER JOIN sys.allocation_units a + ON p.partition_id = a.container_id +WHERE o.type = ''U'' +AND o.is_ms_shipped = 0 +GROUP BY o.object_id + ,o.schema_id + ,o.name; +END'; + +IF @IsHadrEnabled = 0 +OR ( + @IsHadrEnabled = 1 + AND EXISTS ( + SELECT 1 + FROM sys.dm_hadr_availability_replica_states AS a + JOIN sys.availability_replicas AS b + ON b.replica_id = a.replica_id + WHERE b.replica_server_name = @@SERVERNAME + AND a.role_desc = @RoleDesc + ) +) +BEGIN + EXEC sp_MSForEachDB @sql_tbls; +END; + +SELECT @@SERVERNAME as servername + ,DEFAULT_DOMAIN() AS domain + ,DBName + ,SchemaName + ,TblName + ,Rows + ,Reserved + ,Data + ,Indx + ,Unused +FROM #Tbl_DataDictionary; + +IF OBJECT_ID('tempdb..#Tbl_DataDictionary') IS NOT NULL + DROP TABLE #Tbl_DataDictionary; diff --git a/database-info/table-size.sql b/database-get-table-size.sql similarity index 87% rename from database-info/table-size.sql rename to database-get-table-size.sql index 79a8d28..ca69d9f 100644 --- a/database-info/table-size.sql +++ b/database-get-table-size.sql @@ -1,40 +1,35 @@ - -DBCC UPDATEUSAGE(0); - -DECLARE @pgsz NUMERIC(19,10); - -SELECT @pgsz = [low] * 0.0009765625 /*KB*/ * 0.0009765625 /*MB*/ -FROM [master].dbo.spt_values -WHERE number = 1 -AND type = 'E'; - -/* -exec sp_spaceused 'ZipCode'; -exec sp_spaceused 'StatisticalArea_to_Zip'; -*/ - -DECLARE @l_DBId INT; - -SET @l_DBId = DB_ID(); - -SELECT TblId = o.object_id - , TblName = o.name - , [Rows] = MAX(CASE WHEN i.index_id IN(0,1) THEN p.rows END) - , Reserved = CONVERT(NUMERIC(9,1),SUM(a.total_pages) * @pgsz) - , Data = CONVERT(NUMERIC(9,1),SUM(CASE WHEN i.index_id IN(0,1) THEN a.data_pages END) * @pgsz) - , Indx = CONVERT(NUMERIC(9,1),ISNULL(SUM(CASE WHEN i.index_id > 1 THEN a.data_pages END),0) * @pgsz) - , Unused = CONVERT(NUMERIC(9,1),(SUM(a.total_pages) - SUM(a.used_pages)) * @pgsz) -FROM sys.objects o - INNER JOIN sys.indexes i - ON o.object_id = i.object_id - INNER JOIN sys.partitions p - ON i.object_id = p.OBJECT_ID - AND i.index_id = p.index_id - INNER JOIN sys.allocation_units a - ON p.partition_id = a.container_id -WHERE o.type = 'U' -AND o.is_ms_shipped = 0 -GROUP BY o.object_id - , o.name -ORDER BY 4 DESC - , 2; + +--DBCC UPDATEUSAGE(0); + +DECLARE @pgsz NUMERIC(19,10); + +SELECT @pgsz = [low] * 0.0009765625 /*KB*/ * 0.0009765625 /*MB*/ +FROM [master].dbo.spt_values +WHERE number = 1 +AND type = 'E'; + +DECLARE @l_DBId INT; + +SET @l_DBId = DB_ID(); + +SELECT TblId = o.object_id + , TblName = o.name + , [Rows] = MAX(CASE WHEN i.index_id IN(0,1) THEN p.rows END) + , Reserved = CONVERT(NUMERIC(9,1),SUM(a.total_pages) * @pgsz) + , Data = CONVERT(NUMERIC(9,1),SUM(CASE WHEN i.index_id IN(0,1) THEN a.data_pages END) * @pgsz) + , Indx = CONVERT(NUMERIC(9,1),ISNULL(SUM(CASE WHEN i.index_id > 1 THEN a.data_pages END),0) * @pgsz) + , Unused = CONVERT(NUMERIC(9,1),(SUM(a.total_pages) - SUM(a.used_pages)) * @pgsz) +FROM sys.objects o + INNER JOIN sys.indexes i + ON o.object_id = i.object_id + INNER JOIN sys.partitions p + ON i.object_id = p.OBJECT_ID + AND i.index_id = p.index_id + INNER JOIN sys.allocation_units a + ON p.partition_id = a.container_id +WHERE o.type = 'U' +AND o.is_ms_shipped = 0 +GROUP BY o.object_id + , o.name +ORDER BY 4 DESC + , 2; diff --git a/database-info/trigger-table-list.sql b/database-get-tables-with-triggers-list.sql similarity index 97% rename from database-info/trigger-table-list.sql rename to database-get-tables-with-triggers-list.sql index f31431b..5a1a541 100644 --- a/database-info/trigger-table-list.sql +++ b/database-get-tables-with-triggers-list.sql @@ -1,18 +1,18 @@ ---http://www.sqlfingers.com/2018/05/which-sql-server-tables-have-triggers.html - -SELECT - so.name TriggerName, - USER_NAME(so.uid) TriggerOwner, - USER_NAME(so2.uid) TableSchema, - OBJECT_NAME(so.parent_obj) TableName, - OBJECTPROPERTY( so.id, 'ExecIsUpdateTrigger') IsUpdate, - OBJECTPROPERTY( so.id, 'ExecIsDeleteTrigger') IsDelete, - OBJECTPROPERTY( so.id, 'ExecIsInsertTrigger') IsInsert, - OBJECTPROPERTY( so.id, 'ExecIsAfterTrigger') IsAfter, - OBJECTPROPERTY( so.id, 'ExecIsInsteadOfTrigger') IsInsteadOf, - OBJECTPROPERTY(so.id, 'ExecIsTriggerDisabled') IsDisabled -FROM - sysobjects so INNER JOIN sysobjects so2 - ON so.parent_obj = so2.Id -WHERE +--http://www.sqlfingers.com/2018/05/which-sql-server-tables-have-triggers.html + +SELECT + so.name TriggerName, + USER_NAME(so.uid) TriggerOwner, + USER_NAME(so2.uid) TableSchema, + OBJECT_NAME(so.parent_obj) TableName, + OBJECTPROPERTY( so.id, 'ExecIsUpdateTrigger') IsUpdate, + OBJECTPROPERTY( so.id, 'ExecIsDeleteTrigger') IsDelete, + OBJECTPROPERTY( so.id, 'ExecIsInsertTrigger') IsInsert, + OBJECTPROPERTY( so.id, 'ExecIsAfterTrigger') IsAfter, + OBJECTPROPERTY( so.id, 'ExecIsInsteadOfTrigger') IsInsteadOf, + OBJECTPROPERTY(so.id, 'ExecIsTriggerDisabled') IsDisabled +FROM + sysobjects so INNER JOIN sysobjects so2 + ON so.parent_obj = so2.Id +WHERE so.type = 'TR' \ No newline at end of file diff --git a/database-info/foreign-keys-find-not-trusted.sql b/database-get-untrusted-foreign-keys.sql similarity index 97% rename from database-info/foreign-keys-find-not-trusted.sql rename to database-get-untrusted-foreign-keys.sql index d998ecd..8723564 100644 --- a/database-info/foreign-keys-find-not-trusted.sql +++ b/database-get-untrusted-foreign-keys.sql @@ -1,21 +1,21 @@ -SELECT '[' + s.name + '].[' + o.name + '].[' + i.name + ']' AS keyname - ,'ALTER TABLE [' + o.name + '] WITH CHECK CHECK CONSTRAINT [' + i.name + '];' -FROM sys.foreign_keys i - INNER JOIN sys.objects o - ON i.parent_object_id = o.object_id - INNER JOIN sys.schemas s - ON o.schema_id = s.schema_id -WHERE i.is_not_trusted = 1 -AND i.is_not_for_replication = 0; - -SELECT '[' + s.name + '].[' + o.name + '].[' + i.name + ']' AS keyname - ,'ALTER TABLE [' + o.name + '] WITH CHECK CHECK CONSTRAINT [' + i.name + '];' -FROM sys.check_constraints i - INNER JOIN sys.objects o - ON i.parent_object_id = o.object_id - INNER JOIN sys.schemas s - ON o.schema_id = s.schema_id -WHERE i.is_not_trusted = 1 -AND i.is_not_for_replication = 0 -AND i.is_disabled = 0; - +SELECT '[' + s.name + '].[' + o.name + '].[' + i.name + ']' AS keyname + ,'ALTER TABLE [' + o.name + '] WITH CHECK CHECK CONSTRAINT [' + i.name + '];' +FROM sys.foreign_keys i + INNER JOIN sys.objects o + ON i.parent_object_id = o.object_id + INNER JOIN sys.schemas s + ON o.schema_id = s.schema_id +WHERE i.is_not_trusted = 1 +AND i.is_not_for_replication = 0; + +SELECT '[' + s.name + '].[' + o.name + '].[' + i.name + ']' AS keyname + ,'ALTER TABLE [' + o.name + '] WITH CHECK CHECK CONSTRAINT [' + i.name + '];' +FROM sys.check_constraints i + INNER JOIN sys.objects o + ON i.parent_object_id = o.object_id + INNER JOIN sys.schemas s + ON o.schema_id = s.schema_id +WHERE i.is_not_trusted = 1 +AND i.is_not_for_replication = 0 +AND i.is_disabled = 0; + diff --git a/database-info/security-find-orphan-users.sql b/database-info/security-find-orphan-users.sql deleted file mode 100644 index e83749e..0000000 --- a/database-info/security-find-orphan-users.sql +++ /dev/null @@ -1,34 +0,0 @@ -USE master; -GO - -DECLARE @SQL NVARCHAR(MAX); - -CREATE TABLE #OrphanUsers ( - DBName sysname - ,UserName sysname - ,UserSID VARBINARY(85) -); - -SET @SQL = ' -INSERT #OrphanUsers (DBName, UserName, UserSID) -SELECT DB_NAME() AS DBName - ,name AS UserName - ,sid AS UserSID -FROM sys.sysusers -WHERE issqluser = 1 -AND sid IS NOT NULL -AND sid <> 0x0 -AND LEN(sid) <= 16 -AND SUSER_SNAME(sid) IS NULL;'; - - -EXEC sys.sp_MSforeachdb @SQL; - -SELECT DBName - ,UserName - ,UserSID -FROM #OrphanUsers -ORDER BY DBName - ,UserName; - -DROP TABLE #OrphanUsers; diff --git a/database-migrate-encryption-keys.sql b/database-migrate-encryption-keys.sql new file mode 100644 index 0000000..9ccedaa --- /dev/null +++ b/database-migrate-encryption-keys.sql @@ -0,0 +1,17 @@ +create table #key_tbls (DBName VARCHAR(100), KeyName VARCHAR(100)); + +declare @sql nvarchar(max) = 'use [?]; insert #key_tbls (DBName, KeyName) select DB_NAME(), name from sys.symmetric_keys where name <> ''##MS_DatabaseMasterKey##'';' + +exec sp_MSforeachdb @sql + +select DBName, KeyName + ,'use ' + DBName + '; open master key decryption by password = ''password''; alter master key add encryption by service master key; select DBName(); exec SystemConfiguration_GetValue ''ValidationKey'';' +from #key_tbls + +/* +open master key decryption by password = 'password' + +alter master key add encryption by service master key + +exec SystemConfiguration_GetValue 'ValidationKey' +*/ diff --git a/database-relocate-files.sql b/database-relocate-files.sql new file mode 100644 index 0000000..5bcb7ef --- /dev/null +++ b/database-relocate-files.sql @@ -0,0 +1,48 @@ +--ALTER DATABASE MyDatabase SET OFFLINE; + +----move log file to E drive manually and attach from new location + +--ALTER DATABASE MyDatabase + +-- MODIFY FILE ( + +-- NAME='MyDatabase_Log', + +-- FILENAME='E:\LogFiles\MyDatabase_Log.ldf'); + +--ALTER DATABASE MyDatabase SET ONLINE; + +USE master; +GO +SET NOCOUNT ON; +GO + +DECLARE @OverrideDB sysname = 'DBName' + ,@ServerName sysname = @@SERVERNAME + ,@TargetFile varchar(200) = 'LogicalFileName' + ,@NewFilePath varchar(200) = 'Path+FileName'; + +-- create offline statement +SELECT 'ALTER DATABASE ' + name + ' SET OFFLINE;' AS OfflineDatabase +FROM sys.databases +WHERE name = @OverrideDB; + +-- create powershell move statement +SELECT 'Move-Item \\' + @ServerName + '\' + REPLACE(physical_name,':','$') + + ' \\' + @ServerName + '\' + REPLACE(@NewFilePath,':','$') AS PowerShellMoveScript +FROM sys.master_files +WHERE @OverrideDB = DB_NAME(database_id) +AND @TargetFile = name; + +-- create alter statement +SELECT 'ALTER DATABASE ' + DB_NAME(database_id) + ' + MODIFY FILE ( NAME = ''' + name + ''' + ,FILENAME = ''' + @NewFilePath + ''');' +FROM sys.master_files +WHERE @OverrideDB = DB_NAME(database_id) +AND @TargetFile = name; + +-- create online statement +SELECT 'ALTER DATABASE ' + name + ' SET ONLINE;' AS OnlineDatabase +FROM sys.databases +WHERE name = @OverrideDB; diff --git a/database-config/synonym-remap.sql b/database-remap-synonyms.sql similarity index 96% rename from database-config/synonym-remap.sql rename to database-remap-synonyms.sql index 306cd02..b8a4c5b 100644 --- a/database-config/synonym-remap.sql +++ b/database-remap-synonyms.sql @@ -1,12 +1,12 @@ -USE [?]; - -DECLARE @l_SQL NVARCHAR(MAX) = '' - ,@l_TargetDB NVARCHAR(1035) = '%MCM_ETL%'; - -SELECT @l_SQL += N'DROP SYNONYM dbo.' + name + N'; CREATE SYNONYM dbo.' + name + N' FOR RPRMBSSQLVS2.' - + base_object_name + N';' -FROM sys.synonyms -WHERE base_object_name LIKE @l_TargetDB; - -EXEC sys.sp_executesql @l_SQL; - +USE [?]; + +DECLARE @l_SQL NVARCHAR(MAX) = '' + ,@l_TargetDB NVARCHAR(1035) = '%MCM_ETL%'; + +SELECT @l_SQL += N'DROP SYNONYM dbo.' + name + N'; CREATE SYNONYM dbo.' + name + N' FOR RPRMBSSQLVS2.' + + base_object_name + N';' +FROM sys.synonyms +WHERE base_object_name LIKE @l_TargetDB; + +EXEC sys.sp_executesql @l_SQL; + diff --git a/database-config/log-file-VLF-resize.sql b/database-resize-log-file-VLFs.sql similarity index 96% rename from database-config/log-file-VLF-resize.sql rename to database-resize-log-file-VLFs.sql index 777a834..6c922f3 100644 --- a/database-config/log-file-VLF-resize.sql +++ b/database-resize-log-file-VLFs.sql @@ -1,33 +1,33 @@ -USE [?] -GO - --- Step 1 --- run and then paste shrink and resize stmts into Step 2 -select name - , CurrentSize_MB = CONVERT(BIGINT,size)*8/1024 - , ShrinkLog = 'DBCC SHRINKFILE (' + name + ', 0)' - , ResizeLog = 'ALTER DATABASE ' + DB_NAME() + ' MODIFY FILE (NAME = ''' + name + ''', SIZE = ' - + CASE WHEN CONVERT(BIGINT,size)*8/1024. < 1024 THEN CONVERT(VARCHAR(10),CONVERT(BIGINT,size)*8/1024)+ 'MB)' - WHEN CONVERT(BIGINT,size)*8/1024. >= 1024 THEN CONVERT(VARCHAR(10),CONVERT(BIGINT,size)*8/1024/1024)+ 'GB)' - END - , Used_MB = CONVERT(BIGINT, FILEPROPERTY(name, 'SpaceUsed'))*8/1024 -from sys.master_files -where database_id = DB_ID() -AND type_desc = 'LOG'; -GO - - --- Step 2 -DBCC LogInfo -GO -CHECKPOINT -GO --- COPY 'ShrinkLog' HERE -- - -GO --- COPY 'ResizeLog' HERE -- --- if > 8 GB then break into 8 GB expansions - -GO -DBCC LogInfo -GO +USE [?] +GO + +-- Step 1 +-- run and then paste shrink and resize stmts into Step 2 +select name + , CurrentSize_MB = CONVERT(BIGINT,size)*8/1024 + , ShrinkLog = 'DBCC SHRINKFILE (' + name + ', 0)' + , ResizeLog = 'ALTER DATABASE ' + DB_NAME() + ' MODIFY FILE (NAME = ''' + name + ''', SIZE = ' + + CASE WHEN CONVERT(BIGINT,size)*8/1024. < 1024 THEN CONVERT(VARCHAR(10),CONVERT(BIGINT,size)*8/1024)+ 'MB)' + WHEN CONVERT(BIGINT,size)*8/1024. >= 1024 THEN CONVERT(VARCHAR(10),CONVERT(BIGINT,size)*8/1024/1024)+ 'GB)' + END + , Used_MB = CONVERT(BIGINT, FILEPROPERTY(name, 'SpaceUsed'))*8/1024 +from sys.master_files +where database_id = DB_ID() +AND type_desc = 'LOG'; +GO + + +-- Step 2 +DBCC LogInfo +GO +CHECKPOINT +GO +-- COPY 'ShrinkLog' HERE -- + +GO +-- COPY 'ResizeLog' HERE -- +-- if > 8 GB then break into 8 GB expansions + +GO +DBCC LogInfo +GO diff --git a/database-revoke-connect-permissions.sql b/database-revoke-connect-permissions.sql new file mode 100644 index 0000000..f29f2fa --- /dev/null +++ b/database-revoke-connect-permissions.sql @@ -0,0 +1,10 @@ +USE [?]; + +SELECT 'REVOKE CONNECT FROM [' + name + '];' + ,'GRANT CONNECT FROM [' + name + '];' +FROM sys.sysusers +WHERE islogin = 1 +AND hasdbaccess = 1 +AND name <> 'dbo'; + + diff --git a/database-info/foreign-keys-find-and-script-missing.sql b/database-script-missing-foreign-keys.sql similarity index 97% rename from database-info/foreign-keys-find-and-script-missing.sql rename to database-script-missing-foreign-keys.sql index b8665e3..6afc865 100644 --- a/database-info/foreign-keys-find-and-script-missing.sql +++ b/database-script-missing-foreign-keys.sql @@ -1,89 +1,89 @@ -SELECT CONCAT(S.name, '.', O.name) AS BaseTable - ,C.name AS BaseColumn - ,CONCAT(S2.name, '.', O2.name) AS ReferenceTable - ,CONCAT( - 'alter table ', S.name, '.', O.name, ' with check add constraint FK_', O.name, '_', O2.name - ,' foreign key (', C.name, ') references ', S2.name, '.', O2.name, '(' + IDC.name + ')' - ) AS FKCreateStatement -FROM sys.columns C - INNER JOIN sys.identity_columns IDC - ON (IDC.name = C.name OR C.name = OBJECT_NAME(IDC.object_id) + IDC.name) - AND C.object_id <> IDC.object_id - AND C.is_identity = 0 --exlude Columns which are identities - INNER JOIN sys.objects O - ON O.object_id = C.object_id - AND O.is_ms_shipped = 0 - AND O.type = 'u' - INNER JOIN sys.schemas S - ON S.schema_id = O.schema_id - INNER JOIN sys.objects O2 - ON O2.object_id = IDC.object_id - AND O2.is_ms_shipped = 0 - AND O2.type = 'u' - INNER JOIN sys.schemas S2 - ON S2.schema_id = O2.schema_id - LEFT JOIN sys.foreign_key_columns FKC - ON IDC.object_id = FKC.referenced_object_id - AND FKC.referenced_column_id = IDC.column_id - INNER JOIN - ( - SELECT I.object_id - ,IC.index_id - FROM sys.index_columns IC - INNER JOIN sys.indexes I - ON I.object_id = IC.object_id - AND I.index_id = IC.index_id - WHERE I.is_primary_key = 1 - GROUP BY I.object_id - ,IC.index_id - HAVING COUNT(*) = 1 - ) SingleColumnPK - ON IDC.object_id = SingleColumnPK.object_id -WHERE FKC.referenced_object_id IS NULL -AND C.name <> 'ID' -ORDER BY 1; - - -SELECT (S.name + '.' + O.name) AS BaseTable - ,C.name AS BaseColumn - ,(S2.name + '.' + O2.name) AS ReferenceTable - ,('alter table ' + S.name + '.' + O.name + ' with check add constraint FK_' + O.name + '_' + O2.name - + ' foreign key (' + C.name + ') references ' + S2.name + '.' + O2.name + '(' + IDC.name + ')' - ) AS FKCreateStatement -FROM sys.columns C - INNER JOIN sys.identity_columns IDC - ON (IDC.name = C.name OR C.name = OBJECT_NAME(IDC.object_id) + IDC.name) - AND C.object_id <> IDC.object_id - AND C.is_identity = 0 --exlude Columns which are identities - INNER JOIN sys.objects O - ON O.object_id = C.object_id - AND O.is_ms_shipped = 0 - AND O.type = 'u' - INNER JOIN sys.schemas S - ON S.schema_id = O.schema_id - INNER JOIN sys.objects O2 - ON O2.object_id = IDC.object_id - AND O2.is_ms_shipped = 0 - AND O2.type = 'u' - INNER JOIN sys.schemas S2 - ON S2.schema_id = O2.schema_id - LEFT JOIN sys.foreign_key_columns FKC - ON IDC.object_id = FKC.referenced_object_id - AND FKC.referenced_column_id = IDC.column_id - INNER JOIN - ( - SELECT I.object_id - ,IC.index_id - FROM sys.index_columns IC - INNER JOIN sys.indexes I - ON I.object_id = IC.object_id - AND I.index_id = IC.index_id - WHERE I.is_primary_key = 1 - GROUP BY I.object_id - ,IC.index_id - HAVING COUNT(*) = 1 - ) SingleColumnPK - ON IDC.object_id = SingleColumnPK.object_id -WHERE FKC.referenced_object_id IS NULL -AND C.name <> 'ID' +SELECT CONCAT(S.name, '.', O.name) AS BaseTable + ,C.name AS BaseColumn + ,CONCAT(S2.name, '.', O2.name) AS ReferenceTable + ,CONCAT( + 'alter table ', S.name, '.', O.name, ' with check add constraint FK_', O.name, '_', O2.name + ,' foreign key (', C.name, ') references ', S2.name, '.', O2.name, '(' + IDC.name + ')' + ) AS FKCreateStatement +FROM sys.columns C + INNER JOIN sys.identity_columns IDC + ON (IDC.name = C.name OR C.name = OBJECT_NAME(IDC.object_id) + IDC.name) + AND C.object_id <> IDC.object_id + AND C.is_identity = 0 --exlude Columns which are identities + INNER JOIN sys.objects O + ON O.object_id = C.object_id + AND O.is_ms_shipped = 0 + AND O.type = 'u' + INNER JOIN sys.schemas S + ON S.schema_id = O.schema_id + INNER JOIN sys.objects O2 + ON O2.object_id = IDC.object_id + AND O2.is_ms_shipped = 0 + AND O2.type = 'u' + INNER JOIN sys.schemas S2 + ON S2.schema_id = O2.schema_id + LEFT JOIN sys.foreign_key_columns FKC + ON IDC.object_id = FKC.referenced_object_id + AND FKC.referenced_column_id = IDC.column_id + INNER JOIN + ( + SELECT I.object_id + ,IC.index_id + FROM sys.index_columns IC + INNER JOIN sys.indexes I + ON I.object_id = IC.object_id + AND I.index_id = IC.index_id + WHERE I.is_primary_key = 1 + GROUP BY I.object_id + ,IC.index_id + HAVING COUNT(*) = 1 + ) SingleColumnPK + ON IDC.object_id = SingleColumnPK.object_id +WHERE FKC.referenced_object_id IS NULL +AND C.name <> 'ID' +ORDER BY 1; + + +SELECT (S.name + '.' + O.name) AS BaseTable + ,C.name AS BaseColumn + ,(S2.name + '.' + O2.name) AS ReferenceTable + ,('alter table ' + S.name + '.' + O.name + ' with check add constraint FK_' + O.name + '_' + O2.name + + ' foreign key (' + C.name + ') references ' + S2.name + '.' + O2.name + '(' + IDC.name + ')' + ) AS FKCreateStatement +FROM sys.columns C + INNER JOIN sys.identity_columns IDC + ON (IDC.name = C.name OR C.name = OBJECT_NAME(IDC.object_id) + IDC.name) + AND C.object_id <> IDC.object_id + AND C.is_identity = 0 --exlude Columns which are identities + INNER JOIN sys.objects O + ON O.object_id = C.object_id + AND O.is_ms_shipped = 0 + AND O.type = 'u' + INNER JOIN sys.schemas S + ON S.schema_id = O.schema_id + INNER JOIN sys.objects O2 + ON O2.object_id = IDC.object_id + AND O2.is_ms_shipped = 0 + AND O2.type = 'u' + INNER JOIN sys.schemas S2 + ON S2.schema_id = O2.schema_id + LEFT JOIN sys.foreign_key_columns FKC + ON IDC.object_id = FKC.referenced_object_id + AND FKC.referenced_column_id = IDC.column_id + INNER JOIN + ( + SELECT I.object_id + ,IC.index_id + FROM sys.index_columns IC + INNER JOIN sys.indexes I + ON I.object_id = IC.object_id + AND I.index_id = IC.index_id + WHERE I.is_primary_key = 1 + GROUP BY I.object_id + ,IC.index_id + HAVING COUNT(*) = 1 + ) SingleColumnPK + ON IDC.object_id = SingleColumnPK.object_id +WHERE FKC.referenced_object_id IS NULL +AND C.name <> 'ID' ORDER BY 1; \ No newline at end of file diff --git a/error-log-query-using-fn_dblog.sql b/error-log-query-using-fn_dblog.sql new file mode 100644 index 0000000..6f77c91 --- /dev/null +++ b/error-log-query-using-fn_dblog.sql @@ -0,0 +1,5 @@ +SELECT [Operation], COUNT(*) + FROM sys.fn_dblog(NULL, NULL) + GROUP BY [Operation] + ORDER BY [Operation]; + \ No newline at end of file diff --git a/server-info/error-log-view-using-xp_readerrorlog.sql b/error-log-query-using-xp_readerrorlog.sql similarity index 95% rename from server-info/error-log-view-using-xp_readerrorlog.sql rename to error-log-query-using-xp_readerrorlog.sql index 31a026f..8aad1ec 100644 --- a/server-info/error-log-view-using-xp_readerrorlog.sql +++ b/error-log-query-using-xp_readerrorlog.sql @@ -1,23 +1,23 @@ -DECLARE @ArchiveID INT --Value of error log file you want to read: 0 = current, 1 = Archive #1, 2 = Archive #2, etc... - ,@LogFileType INT --Log file type: 1 or NULL = error log, 2 = SQL Agent log - ,@Filter1Text NVARCHAR(4000) --Search string 1: String one you want to search for - ,@Filter2Text NVARCHAR(4000) --Search string 2: String two you want to search for to further refine the results - ,@FirstEntry DATETIME --Search from start time - ,@LastEntry DATETIME --Search to end time - ,@SortOrder NVARCHAR(4000); --Sort order for results: N'asc' = ascending, N'desc' = descending - -SELECT @ArchiveID = 0 - ,@LogFileType = 1 - ,@Filter1Text = NULL - ,@Filter2Text = NULL - ,@FirstEntry = NULL - ,@LastEntry = NULL - ,@SortOrder = N'asc'; - -EXEC master.sys.xp_readerrorlog @ArchiveID - ,@LogFileType - ,@Filter1Text - ,@Filter2Text - ,@FirstEntry - ,@LastEntry - ,@SortOrder; +DECLARE @ArchiveID INT --Value of error log file you want to read: 0 = current, 1 = Archive #1, 2 = Archive #2, etc... + ,@LogFileType INT --Log file type: 1 or NULL = error log, 2 = SQL Agent log + ,@Filter1Text NVARCHAR(4000) --Search string 1: String one you want to search for + ,@Filter2Text NVARCHAR(4000) --Search string 2: String two you want to search for to further refine the results + ,@FirstEntry DATETIME --Search from start time + ,@LastEntry DATETIME --Search to end time + ,@SortOrder NVARCHAR(4000); --Sort order for results: N'asc' = ascending, N'desc' = descending + +SELECT @ArchiveID = 0 + ,@LogFileType = 1 + ,@Filter1Text = 'SomeText' + ,@Filter2Text = NULL + ,@FirstEntry = NULL + ,@LastEntry = NULL + ,@SortOrder = N'asc'; + +EXEC master.sys.xp_readerrorlog @ArchiveID + ,@LogFileType + ,@Filter1Text + ,@Filter2Text + ,@FirstEntry + ,@LastEntry + ,@SortOrder; diff --git a/execute-as.sql b/execute-as.sql new file mode 100644 index 0000000..d02e707 --- /dev/null +++ b/execute-as.sql @@ -0,0 +1,20 @@ + +--Display current execution context +SELECT SUSER_NAME(), USER_NAME(); + +--Scope of impersonation is at the server level +EXECUTE AS LOGIN = 'SomeLogin'; +----Scope of impersonation is restricted to the current database +--EXECUTE AS USER = 'SomeLogin'; + +--Display current execution context +SELECT SUSER_NAME(), USER_NAME(); + +--Command to be ran under impersonation +[COPY COMMAND HERE] + +--Reset the execution context +REVERT; + +--Display current execution context +SELECT SUSER_NAME(), USER_NAME(); diff --git a/extended-events-get-deadlock-report.sql b/extended-events-get-deadlock-report.sql new file mode 100644 index 0000000..5799de7 --- /dev/null +++ b/extended-events-get-deadlock-report.sql @@ -0,0 +1,27 @@ +--Extracting Deadlock information using SYSTEM_HEALTH Extended Events +--https://www.sqlservercentral.com/blogs/extracting-deadlock-information-using-system_health-extended-events +CREATE TABLE #errorlog ( + LogDate DATETIME + , ProcessInfo VARCHAR(100) + , [Text] VARCHAR(MAX) +); + +DECLARE @tag VARCHAR (MAX) + ,@path VARCHAR(MAX) + ,@DateTimeOffset INT = DATEDIFF(HOUR,GETUTCDATE(),GETDATE()); + +INSERT INTO #errorlog EXEC sp_readerrorlog; + +SELECT @tag = [Text] +FROM #errorlog +WHERE [Text] LIKE 'Logging%MSSQL\Log%'; + +DROP TABLE IF EXISTS #errorlog; + +SET @path = SUBSTRING(@tag, 38, CHARINDEX('MSSQL\Log', @tag) - 29); + +SELECT CONVERT(xml, event_data).query('/event/data/value/child::*') AS DeadlockReport + ,DATEADD(HOUR,@DateTimeOffset,CONVERT(xml, event_data).value('(event[@name="xml_deadlock_report"]/@timestamp)[1]', 'datetime')) AS Execution_Time +FROM sys.fn_xe_file_target_read_file (@path + '\system_health*.xel', NULL, NULL, NULL) +WHERE OBJECT_NAME like 'xml_deadlock_report' +ORDER BY Execution_Time DESC; diff --git a/get-blocking-info.sql b/get-blocking-info.sql new file mode 100644 index 0000000..768bdd5 --- /dev/null +++ b/get-blocking-info.sql @@ -0,0 +1,416 @@ +--IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND object_id = object_id('dbo.Check_Blocking')) +-- EXEC ('CREATE PROCEDURE dbo.Check_Blocking AS SELECT ''This is a stub''') +--GO + +--ALTER PROCEDURE dbo.Check_Blocking +DECLARE + @BlockingDurationThreshold smallint = 60, + @BlockedSessionThreshold smallint = NULL +--AS +/************************************************************************************************* +AUTHOR: Andy Mallon +CREATED: 20141218 +PARAMETERS +* @BlockingDurationThreshold - seconds - Shows blocked sessions that have been waiting longer than this many seconds. +* @BlockedSessionThreshold - Shows blocking only when the number of blocked sessions is this number or higher. +************************************************************************************************** +MODIFICATIONS: + 20141222 - AM2 - Parse out the Hex jobid in ProgramName & turn into the Job Name. + 20141229 - AM2 - Parse out current SqlStatement from the complete SqlText. + - Start including SqlStatement in the email instead of SqlText + - I now have 3 different answers to "What is the current SQL?" + 1) SqlText - This is the full output from sys.dm_exec_sql_text(). + - If a procedure is running, this will be the CREATE PROCEDURE statement. + 2) SqlStatement - Uses Statement offset values to determine specific line from SqlText + - If a procedure is running, this is the specific statement within that proc + 3) InputBuffer - This is the output from DBCC INPUTBUFFER + - If a procedure is running, this is the EXEC statement + 20171208 - AM2 - Add some functionality so that I can alert on number of sessions blocked. + 20171210 - AM2 - Add Debug Mode = 2 to return the Email Body as a chunk of HTML instead of emailing it. +************************************************************************************************** + This code is licensed under the GNU GPL, as part of Andy Mallon's DBA Database. + https://github.com/amtwo/dba-database/blob/master/LICENSE + ©2014-2019 â— Andy Mallon â— am2.co + Source: https://github.com/amtwo/dba-database/blob/master/stored-procedures/dbo.Check_Blocking.sql +*************************************************************************************************/ +SET NOCOUNT ON; +--READ UNCOMMITTED, since we're dealing with blocking, we don't want to make things worse. +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; + +---Sure, it would work if you supplied both, but the ANDing of those gets confusing to people, so easier to just do this. +IF ((@BlockingDurationThreshold IS NOT NULL AND @BlockedSessionThreshold IS NOT NULL) + OR COALESCE(@BlockingDurationThreshold, @BlockedSessionThreshold) IS NULL) +BEGIN + RAISERROR('Must supply either @BlockingDurationThreshold or @BlockedSessionThreshold (but not both).',16,1); +END; + + +DECLARE @Id int = 1, + @Spid int = 0, + @JobIdHex nvarchar(34), + @JobName nvarchar(256), + @WaitResource nvarchar(256), + @DbName nvarchar(256), + @ObjectName nvarchar(256), + @IndexName nvarchar(256), + @Sql nvarchar(max); + +DROP TABLE IF EXISTS #Blocked; +DROP TABLE IF EXISTS #InputBuffer; +DROP TABLE IF EXISTS #LeadingBlocker; + +CREATE TABLE #Blocked ( + ID int identity(1,1) PRIMARY KEY, + WaitingSpid smallint, + BlockingSpid smallint, + LeadingBlocker smallint, + BlockingChain nvarchar(4000), + DbName sysname, + HostName nvarchar(128), + ProgramName nvarchar(128), + LoginName nvarchar(128), + LoginTime datetime2(3), + LastRequestStart datetime2(3), + LastRequestEnd datetime2(3), + TransactionCnt int, + Command nvarchar(32), + WaitTime int, + WaitResource nvarchar(256), + WaitDescription nvarchar(1000), + SqlText nvarchar(max), + SqlStatement nvarchar(max), + InputBuffer nvarchar(4000), + SessionInfo XML, + ); + +CREATE TABLE #InputBuffer ( + EventType nvarchar(30), + Params smallint, + EventInfo nvarchar(4000) + ); + +CREATE TABLE #LeadingBlocker ( + Id int identity(1,1) PRIMARY KEY, + LeadingBlocker smallint, + BlockedSpidCount int, + DbName sysname, + HostName nvarchar(128), + ProgramName nvarchar(128), + LoginName nvarchar(128), + LoginTime datetime2(3), + LastRequestStart datetime2(3), + LastRequestEnd datetime2(3), + TransactionCnt int, + Command nvarchar(32), + WaitTime int, + WaitResource nvarchar(256), + WaitDescription nvarchar(1000), + SqlText nvarchar(max), + SqlStatement nvarchar(max), + InputBuffer nvarchar(4000), + SessionInfo xml, + ); + + +--Grab all sessions involved in Blocking (both blockers & waiters) + +INSERT INTO #Blocked (WaitingSpid, BlockingSpid, DbName, HostName, ProgramName, LoginName, LoginTime, LastRequestStart, + LastRequestEnd, TransactionCnt, Command, WaitTime, WaitResource, SqlText, SqlStatement) +-- WAITERS +SELECT s.session_id AS WaitingSpid, + r.blocking_session_id AS BlockingSpid, + db_name(r.database_id) AS DbName, + s.host_name AS HostName, + s.program_name AS ProgramName, + s.login_name AS LoginName, + s.login_time AS LoginTime, + s.last_request_start_time AS LastRequestStart, + s.last_request_end_time AS LastRequestEnd, + -- Need to use sysprocesses for now until we're fully on 2012/2014 + (SELECT TOP 1 sp.open_tran FROM master.sys.sysprocesses sp WHERE sp.spid = s.session_id) AS TransactionCnt, + --s.open_transaction_count AS TransactionCnt, + r.command AS Command, + r.wait_time AS WaitTime, + r.wait_resource AS WaitResource, + COALESCE(t.text,'') AS SqlText, + COALESCE(SUBSTRING(t.text, (r.statement_start_offset/2)+1, ( + (CASE r.statement_end_offset + WHEN -1 THEN DATALENGTH(t.text) + ELSE r.statement_end_offset + END - r.statement_start_offset) + /2) + 1),'') AS SqlStatement +FROM sys.dm_exec_sessions s +INNER JOIN sys.dm_exec_requests r ON r.session_id = s.session_id +OUTER APPLY sys.dm_exec_sql_text (r.sql_handle) t +WHERE r.blocking_session_id <> 0 --Blocked +AND r.wait_time >= COALESCE(@BlockingDurationThreshold,0)*1000 +UNION +-- BLOCKERS +SELECT s.session_id AS WaitingSpid, + COALESCE(r.blocking_session_id,0) AS BlockingSpid, + COALESCE(db_name(r.database_id),'') AS DbName, + s.host_name AS HostName, + s.program_name AS ProgramName, + s.login_name AS LoginName, + s.login_time AS LoginTime, + s.last_request_start_time AS LastRequestStart, + s.last_request_end_time AS LastRequestEnd, + -- Need to use sysprocesses for now until we're fully on 2012/2014 + (SELECT TOP 1 sp.open_tran FROM master.sys.sysprocesses sp WHERE sp.spid = s.session_id) AS TransactionCnt, + --s.open_transaction_count AS TransactionCnt, + COALESCE(r.command,'') AS Command, + COALESCE(r.wait_time,'') AS WaitTime, + COALESCE(r.wait_resource,'') AS WaitResource, + COALESCE(t.text,'') AS SqlText, + COALESCE(SUBSTRING(t.text, (r.statement_start_offset/2)+1, ( + (CASE r.statement_end_offset + WHEN -1 THEN DATALENGTH(t.text) + ELSE r.statement_end_offset + END - r.statement_start_offset) + /2) + 1),'') AS SqlStatement +FROM sys.dm_exec_sessions s +LEFT JOIN sys.dm_exec_requests r ON r.session_id = s.session_id +OUTER APPLY sys.dm_exec_sql_text (r.sql_handle) t +WHERE s.session_id IN (SELECT blocking_session_id FROM sys.dm_exec_requests ) --Blockers +AND COALESCE(r.blocking_session_id,0) = 0; --Not blocked + + +-- Grab the input buffer for all sessions, too. +WHILE EXISTS (SELECT 1 FROM #Blocked WHERE InputBuffer IS NULL) +BEGIN + TRUNCATE TABLE #InputBuffer; + + SELECT TOP 1 @Spid = WaitingSpid, @ID = ID + FROM #Blocked + WHERE InputBuffer IS NULL; + + SET @Sql = 'DBCC INPUTBUFFER (' + CAST(@Spid AS varchar(10)) + ');'; + + BEGIN TRY + INSERT INTO #InputBuffer + EXEC sp_executesql @sql; + END TRY + BEGIN CATCH + PRINT 'InputBuffer Failed'; + END CATCH + + --SELECT @id, @Spid, COALESCE((SELECT TOP 1 EventInfo FROM #InputBuffer),'') + --EXEC sp_executesql @sql; + + UPDATE b + SET InputBuffer = COALESCE((SELECT TOP 1 EventInfo FROM #InputBuffer),'') + FROM #Blocked b + WHERE ID = @Id; +END; + +--Convert Hex job_ids for SQL Agent jobs to names. +WHILE EXISTS(SELECT 1 FROM #Blocked WHERE ProgramName LIKE 'SQLAgent - TSQL JobStep (Job 0x%') +BEGIN + SELECT @JobIdHex = '', @JobName = ''; + + SELECT TOP 1 @ID = ID, + @JobIdHex = SUBSTRING(ProgramName,30,34) + FROM #Blocked + WHERE ProgramName LIKE 'SQLAgent - TSQL JobStep (Job 0x%'; + + SELECT @Sql = N'SELECT @JobName = name FROM msdb.dbo.sysjobs WHERE job_id = ' + @JobIdHex; + EXEC sp_executesql @Sql, N'@JobName nvarchar(256) OUT', @JobName = @JobName OUT; + + UPDATE b + SET ProgramName = LEFT(REPLACE(ProgramName,@JobIdHex,@JobName),128) + FROM #Blocked b + WHERE ID = @Id; +END; + +--Decypher wait resources. +DECLARE wait_cur CURSOR FOR + SELECT WaitingSpid, WaitResource FROM #Blocked WHERE WaitResource <> ''; + +OPEN wait_cur; +FETCH NEXT FROM wait_cur INTO @Spid, @WaitResource; +WHILE @@FETCH_STATUS = 0 +BEGIN + IF @WaitResource LIKE 'KEY%' + BEGIN + --Decypher DB portion of wait resource + SET @WaitResource = LTRIM(REPLACE(@WaitResource,'KEY:','')); + SET @DbName = db_name(SUBSTRING(@WaitResource,0,CHARINDEX(':',@WaitResource))); + --now get the object name + SET @WaitResource = SUBSTRING(@WaitResource,CHARINDEX(':',@WaitResource)+1,256); + SELECT @Sql = 'SELECT @ObjectName = SCHEMA_NAME(o.schema_id) + ''.'' + o.name, @IndexName = i.name ' + + 'FROM [' + @DbName + '].sys.partitions p ' + + 'JOIN [' + @DbName + '].sys.objects o ON p.OBJECT_ID = o.OBJECT_ID ' + + 'JOIN [' + @DbName + '].sys.indexes i ON p.OBJECT_ID = i.OBJECT_ID AND p.index_id = i.index_id ' + + 'WHERE p.hobt_id = SUBSTRING(@WaitResource,0,CHARINDEX('' '',@WaitResource))' + EXEC sp_executesql @sql,N'@WaitResource nvarchar(256),@ObjectName nvarchar(256) OUT,@IndexName nvarchar(256) OUT', + @WaitResource = @WaitResource, @ObjectName = @ObjectName OUT, @IndexName = @IndexName OUT + --now populate the WaitDescription column + UPDATE b + SET WaitDescription = 'KEY WAIT: ' + @DbName + '.' + @ObjectName + ' (' + COALESCE(@IndexName,'') + ')' + FROM #Blocked b + WHERE WaitingSpid = @Spid; + END; + ELSE IF @WaitResource LIKE 'OBJECT%' + BEGIN + --Decypher DB portion of wait resource + SET @WaitResource = LTRIM(REPLACE(@WaitResource,'OBJECT:','')); + SET @DbName = db_name(SUBSTRING(@WaitResource,0,CHARINDEX(':',@WaitResource))); + --now get the object name + SET @WaitResource = SUBSTRING(@WaitResource,CHARINDEX(':',@WaitResource)+1,256); + SET @Sql = 'SELECT @ObjectName = schema_name(schema_id) + ''.'' + name FROM [' + @DbName + '].sys.objects WHERE object_id = SUBSTRING(@WaitResource,0,CHARINDEX('':'',@WaitResource))'; + EXEC sp_executesql @sql,N'@WaitResource nvarchar(256),@ObjectName nvarchar(256) OUT',@WaitResource = @WaitResource, @ObjectName = @ObjectName OUT; + --Now populate the WaitDescription column + UPDATE b + SET WaitDescription = 'OBJECT WAIT: ' + @DbName + '.' + @ObjectName + FROM #Blocked b + WHERE WaitingSpid = @Spid; + END; + ELSE IF (@WaitResource LIKE 'PAGE%' OR @WaitResource LIKE 'RID%') + BEGIN + --Decypher DB portion of wait resource + SELECT @WaitResource = LTRIM(REPLACE(@WaitResource,'PAGE:','')); + SELECT @WaitResource = LTRIM(REPLACE(@WaitResource,'RID:','')); + SET @DbName = db_name(SUBSTRING(@WaitResource,0,CHARINDEX(':',@WaitResource))); + --now get the file name + SET @WaitResource = SUBSTRING(@WaitResource,CHARINDEX(':',@WaitResource)+1,256) + SELECT @ObjectName = name + FROM sys.master_files + WHERE database_id = db_id(@DbName) + AND file_id = SUBSTRING(@WaitResource,0,CHARINDEX(':',@WaitResource)); + --Now populate the WaitDescription column + SET @WaitResource = SUBSTRING(@WaitResource,CHARINDEX(':',@WaitResource)+1,256) + IF @WaitResource LIKE '%:%' + BEGIN + UPDATE b + SET WaitDescription = 'ROW WAIT: ' + @DbName + ' File: ' + @ObjectName + ' Page_id/Slot: ' + @WaitResource + FROM #Blocked b + WHERE WaitingSpid = @Spid; + END; + ELSE + BEGIN + UPDATE b + SET WaitDescription = 'PAGE WAIT: ' + @DbName + ' File: ' + @ObjectName + ' Page_id: ' + @WaitResource + FROM #Blocked b + WHERE WaitingSpid = @Spid; + END; + END; + FETCH NEXT FROM wait_cur INTO @Spid, @WaitResource; +END; +CLOSE wait_cur; +DEALLOCATE wait_cur; + + +--Move the LEADING blockers out to their own table. +INSERT INTO #LeadingBlocker (LeadingBlocker, DbName, HostName, ProgramName, LoginName, LoginTime, LastRequestStart, LastRequestEnd, + TransactionCnt, Command, WaitTime, WaitResource, WaitDescription, SqlText, SqlStatement, InputBuffer) +SELECT WaitingSpid, DbName, HostName, ProgramName, LoginName, LoginTime, LastRequestStart, LastRequestEnd, + TransactionCnt, Command, WaitTime, WaitResource, WaitDescription, SqlText, SqlStatement, InputBuffer +FROM #Blocked b +WHERE BlockingSpid = 0 +AND EXISTS (SELECT 1 FROM #Blocked b1 WHERE b1.BlockingSpid = b.WaitingSpid); + +DELETE FROM #Blocked WHERE BlockingSpid = 0; + +--Update #Blocked to include LeadingBlocker & BlockingChain +WITH BlockingChain AS ( + SELECT LeadingBlocker AS Spid, + CAST(0 AS smallint) AS Blocker, + CAST(LeadingBlocker AS nvarchar(4000)) AS BlockingChain, + LeadingBlocker AS LeadingBlocker + FROM #LeadingBlocker + UNION ALL + SELECT b.WaitingSpid AS Spid, + b.BlockingSpid AS Blocker, + RIGHT((CAST(b.WaitingSpid AS nvarchar(10)) + N' ' + CHAR(187) + N' ' + bc.BlockingChain),4000) AS BlockingChain, + bc.LeadingBlocker + FROM #Blocked b + JOIN BlockingChain bc ON bc.Spid = b.BlockingSpid + ) +UPDATE b +SET LeadingBlocker = bc.LeadingBlocker, + BlockingChain = bc.BlockingChain +FROM #Blocked b +JOIN BlockingChain bc ON b.WaitingSpid = bc.Spid; + +-- Populate BlockedSpidCount for #LeadingBlocker +UPDATE lb +SET BlockedSpidCount = cnt.BlockedSpidCount +FROM #LeadingBlocker lb +JOIN (SELECT LeadingBlocker, COUNT(*) BlockedSpidCount FROM #Blocked GROUP BY LeadingBlocker) cnt + ON cnt.LeadingBlocker = lb.LeadingBlocker; + + +-- Populate SessionInfo column with HTML details for sending email +-- Since there's a bunch of logic here, code is more readable doing this separate than mashing it in with the rest of HTML email creation + +UPDATE lb +SET SessionInfo = (SELECT LeadingBlocker, + LoginName, + TransactionCnt, + WaitResource = COALESCE(WaitDescription,WaitResource), + HostName, + DbName, + LastRequest = CONVERT(varchar(20),LastRequestStart,20), + ProgramName, + InputBuffer, + SqlStatement, + SqlText + FROM #LeadingBlocker lb2 + WHERE lb.id = lb2.id + FOR XML PATH ('LeadBlocker')) +FROM #LeadingBlocker lb; + + +/*UPDATE b +SET SessionInfo = '' + LoginName + '' + + '' + HostName + '' + + CASE WHEN TransactionCnt <> 0 + THEN '' + CAST(TransactionCnt AS nvarchar(10)) + '' + ELSE '' + END + + CASE WHEN WaitResource <> '' + THEN '' + COALESCE(WaitDescription,WaitResource) + '' + ELSE '' + END + + '' + DbName + '' + + '' + CONVERT(varchar(20),LastRequestStart,20) + '' + + '' + ProgramName + '' +FROM #Blocked b; +*/ +UPDATE b +SET SessionInfo = (SELECT WaitingSpid, + BlockingChain, + LoginName, + TransactionCnt, + WaitResource = COALESCE(WaitDescription,WaitResource), + HostName, + DbName, + LastRequest = CONVERT(varchar(20),LastRequestStart,20), + ProgramName, + InputBuffer, + SqlStatement, + SqlText + FROM #Blocked b2 + WHERE b.id = b2.id + FOR XML PATH ('BlockedSession')) +FROM #Blocked b; + +--output results + IF NOT EXISTS (SELECT 1 FROM #LeadingBlocker WHERE BlockedSpidCount >= COALESCE(@BlockedSessionThreshold,BlockedSpidCount)) + SELECT 'No Blocking Detected' AS Blocking; + ELSE + BEGIN + SELECT * FROM #LeadingBlocker + WHERE BlockedSpidCount >= COALESCE(@BlockedSessionThreshold,BlockedSpidCount) + ORDER BY LoginTime; + -- + SELECT * FROM #Blocked b + WHERE EXISTS (SELECT 1 FROM #LeadingBlocker lb + WHERE lb.LeadingBlocker = b.LeadingBlocker + AND lb.BlockedSpidCount >= COALESCE(@BlockedSessionThreshold,lb.BlockedSpidCount)) + ORDER BY b.WaitTime DESC; + END; + + + +GO \ No newline at end of file diff --git a/get-connected-logins.sql b/get-connected-logins.sql new file mode 100644 index 0000000..c3fbd26 --- /dev/null +++ b/get-connected-logins.sql @@ -0,0 +1,14 @@ +DECLARE @Login VARCHAR(128) = 'v-%'; + +SELECT name +FROM sys.server_principals +WHERE name LIKE @Login; + +SELECT DB_NAME(dbid) as DBName + ,COUNT(dbid) as NumberOfConnections + ,loginame as LoginName +FROM sys.sysprocesses +WHERE dbid > 4 +AND loginame LIKE @Login +GROUP BY dbid + ,loginame; diff --git a/get-connection-ip-address.sql b/get-connection-ip-address.sql new file mode 100644 index 0000000..d09cd72 --- /dev/null +++ b/get-connection-ip-address.sql @@ -0,0 +1,3 @@ +SELECT dec.local_net_address, dec.local_tcp_port +FROM sys.dm_exec_connections AS dec +WHERE dec.session_id = @@SPID; \ No newline at end of file diff --git a/get-database-column-datatype.sql b/get-database-column-datatype.sql new file mode 100644 index 0000000..a939bb3 --- /dev/null +++ b/get-database-column-datatype.sql @@ -0,0 +1,14 @@ +USE [?]; +GO + +SELECT object_name(c.object_id) as TableName + ,c.name as ColumnName + ,upper(t.name) as Datatype + ,case when c.max_length = -1 then 'max' else convert(varchar(10),c.max_length) end as max_length +from sys.columns c + join sys.types t on c.system_type_id = t.system_type_id + join sys.tables b on c.object_id = b.object_id +where t.name = 'nvarchar' +and schema_name(b.schema_id) = 'dbo' +order by 1, c.column_id + diff --git a/get-session-aggregates.sql b/get-session-aggregates.sql new file mode 100644 index 0000000..e8425bf --- /dev/null +++ b/get-session-aggregates.sql @@ -0,0 +1,109 @@ + +DECLARE @StartTime DATETIME; +--SET @StartTime = '7/24/2019 12:00:00'; -- if set, only shows connections with a last_request_start_time >= @StartTime + +DROP TABLE IF EXISTS #sessions +SELECT * INTO #sessions FROM sys.dm_exec_sessions WHERE @StartTime IS NULL OR last_request_start_time >= @StartTime; + +-- user sessions per database +WITH status_count AS ( + SELECT DB_NAME(database_id) AS database_name + ,status + ,COUNT(*) AS sessions + FROM #sessions + WHERE is_user_process = 1 + GROUP BY database_id + ,status +) +SELECT c1.database_name + ,MAX(CASE WHEN c1.status = 'Running' THEN c1.sessions ELSE 0 END) as Running + ,MAX(CASE WHEN c1.status = 'Sleeping' THEN c1.sessions ELSE 0 END) as Sleeping + ,MAX(CASE WHEN c1.status = 'Dormant' THEN c1.sessions ELSE 0 END) as Dormant + ,MAX(CASE WHEN c1.status = 'Preconnect' THEN c1.sessions ELSE 0 END) as Preconnect + ,SUM(c1.sessions) as Total +FROM status_count c1 + JOIN ( + SELECT database_name + ,SUM(sessions) as sessions + ,ROW_NUMBER() OVER (ORDER BY SUM(sessions) DESC) as orderby + FROM status_count + GROUP BY database_name + ) c2 ON c1.database_name = c2.database_name +GROUP BY c1.database_name + ,c2.orderby +ORDER BY c2.orderby; + +-- user sessions per host +WITH status_count AS ( + SELECT host_name + ,status + ,COUNT(*) AS sessions + FROM #sessions + WHERE is_user_process = 1 + GROUP BY host_name + ,status +) +SELECT c1.host_name + ,MAX(CASE WHEN c1.status = 'Running' THEN c1.sessions ELSE 0 END) as Running + ,MAX(CASE WHEN c1.status = 'Sleeping' THEN c1.sessions ELSE 0 END) as Sleeping + ,MAX(CASE WHEN c1.status = 'Dormant' THEN c1.sessions ELSE 0 END) as Dormant + ,MAX(CASE WHEN c1.status = 'Preconnect' THEN c1.sessions ELSE 0 END) as Preconnect + ,SUM(c1.sessions) as Total +FROM status_count c1 + JOIN ( + SELECT host_name + ,SUM(sessions) as sessions + ,ROW_NUMBER() OVER (ORDER BY SUM(sessions) DESC) as orderby + FROM status_count + GROUP BY host_name + ) c2 ON c1.host_name = c2.host_name +GROUP BY c1.host_name + ,c2.orderby +ORDER BY c2.orderby; + +-- user sessions per login +WITH status_count AS ( + SELECT login_name + ,status + ,COUNT(*) AS sessions + FROM #sessions + WHERE is_user_process = 1 + GROUP BY login_name + ,status +) +SELECT c1.login_name + ,MAX(CASE WHEN c1.status = 'Running' THEN c1.sessions ELSE 0 END) as Running + ,MAX(CASE WHEN c1.status = 'Sleeping' THEN c1.sessions ELSE 0 END) as Sleeping + ,MAX(CASE WHEN c1.status = 'Dormant' THEN c1.sessions ELSE 0 END) as Dormant + ,MAX(CASE WHEN c1.status = 'Preconnect' THEN c1.sessions ELSE 0 END) as Preconnect + ,SUM(c1.sessions) as Total +FROM status_count c1 + JOIN ( + SELECT login_name + ,SUM(sessions) as sessions + ,ROW_NUMBER() OVER (ORDER BY SUM(sessions) DESC) as orderby + FROM status_count + GROUP BY login_name + ) c2 ON c1.login_name = c2.login_name +GROUP BY c1.login_name + ,c2.orderby +ORDER BY c2.orderby; + +-- user database session resource consumption +SELECT login_name + ,DB_NAME(database_id) as database_name + ,SUM(cpu_time) as cpu_time + ,MAX(last_request_end_time) as last_request_end_time + ,SUM(memory_usage) * 8 as memory_kb -- memory_usage: Number of 8-KB pages of memory + ,SUM(reads) as reads + ,SUM(writes) as writes + ,SUM(open_transaction_count) as open_transaction_count +FROM #sessions +WHERE is_user_process = 1 +AND database_id > 4 +GROUP BY login_name + ,database_id +ORDER BY cpu_time DESC; +--ORDER BY memory_kb DESC; +--ORDER BY writes DESC; +--ORDER BY open_transaction_count DESC; diff --git a/get-session-details.sql b/get-session-details.sql new file mode 100644 index 0000000..da9d9e1 --- /dev/null +++ b/get-session-details.sql @@ -0,0 +1,19 @@ +SELECT s.session_id + ,DB_NAME(s.database_id) as [database] + ,s.login_name + ,s.status + ,b.event_info + ,s.cpu_time + ,s.memory_usage + ,s.total_scheduled_time + ,s.total_elapsed_time + ,s.reads + ,s.writes + ,s.logical_reads + ,s.transaction_isolation_level + ,s.open_transaction_count + ,DATEDIFF(MILLISECOND,s.last_request_start_time, s.last_request_end_time) +FROM sys.dm_exec_sessions s + CROSS APPLY sys.dm_exec_input_buffer (s.session_id, NULL) b +WHERE s.session_id > 50 +ORDER BY DATEDIFF(MILLISECOND,s.last_request_start_time, s.last_request_end_time) DESC diff --git a/get-session-locks.sql b/get-session-locks.sql new file mode 100644 index 0000000..c86ab6a --- /dev/null +++ b/get-session-locks.sql @@ -0,0 +1,32 @@ + +declare @spid int = 55 + ,@captures int = 10 + ,@loop int = 1 + ,@delay varchar(10) = '0:00:03'; + +drop table if exists #lock_detail; + +create table #lock_detail (spid int, dbid int, objid bigint, indid int, type varchar(10), resource varchar(50), mode varchar(50), status varchar(50)); + +while @loop <= @captures +begin + waitfor delay @delay; + + insert #lock_detail + exec sp_lock @spid; + + set @loop += 1; +end; + +select spid + ,db_name(dbid) as db + ,objid + ,indid + ,type + ,resource + ,mode + ,status +from #lock_detail +where 1=1 +--and type <> 'db' +--and db_name(dbid) = 'tempdb' diff --git a/get-worker-thread-counts.sql b/get-worker-thread-counts.sql new file mode 100644 index 0000000..d8ded81 --- /dev/null +++ b/get-worker-thread-counts.sql @@ -0,0 +1,8 @@ + +select (select max_workers_count from sys.dm_os_sys_info) as 'TotalThreads' + ,sum(active_Workers_count) as 'Currentthreads' + ,(select max_workers_count from sys.dm_os_sys_info)-sum(active_Workers_count) as 'Availablethreads' + ,sum(runnable_tasks_count) as 'WorkersWaitingfor_cpu' + ,sum(work_queue_count) as 'Request_Waiting_for_threads' +from sys.dm_os_Schedulers +where status='VISIBLE ONLINE' diff --git a/get-worker-threads.sql b/get-worker-threads.sql new file mode 100644 index 0000000..377024c --- /dev/null +++ b/get-worker-threads.sql @@ -0,0 +1,86 @@ +-- Are my actual worker threads exceeding the sp_configure 'max worker threads' value? +-- https://techcommunity.microsoft.com/t5/Premier-Field-Engineering/Are-my-actual-worker-threads-exceeding-the-sp-configure-max/ba-p/370506 + +-- Number of Availability Groups +SELECT count(*) AS NumAvailabilityGroups +FROM sys.availability_groups + +-- Find Max Worker Threads +--exec sp_server_diagnostics +-- 0 THEN t.max_length - WHEN t.name IN ('CHAR', 'NCHAR') THEN c.max_length - END - ) AS Fixed_Data_Size - ,COUNT(CASE WHEN t.precision = 0 AND t.name NOT IN ('CHAR', 'NCHAR') THEN 1 END) AS Num_Variable_Cols - ,SUM(CASE WHEN t.precision = 0 AND t.name NOT IN ('CHAR', 'NCHAR') THEN c.max_length END) AS Max_Var_Size - ,2 + (COUNT(CASE WHEN t.precision = 0 AND t.name NOT IN ('CHAR', 'NCHAR') THEN 1 END) * 2) - + SUM(CASE WHEN t.precision = 0 AND t.name NOT IN ('CHAR', 'NCHAR') THEN c.max_length END) AS Variable_Data_Size - ,2 + ((COUNT(c.column_id) + 7) / 8) AS Null_Bitmap - FROM sys.columns c - INNER JOIN sys.types t - ON c.system_type_id = t.system_type_id - WHERE c.object_id = @l_tblid + +DECLARE @l_tblname NVARCHAR(128) = N'' + ,@l_FillFactor NUMERIC(5, 1) = 100 + ,@l_tblid INT; + +SELECT @l_tblid = object_id +FROM sys.tables +WHERE name = @l_tblname; + +SELECT x.Fixed_Data_Size + x.Variable_Data_Size + x.Null_Bitmap + 4 AS Row_Size + ,8096 / ((x.Fixed_Data_Size + x.Variable_Data_Size + x.Null_Bitmap + 4) + 2) AS Rows_Per_Page + ,8096 * ((100 - @l_FillFactor) / 100) / ((x.Fixed_Data_Size + x.Variable_Data_Size + x.Null_Bitmap + 4) + 2) AS Free_Rows_Per_Page +FROM +( + SELECT COUNT(c.column_id) AS Num_Cols + ,SUM(CASE WHEN t.precision > 0 THEN t.max_length + WHEN t.name IN ('CHAR', 'NCHAR') THEN c.max_length + END + ) AS Fixed_Data_Size + ,COUNT(CASE WHEN t.precision = 0 AND t.name NOT IN ('CHAR', 'NCHAR') THEN 1 END) AS Num_Variable_Cols + ,SUM(CASE WHEN t.precision = 0 AND t.name NOT IN ('CHAR', 'NCHAR') THEN c.max_length END) AS Max_Var_Size + ,2 + (COUNT(CASE WHEN t.precision = 0 AND t.name NOT IN ('CHAR', 'NCHAR') THEN 1 END) * 2) + + SUM(CASE WHEN t.precision = 0 AND t.name NOT IN ('CHAR', 'NCHAR') THEN c.max_length END) AS Variable_Data_Size + ,2 + ((COUNT(c.column_id) + 7) / 8) AS Null_Bitmap + FROM sys.columns c + INNER JOIN sys.types t + ON c.system_type_id = t.system_type_id + WHERE c.object_id = @l_tblid ) x; \ No newline at end of file diff --git a/performance-tuning/index-find-bad-indexes.sql b/index-get-bad-indexes.sql similarity index 97% rename from performance-tuning/index-find-bad-indexes.sql rename to index-get-bad-indexes.sql index 7f93a68..51d032b 100644 --- a/performance-tuning/index-find-bad-indexes.sql +++ b/index-get-bad-indexes.sql @@ -1,29 +1,29 @@ -SELECT OBJECT_NAME(s.[object_id]) AS [Table Name] - , i.name AS [Index Name] - --, i.index_id AS [Index Id] - , i.type_desc AS [Index Type] - , s.user_seeks + s.user_scans + s.user_lookups AS [Total Reads] - , s.user_updates AS [Total Writes] - , s.user_updates - (s.user_seeks + s.user_scans + s.user_lookups) AS [Difference] - , CASE - WHEN s.user_updates < 1 THEN 100 - ELSE 1.00 * (s.user_seeks + s.user_scans + s.user_lookups) / s.user_updates - END AS reads_per_write - , (SELECT SUM(p.rows) FROM sys.partitions p WHERE p.index_id = i.index_id AND i.object_id = p.object_id) AS [Rows] - , CASE WHEN i.is_primary_key = 1 OR i.is_unique_constraint = 1 THEN - 'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(s.[object_id])) + '.' + QUOTENAME(OBJECT_NAME(s.[object_id])) + ' DROP CONSTRAINT ' + QUOTENAME(i.name) - ELSE - 'DROP INDEX ' + QUOTENAME(i.name) + ' ON ' + QUOTENAME(OBJECT_SCHEMA_NAME(s.[object_id])) + '.' + QUOTENAME(OBJECT_NAME(s.[object_id])) - END as [Drop Statement] -FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) - INNER JOIN sys.indexes AS i WITH (NOLOCK) - ON s.[object_id] = i.[object_id] - AND i.index_id = s.index_id -WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 -AND s.database_id = DB_ID() -AND s.user_updates > (s.user_seeks + s.user_scans + s.user_lookups) -AND i.index_id > 1 -ORDER BY [Difference] DESC - , [Total Writes] DESC - , [Total Reads] ASC -OPTION (RECOMPILE); +SELECT OBJECT_NAME(s.[object_id]) AS [Table Name] + , i.name AS [Index Name] + --, i.index_id AS [Index Id] + , i.type_desc AS [Index Type] + , s.user_seeks + s.user_scans + s.user_lookups AS [Total Reads] + , s.user_updates AS [Total Writes] + , s.user_updates - (s.user_seeks + s.user_scans + s.user_lookups) AS [Difference] + , CASE + WHEN s.user_updates < 1 THEN 100 + ELSE 1.00 * (s.user_seeks + s.user_scans + s.user_lookups) / s.user_updates + END AS reads_per_write + , (SELECT SUM(p.rows) FROM sys.partitions p WHERE p.index_id = i.index_id AND i.object_id = p.object_id) AS [Rows] + , CASE WHEN i.is_primary_key = 1 OR i.is_unique_constraint = 1 THEN + 'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(s.[object_id])) + '.' + QUOTENAME(OBJECT_NAME(s.[object_id])) + ' DROP CONSTRAINT ' + QUOTENAME(i.name) + ELSE + 'DROP INDEX ' + QUOTENAME(i.name) + ' ON ' + QUOTENAME(OBJECT_SCHEMA_NAME(s.[object_id])) + '.' + QUOTENAME(OBJECT_NAME(s.[object_id])) + END as [Drop Statement] +FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) + INNER JOIN sys.indexes AS i WITH (NOLOCK) + ON s.[object_id] = i.[object_id] + AND i.index_id = s.index_id +WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 +AND s.database_id = DB_ID() +AND s.user_updates > (s.user_seeks + s.user_scans + s.user_lookups) +AND i.index_id > 1 +ORDER BY [Difference] DESC + , [Total Writes] DESC + , [Total Reads] ASC +OPTION (RECOMPILE); diff --git a/database-info/index-detail-by-table.sql b/index-get-detail-by-table.sql similarity index 97% rename from database-info/index-detail-by-table.sql rename to index-get-detail-by-table.sql index a169b61..95d80bf 100644 --- a/database-info/index-detail-by-table.sql +++ b/index-get-detail-by-table.sql @@ -1,227 +1,228 @@ -SET NOCOUNT ON; - -DECLARE @DBId INT = DB_ID() - ,@SchemaName sysname - ,@TblName sysname = N'[T_FTS_QUEUE]' - ,@TblId INT - ,@MinFragmentation REAL = 5.0 -- Defaulted to 5% as recommended by MS in BOL - ,@MinPageCount INT = 1000 -- Defaulted to 1000 pages as recommended by MS in BOL - ,@EstimateCompression BIT = 0 - ,@CompressionType NVARCHAR(60) = N'ROW'; - -SET @TblId = OBJECT_ID(@TblName); -SET @SchemaName = OBJECT_SCHEMA_NAME(@TblId, @DBId); - -/****** INDEX CATALOG BLOCK START ******/ -SELECT 'CATALOG:' AS Info; -SELECT '[' + DB_NAME() + '].[' + @SchemaName + '].[' + OBJECT_NAME(@TblId, @DBId) + ']' AS Object - ,i.name AS [Index] - ,i.type_desc AS [Index Type] - ,ds.type_desc AS [Data Space Type] - ,ds.name AS [Data Space Name] - ,i.is_primary_key AS PK - ,i.is_unique_constraint AS AK - ,i.fill_factor AS [Fill Factor] - ,STUFF(( - SELECT CASE WHEN ic.is_descending_key = 1 THEN ', ' + c.name + '(-)' - ELSE ', ' + c.name - END - FROM sys.index_columns ic - INNER JOIN sys.columns c - ON c.object_id = i.object_id - AND c.column_id = ic.column_id - WHERE ic.object_id = @TblId - AND ic.index_id = i.index_id - AND ic.is_included_column = 0 - ORDER BY ic.key_ordinal - FOR XML PATH('') - ), 1, 2, '' - ) AS Columns - ,STUFF(( - SELECT CASE WHEN ic.is_descending_key = 1 THEN ', ' + c.name + '(-)' - ELSE ', ' + c.name - END - FROM sys.index_columns ic - INNER JOIN sys.columns c - ON c.object_id = i.object_id - AND c.column_id = ic.column_id - WHERE ic.object_id = @TblId - AND ic.index_id = i.index_id - AND ic.is_included_column = 1 - ORDER BY ic.key_ordinal - FOR XML PATH('') - ), 1, 2, '' - ) AS [Included Columns] - ,s.user_seeks + s.user_scans + s.user_lookups AS TotalReads - ,s.user_updates AS TotalWrites -FROM sys.indexes i - INNER JOIN sys.data_spaces ds - ON i.data_space_id = ds.data_space_id - INNER JOIN sys.dm_db_index_usage_stats AS s - ON s.object_id = i.object_id - AND i.index_id = s.index_id -WHERE i.object_id = @TblId -AND i.is_disabled = 0 -AND i.is_hypothetical = 0 -ORDER BY i.index_id - ,i.name -OPTION (MAXDOP 2); -/****** INDEX CATALOG BLOCK END ******/ - -/****** INDEX SIZE BLOCK START ******/ -DECLARE @tmp_compression TABLE ( - object_name NVARCHAR(128) - ,schema_name NVARCHAR(128) - ,index_id INT PRIMARY KEY CLUSTERED - ,partition_number INT - ,size_with_current_compression_setting BIGINT - ,size_with_requested_compression_setting BIGINT - ,sample_size_with_current_compression_setting BIGINT - ,sample_size_with_requested_compression_setting BIGINT -); - -IF @EstimateCompression = 1 - INSERT INTO @tmp_compression ( - object_name - ,schema_name - ,index_id - ,partition_number - ,size_with_current_compression_setting - ,size_with_requested_compression_setting - ,sample_size_with_current_compression_setting - ,sample_size_with_requested_compression_setting - ) - EXEC sys.sp_estimate_data_compression_savings - @schema_name = @SchemaName - ,@object_name = @TblName - ,@index_id = NULL - ,@partition_number = NULL - ,@data_compression = @CompressionType; - -SELECT 'SIZE:' AS Info; -SELECT '[' + DB_NAME() + '].[' + OBJECT_SCHEMA_NAME(@TblId, @DBId) + '].[' + OBJECT_NAME(@TblId, @DBId) + ']' AS Object - ,i.name AS [Index] - ,i.type_desc AS [Index Type] - ,CONVERT(NUMERIC(9, 2), ps.page_count * 8 * /*convert to MB*/ 0.000976562) AS [Index Size (MB)] - ,ps.page_count AS Pages - ,CONVERT(NUMERIC(5, 2), ps.avg_page_space_used_in_percent) AS [Avg Page Space Used (%)] - ,ps.record_count AS Records - ,ps.avg_record_size_in_bytes AS [Avg Record Size (bytes)] - ,ps.compressed_page_count AS [Compressed Pages] - ,CONVERT(NUMERIC(5, 2), tmp.size_with_requested_compression_setting * /*convert to MB*/ 0.000976562) AS [Est Compressed Size (MB)] - ,'ALTER INDEX [' + i.name + +'] ON ' + '[' + OBJECT_SCHEMA_NAME(@TblId, @DBId) + '].[' - + OBJECT_NAME(@TblId, @DBId) + ']' + ' REBUILD WITH ( FILLFACTOR = ' - + CONVERT( CHAR(3), CASE WHEN i.fill_factor = 0 THEN 100 - ELSE i.fill_factor - END - ) + ', ONLINE=ON, SORT_IN_TEMPDB=ON );' + ' UPDATE STATISTICS [' + OBJECT_SCHEMA_NAME(@TblId, @DBId) - + '].[' + OBJECT_NAME(@TblId, @DBId) + '] [' + i.name + +'];' AS [Rebuild Script] -FROM sys.dm_db_index_physical_stats(@DBId, @TblId, NULL, NULL, 'SAMPLED') AS ps - INNER JOIN sys.indexes i - ON ps.object_id = i.object_id - AND ps.index_id = i.index_id - LEFT OUTER JOIN @tmp_compression tmp - ON i.index_id = tmp.index_id -WHERE i.object_id = @TblId -AND i.is_disabled = 0 -AND i.is_hypothetical = 0 -ORDER BY i.index_id - ,i.name -OPTION (MAXDOP 2); -/****** INDEX SIZE BLOCK END ******/ - -/****** POSSIBLE MISSING INDEXES BLOCK START ******/ -SELECT 'POSSIBLE MISSING (since last restart):' AS Info; -/* ------------------------------------------------------------------ --- Title: FindMissingIndexes --- Author: Brent Ozar --- Date: 2009-04-01 --- Modified By: Clayton Kramer --- Description: This query returns indexes that SQL Server 2005 --- (and higher) thinks are missing since the last restart. The --- "Impact" column is relative to the time of last restart and how --- bad SQL Server needs the index. 10 million+ is high. --- Changes: Updated to expose full table name. This makes it easier --- to identify which database needs an index. Modified the --- CreateIndexStatement to use the full table path and include the --- equality/inequality columns for easier identifcation. ------------------------------------------------------------------- */ -SELECT CONVERT(NUMERIC(19, 2), (migs.avg_total_user_cost * migs.avg_user_impact) * (migs.user_seeks + migs.user_scans)) AS Impact - ,mid.statement AS [Table] - ,mid.equality_columns -- table.column = constant_value - ,mid.inequality_columns -- table.column > constant_value - ,mid.included_columns - ,(migs.user_seeks + migs.user_scans) AS [Rec Index Reads] - ,'CREATE NONCLUSTERED INDEX ix_' + o.name COLLATE DATABASE_DEFAULT + '_' - + REPLACE( - REPLACE( - REPLACE(ISNULL(mid.equality_columns, '') + ISNULL(mid.inequality_columns, ''), '[', '') - ,']', '' - ), ', ', '_' - ) + ' ON ' + mid.statement + ' ( ' + ISNULL(mid.equality_columns, '') - + CASE WHEN mid.inequality_columns IS NULL THEN '' - ELSE CASE WHEN mid.equality_columns IS NULL THEN '' - ELSE ',' - END + mid.inequality_columns - END + ' ) ' + CASE WHEN mid.included_columns IS NULL THEN '' - ELSE 'INCLUDE (' + mid.included_columns + ')' - END + ' WITH ( FILLFACTOR = 100 ) ON [PRIMARY]' + ';' AS CreateIndexStatement -FROM sys.dm_db_missing_index_group_stats AS migs - INNER JOIN sys.dm_db_missing_index_groups AS mig - ON migs.group_handle = mig.index_group_handle - INNER JOIN sys.dm_db_missing_index_details AS mid - ON mig.index_handle = mid.index_handle - INNER JOIN sys.objects AS o WITH (NOLOCK) - ON mid.object_id = o.object_id -WHERE migs.group_handle IN ( - SELECT TOP (500) - group_handle - FROM sys.dm_db_missing_index_group_stats WITH (NOLOCK) - ORDER BY (avg_total_user_cost * avg_user_impact) * (user_seeks + user_scans) DESC - ) -AND OBJECTPROPERTY(o.object_id, 'isusertable') = 1 -AND o.object_id = @TblId -ORDER BY Impact DESC - ,CreateIndexStatement DESC -OPTION (MAXDOP 2); -/****** POSSIBLE MISSING INDEXES BLOCK END ******/ - -/****** POSSIBLE BAD INDEXES BLOCK START ******/ -SELECT 'POSSIBLE BAD (since last restart):' AS Info; -SELECT OBJECT_NAME(s.object_id) AS [Table Name] - ,i.name AS [Index Name] - ,i.type_desc AS [Index Type] - ,s.user_seeks + s.user_scans + s.user_lookups AS [Total Reads] - ,s.user_updates AS [Total Writes] - ,s.user_updates - (s.user_seeks + s.user_scans + s.user_lookups) AS Difference - ,CASE WHEN s.user_updates < 1 THEN 100 - ELSE 1.00 * (s.user_seeks + s.user_scans + s.user_lookups) / s.user_updates - END AS reads_per_write - ,( - SELECT SUM(p.rows) - FROM sys.partitions p - WHERE p.index_id = i.index_id - AND i.object_id = p.object_id - ) AS Rows - ,CASE WHEN i.is_primary_key = 1 - OR i.is_unique_constraint = 1 THEN - 'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(s.object_id)) + '.' - + QUOTENAME(OBJECT_NAME(s.object_id)) + ' DROP CONSTRAINT ' + QUOTENAME(i.name) - ELSE - 'DROP INDEX ' + QUOTENAME(i.name) + ' ON ' + QUOTENAME(OBJECT_SCHEMA_NAME(s.object_id)) + '.' - + QUOTENAME(OBJECT_NAME(s.object_id)) - END AS [Drop Statement] -FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) - INNER JOIN sys.indexes AS i WITH (NOLOCK) - ON s.object_id = i.object_id - AND i.index_id = s.index_id -WHERE OBJECTPROPERTY(s.object_id, 'IsUserTable') = 1 -AND s.database_id = DB_ID() -AND s.user_updates > (s.user_seeks + s.user_scans + s.user_lookups) -AND i.index_id > 1 -AND i.object_id = @TblId -ORDER BY Difference DESC - ,[Total Writes] DESC - ,[Total Reads] ASC -OPTION (RECOMPILE, MAXDOP 2); +SET NOCOUNT ON; + +DECLARE @DBId INT = DB_ID() + ,@SchemaName sysname + ,@TblName sysname = N'TblName' + ,@TblId INT + ,@MinFragmentation REAL = 5.0 -- Defaulted to 5% as recommended by MS in BOL + ,@MinPageCount INT = 1000 -- Defaulted to 1000 pages as recommended by MS in BOL + ,@EstimateCompression BIT = 0 + ,@CompressionType NVARCHAR(60) = N'ROW'; + +SET @TblId = OBJECT_ID(@TblName); +SET @SchemaName = OBJECT_SCHEMA_NAME(@TblId, @DBId); + +/****** INDEX CATALOG BLOCK START ******/ +SELECT 'CATALOG:' AS Info; +SELECT '[' + DB_NAME() + '].[' + @SchemaName + '].[' + OBJECT_NAME(@TblId, @DBId) + ']' AS Object + ,i.name AS [Index] + ,i.type_desc AS [Index Type] + ,ds.type_desc AS [Data Space Type] + ,ds.name AS [Data Space Name] + ,i.is_primary_key AS PK + ,i.is_unique_constraint AS AK + ,i.fill_factor AS [Fill Factor] + ,STUFF(( + SELECT CASE WHEN ic.is_descending_key = 1 THEN ', ' + c.name + '(-)' + ELSE ', ' + c.name + END + FROM sys.index_columns ic + INNER JOIN sys.columns c + ON c.object_id = i.object_id + AND c.column_id = ic.column_id + WHERE ic.object_id = @TblId + AND ic.index_id = i.index_id + AND ic.is_included_column = 0 + ORDER BY ic.key_ordinal + FOR XML PATH('') + ), 1, 2, '' + ) AS Columns + ,STUFF(( + SELECT CASE WHEN ic.is_descending_key = 1 THEN ', ' + c.name + '(-)' + ELSE ', ' + c.name + END + FROM sys.index_columns ic + INNER JOIN sys.columns c + ON c.object_id = i.object_id + AND c.column_id = ic.column_id + WHERE ic.object_id = @TblId + AND ic.index_id = i.index_id + AND ic.is_included_column = 1 + ORDER BY ic.key_ordinal + FOR XML PATH('') + ), 1, 2, '' + ) AS [Included Columns] + ,s.user_seeks + s.user_scans + s.user_lookups AS TotalReads + ,s.user_updates AS TotalWrites +FROM sys.indexes i + INNER JOIN sys.data_spaces ds + ON i.data_space_id = ds.data_space_id + INNER JOIN sys.dm_db_index_usage_stats AS s + ON s.object_id = i.object_id + AND i.index_id = s.index_id +WHERE i.object_id = @TblId +AND i.is_disabled = 0 +AND i.is_hypothetical = 0 +ORDER BY i.index_id + ,i.name +OPTION (MAXDOP 2); +/****** INDEX CATALOG BLOCK END ******/ + +/****** INDEX SIZE BLOCK START ******/ +DECLARE @tmp_compression TABLE ( + object_name NVARCHAR(128) + ,schema_name NVARCHAR(128) + ,index_id INT PRIMARY KEY CLUSTERED + ,partition_number INT + ,size_with_current_compression_setting BIGINT + ,size_with_requested_compression_setting BIGINT + ,sample_size_with_current_compression_setting BIGINT + ,sample_size_with_requested_compression_setting BIGINT +); + +IF @EstimateCompression = 1 + INSERT INTO @tmp_compression ( + object_name + ,schema_name + ,index_id + ,partition_number + ,size_with_current_compression_setting + ,size_with_requested_compression_setting + ,sample_size_with_current_compression_setting + ,sample_size_with_requested_compression_setting + ) + EXEC sys.sp_estimate_data_compression_savings + @schema_name = @SchemaName + ,@object_name = @TblName + ,@index_id = NULL + ,@partition_number = NULL + ,@data_compression = @CompressionType; + +SELECT 'SIZE:' AS Info; +SELECT '[' + DB_NAME() + '].[' + OBJECT_SCHEMA_NAME(@TblId, @DBId) + '].[' + OBJECT_NAME(@TblId, @DBId) + ']' AS Object + ,i.name AS [Index] + ,i.type_desc AS [Index Type] + ,ps.alloc_unit_type_desc AS [Allocation Type] + ,CONVERT(NUMERIC(9, 2), ps.page_count * 8 * /*convert to MB*/ 0.000976562) AS [Index Size (MB)] + ,ps.page_count AS Pages + ,CONVERT(NUMERIC(5, 2), ps.avg_page_space_used_in_percent) AS [Avg Page Space Used (%)] + ,ps.record_count AS Records + ,ps.avg_record_size_in_bytes AS [Avg Record Size (bytes)] + ,ps.compressed_page_count AS [Compressed Pages] + ,CONVERT(NUMERIC(5, 2), tmp.size_with_requested_compression_setting * /*convert to MB*/ 0.000976562) AS [Est Compressed Size (MB)] + ,'ALTER INDEX [' + i.name + +'] ON ' + '[' + OBJECT_SCHEMA_NAME(@TblId, @DBId) + '].[' + + OBJECT_NAME(@TblId, @DBId) + ']' + ' REBUILD WITH ( FILLFACTOR = ' + + CONVERT( CHAR(3), CASE WHEN i.fill_factor = 0 THEN 100 + ELSE i.fill_factor + END + ) + ', ONLINE=ON, SORT_IN_TEMPDB=ON );' + ' UPDATE STATISTICS [' + OBJECT_SCHEMA_NAME(@TblId, @DBId) + + '].[' + OBJECT_NAME(@TblId, @DBId) + '] [' + i.name + +'];' AS [Rebuild Script] +FROM sys.dm_db_index_physical_stats(@DBId, @TblId, NULL, NULL, 'SAMPLED') AS ps + INNER JOIN sys.indexes i + ON ps.object_id = i.object_id + AND ps.index_id = i.index_id + LEFT OUTER JOIN @tmp_compression tmp + ON i.index_id = tmp.index_id +WHERE i.object_id = @TblId +AND i.is_disabled = 0 +AND i.is_hypothetical = 0 +ORDER BY i.index_id + ,i.name +OPTION (MAXDOP 2); +/****** INDEX SIZE BLOCK END ******/ + +/****** POSSIBLE MISSING INDEXES BLOCK START ******/ +SELECT 'POSSIBLE MISSING (since last restart):' AS Info; +/* ------------------------------------------------------------------ +-- Title: FindMissingIndexes +-- Author: Brent Ozar +-- Date: 2009-04-01 +-- Modified By: Clayton Kramer +-- Description: This query returns indexes that SQL Server 2005 +-- (and higher) thinks are missing since the last restart. The +-- "Impact" column is relative to the time of last restart and how +-- bad SQL Server needs the index. 10 million+ is high. +-- Changes: Updated to expose full table name. This makes it easier +-- to identify which database needs an index. Modified the +-- CreateIndexStatement to use the full table path and include the +-- equality/inequality columns for easier identifcation. +------------------------------------------------------------------ */ +SELECT CONVERT(NUMERIC(19, 2), (migs.avg_total_user_cost * migs.avg_user_impact) * (migs.user_seeks + migs.user_scans)) AS Impact + ,mid.statement AS [Table] + ,mid.equality_columns -- table.column = constant_value + ,mid.inequality_columns -- table.column > constant_value + ,mid.included_columns + ,(migs.user_seeks + migs.user_scans) AS [Rec Index Reads] + ,'CREATE NONCLUSTERED INDEX ix_' + o.name COLLATE DATABASE_DEFAULT + '_' + + REPLACE( + REPLACE( + REPLACE(ISNULL(mid.equality_columns, '') + ISNULL(mid.inequality_columns, ''), '[', '') + ,']', '' + ), ', ', '_' + ) + ' ON ' + mid.statement + ' ( ' + ISNULL(mid.equality_columns, '') + + CASE WHEN mid.inequality_columns IS NULL THEN '' + ELSE CASE WHEN mid.equality_columns IS NULL THEN '' + ELSE ',' + END + mid.inequality_columns + END + ' ) ' + CASE WHEN mid.included_columns IS NULL THEN '' + ELSE 'INCLUDE (' + mid.included_columns + ')' + END + ' WITH ( FILLFACTOR = 100 ) ON [PRIMARY]' + ';' AS CreateIndexStatement +FROM sys.dm_db_missing_index_group_stats AS migs + INNER JOIN sys.dm_db_missing_index_groups AS mig + ON migs.group_handle = mig.index_group_handle + INNER JOIN sys.dm_db_missing_index_details AS mid + ON mig.index_handle = mid.index_handle + INNER JOIN sys.objects AS o WITH (NOLOCK) + ON mid.object_id = o.object_id +WHERE migs.group_handle IN ( + SELECT TOP (500) + group_handle + FROM sys.dm_db_missing_index_group_stats WITH (NOLOCK) + ORDER BY (avg_total_user_cost * avg_user_impact) * (user_seeks + user_scans) DESC + ) +AND OBJECTPROPERTY(o.object_id, 'isusertable') = 1 +AND o.object_id = @TblId +ORDER BY Impact DESC + ,CreateIndexStatement DESC +OPTION (MAXDOP 2); +/****** POSSIBLE MISSING INDEXES BLOCK END ******/ + +/****** POSSIBLE BAD INDEXES BLOCK START ******/ +SELECT 'POSSIBLE BAD (since last restart):' AS Info; +SELECT OBJECT_NAME(s.object_id) AS [Table Name] + ,i.name AS [Index Name] + ,i.type_desc AS [Index Type] + ,s.user_seeks + s.user_scans + s.user_lookups AS [Total Reads] + ,s.user_updates AS [Total Writes] + ,s.user_updates - (s.user_seeks + s.user_scans + s.user_lookups) AS Difference + ,CASE WHEN s.user_updates < 1 THEN 100 + ELSE 1.00 * (s.user_seeks + s.user_scans + s.user_lookups) / s.user_updates + END AS reads_per_write + ,( + SELECT SUM(p.rows) + FROM sys.partitions p + WHERE p.index_id = i.index_id + AND i.object_id = p.object_id + ) AS Rows + ,CASE WHEN i.is_primary_key = 1 + OR i.is_unique_constraint = 1 THEN + 'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(s.object_id)) + '.' + + QUOTENAME(OBJECT_NAME(s.object_id)) + ' DROP CONSTRAINT ' + QUOTENAME(i.name) + ELSE + 'DROP INDEX ' + QUOTENAME(i.name) + ' ON ' + QUOTENAME(OBJECT_SCHEMA_NAME(s.object_id)) + '.' + + QUOTENAME(OBJECT_NAME(s.object_id)) + END AS [Drop Statement] +FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) + INNER JOIN sys.indexes AS i WITH (NOLOCK) + ON s.object_id = i.object_id + AND i.index_id = s.index_id +WHERE OBJECTPROPERTY(s.object_id, 'IsUserTable') = 1 +AND s.database_id = DB_ID() +AND s.user_updates > (s.user_seeks + s.user_scans + s.user_lookups) +AND i.index_id > 1 +AND i.object_id = @TblId +ORDER BY Difference DESC + ,[Total Writes] DESC + ,[Total Reads] ASC +OPTION (RECOMPILE, MAXDOP 2); /****** POSSIBLE BAD INDEXES BLOCK END ******/ \ No newline at end of file diff --git a/performance-tuning/index-find-missing-indexes.sql b/index-get-missing-indexes.sql similarity index 100% rename from performance-tuning/index-find-missing-indexes.sql rename to index-get-missing-indexes.sql diff --git a/performance-tuning/statistics-find-out-of-date-statistics.sql b/index-get-out-of-date-statistics.sql similarity index 93% rename from performance-tuning/statistics-find-out-of-date-statistics.sql rename to index-get-out-of-date-statistics.sql index e81c095..16c2d32 100644 --- a/performance-tuning/statistics-find-out-of-date-statistics.sql +++ b/index-get-out-of-date-statistics.sql @@ -1,35 +1,35 @@ -DECLARE @DBName NVARCHAR(128) = 'geography' - ,@SQL NVARCHAR(MAX); - -SET @SQL = - CASE WHEN @DBName IS NULL THEN 'USE [?];' - ELSE 'USE ' + @DBName + ';' - END - + ' - SELECT DISTINCT - [DBId] = DB_ID() - , DBName = DB_NAME() - , TblId = o.object_id - , TblName = o.name - , StatName = si.name - , LastUpdDate = STATS_DATE(si.id, si.indid) - , UpdScript = '' UPDATE STATISTICS ['' + DB_NAME() + ''].['' + s.name + ''].['' + o.name + ''] ['' + si.name + ''];'' - FROM sys.sysindexes si - INNER JOIN ( - SELECT object_id - , rowcnt = SUM(rows) - FROM sys.partitions - GROUP BY object_id - HAVING SUM(rows) > 0 - ) p ON si.id = p.object_id - INNER JOIN sys.objects o ON p.object_id = o.object_id - INNER JOIN sys.schemas s ON o.schema_id = s.schema_id - WHERE ((si.rowmodctr * 1.0 / p.rowcnt) > 0.3 - OR DATEDIFF(DAY,STATS_DATE(si.id, si.indid),GETDATE()) > 30) - AND o.type = ''U'' - AND si.name IS NOT NULL'; - -IF @DBName IS NULL - EXEC sys.sp_MSforeachdb @SQL; -ELSE - EXEC sys.sp_executesql @statement = @SQL; +DECLARE @DBName NVARCHAR(128) = NULL + ,@SQL NVARCHAR(MAX); + +SET @SQL = + CASE WHEN @DBName IS NULL THEN 'USE [?];' + ELSE 'USE ' + @DBName + ';' + END + + ' + SELECT DISTINCT + [DBId] = DB_ID() + , DBName = DB_NAME() + , TblId = o.object_id + , TblName = o.name + , StatName = si.name + , LastUpdDate = STATS_DATE(si.id, si.indid) + , UpdScript = '' UPDATE STATISTICS ['' + DB_NAME() + ''].['' + s.name + ''].['' + o.name + ''] ['' + si.name + ''];'' + FROM sys.sysindexes si + INNER JOIN ( + SELECT object_id + , rowcnt = SUM(rows) + FROM sys.partitions + GROUP BY object_id + HAVING SUM(rows) > 0 + ) p ON si.id = p.object_id + INNER JOIN sys.objects o ON p.object_id = o.object_id + INNER JOIN sys.schemas s ON o.schema_id = s.schema_id + WHERE ((si.rowmodctr * 1.0 / p.rowcnt) > 0.3 + OR DATEDIFF(DAY,STATS_DATE(si.id, si.indid),GETDATE()) > 30) + AND o.type = ''U'' + AND si.name IS NOT NULL'; + +IF @DBName IS NULL + EXEC sys.sp_MSforeachdb @SQL; +ELSE + EXEC sys.sp_executesql @statement = @SQL; diff --git a/performance-tuning/index-find-overlapping-indexes.sql b/index-get-overlapping-indexes.sql similarity index 97% rename from performance-tuning/index-find-overlapping-indexes.sql rename to index-get-overlapping-indexes.sql index 9e5b491..b278c90 100644 --- a/performance-tuning/index-find-overlapping-indexes.sql +++ b/index-get-overlapping-indexes.sql @@ -1,135 +1,135 @@ --- Create a table variable to hold the core index info -CREATE TABLE #AllIndexes ( - TableID INT NOT NULL, - SchemaName SYSNAME NOT NULL, - TableName SYSNAME NOT NULL, - IndexID INT NULL, - IndexName NVARCHAR(128) NULL, - IndexType VARCHAR(12) NOT NULL, - ConstraintType VARCHAR(11) NOT NULL, - ObjectType VARCHAR(10) NOT NULL, - AllColName NVARCHAR(2078) NULL, - ColName1 NVARCHAR(128) NULL, - ColName2 NVARCHAR(128) NULL, - IndexSizeKB BIGINT NULL, - HasFilter BIT NOT NULL, - HasIncludedColumn BIT NOT NULL -); - -DECLARE @ProductVersion NVARCHAR(128); -DECLARE @MajorVersion TINYINT; -DECLARE @loadIndexSQL NVARCHAR(MAX); - -SET @ProductVersion = CONVERT(NVARCHAR(128), SERVERPROPERTY('ProductVersion')); -SET @MajorVersion = CONVERT(TINYINT, LEFT(@ProductVersion, CHARINDEX('.', @ProductVersion) - 1)); - -SET @loadIndexSQL = N' - INSERT INTO #AllIndexes (TableID, SchemaName, TableName, IndexID, IndexName, IndexType, ConstraintType, - ObjectType, AllColName, ColName1, ColName2, IndexSizeKB, HasFilter, HasIncludedColumn) - SELECT o.object_id, -- TableID - u.[name], -- SchemaName - o.[name], -- TableName - i.index_id, -- IndexID - i.[name], -- IndexName - CASE i.[type] - WHEN 0 THEN ''HEAP'' - WHEN 1 THEN ''CL'' - WHEN 2 THEN ''NC'' - WHEN 3 THEN ''XML'' - ELSE ''UNKNOWN'' - END, -- IndexType - CASE - WHEN (i.is_primary_key) = 1 THEN ''PK'' - WHEN (i.is_unique) = 1 THEN ''UNQ'' - ELSE '''' - END, -- ConstraintType - CASE - WHEN (i.is_unique_constraint) = 1 OR i.is_primary_key = 1 THEN ''CONSTRAINT'' - WHEN i.type = 0 THEN ''HEAP'' - WHEN i.type = 3 THEN ''XML INDEX'' - ELSE ''INDEX'' - END, -- ObjectType - (SELECT COALESCE(c1.[name], '''') - FROM sys.columns AS c1 - INNER JOIN sys.index_columns AS ic1 ON c1.object_id = ic1.object_id - AND c1.column_id = ic1.column_id - AND ic1.key_ordinal = 1 - WHERE ic1.object_id = i.object_id - AND ic1.index_id = i.index_id) + - CASE - WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 2) IS NULL THEN '''' - ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 2) - END + - CASE - WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 3) IS NULL THEN '''' - ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 3) - END + - CASE - WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 4) IS NULL THEN '''' - ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 4) - END + - CASE - WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 5) IS NULL THEN '''' - ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 5) - END + - CASE - WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 6) IS NULL THEN '''' - ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 6) - END + - CASE - WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 7) IS NULL THEN '''' - ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 7) - END + - CASE - WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 8) IS NULL THEN '''' - ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 8) - END, -- AllColName - (SELECT COALESCE(c1.[name], '''') - FROM sys.columns AS c1 - INNER JOIN sys.index_columns AS ic1 ON c1.[object_id] = ic1.[object_id] - AND c1.[column_id] = ic1.[column_id] - AND ic1.[key_ordinal] = 1 - WHERE ic1.[object_id] = i.[object_id] - AND ic1.[index_id] = i.[index_id]), -- ColName1 - CASE - WHEN INDEX_COL(''['' + u.name + ''].[''+ o.name + '']'', i.index_id, 2) IS NULL THEN '''' - ELSE INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.[index_id],2) - END, -- ColName2 - ps.used_page_count * 8, -- IndexSizeKB' + CHAR(13); - - IF @MajorVersion >= 10 - SET @loadIndexSQL = @loadIndexSQL + 'i.has_filter'; - ELSE - SET @loadIndexSQL = @loadIndexSQL + '0'; - - SET @loadIndexSQL = @loadIndexSQL + ', -- HasFilter' + CHAR(13); - - IF @MajorVersion >= 9 - SET @loadIndexSQL = @loadIndexSQL + 'CASE WHEN (SELECT COUNT(*) FROM sys.index_columns ic WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1) >= 1 THEN 1 ELSE 0 END'; - ELSE - SET @loadIndexSQL = @loadIndexSQL + '0'; - - SET @loadIndexSQL = @loadIndexSQL + ' -- HasIncludedColumn - FROM sys.objects o WITH (NOLOCK) - INNER JOIN sys.schemas u WITH (NOLOCK) ON o.schema_id = u.schema_id - LEFT OUTER JOIN sys.indexes i WITH (NOLOCK) ON o.object_id = i.object_id - LEFT OUTER JOIN sys.dm_db_partition_stats ps WITH (NOLOCK) ON ps.[object_id] = i.[object_id] AND ps.[index_id] = i.[index_id] - WHERE o.[type] = ''U'' - AND o.[name] NOT IN (''dtproperties'') - AND i.[name] NOT LIKE ''_WA_Sys_%''; -'; - -EXEC sp_executesql @loadIndexSQL; - ------------ ---SELECT 'Listing Possible Redundant Index keys' AS [Comments]; - -SELECT DISTINCT i.TableName, i.IndexName,i.IndexType, i.ConstraintType, i.AllColName, i.IndexSizeKB, i.HasFilter, i.HasIncludedColumn - FROM #AllIndexes AS i - JOIN #AllIndexes AS i2 ON i.TableID = i2.TableID - AND i.ColName1 = i2.ColName1 - AND i.IndexName <> i2.IndexName - AND i.IndexType <> 'XML' - ORDER BY i.TableName, i.AllColName; - +-- Create a table variable to hold the core index info +CREATE TABLE #AllIndexes ( + TableID INT NOT NULL, + SchemaName SYSNAME NOT NULL, + TableName SYSNAME NOT NULL, + IndexID INT NULL, + IndexName NVARCHAR(128) NULL, + IndexType VARCHAR(12) NOT NULL, + ConstraintType VARCHAR(11) NOT NULL, + ObjectType VARCHAR(10) NOT NULL, + AllColName NVARCHAR(2078) NULL, + ColName1 NVARCHAR(128) NULL, + ColName2 NVARCHAR(128) NULL, + IndexSizeKB BIGINT NULL, + HasFilter BIT NOT NULL, + HasIncludedColumn BIT NOT NULL +); + +DECLARE @ProductVersion NVARCHAR(128); +DECLARE @MajorVersion TINYINT; +DECLARE @loadIndexSQL NVARCHAR(MAX); + +SET @ProductVersion = CONVERT(NVARCHAR(128), SERVERPROPERTY('ProductVersion')); +SET @MajorVersion = CONVERT(TINYINT, LEFT(@ProductVersion, CHARINDEX('.', @ProductVersion) - 1)); + +SET @loadIndexSQL = N' + INSERT INTO #AllIndexes (TableID, SchemaName, TableName, IndexID, IndexName, IndexType, ConstraintType, + ObjectType, AllColName, ColName1, ColName2, IndexSizeKB, HasFilter, HasIncludedColumn) + SELECT o.object_id, -- TableID + u.[name], -- SchemaName + o.[name], -- TableName + i.index_id, -- IndexID + i.[name], -- IndexName + CASE i.[type] + WHEN 0 THEN ''HEAP'' + WHEN 1 THEN ''CL'' + WHEN 2 THEN ''NC'' + WHEN 3 THEN ''XML'' + ELSE ''UNKNOWN'' + END, -- IndexType + CASE + WHEN (i.is_primary_key) = 1 THEN ''PK'' + WHEN (i.is_unique) = 1 THEN ''UNQ'' + ELSE '''' + END, -- ConstraintType + CASE + WHEN (i.is_unique_constraint) = 1 OR i.is_primary_key = 1 THEN ''CONSTRAINT'' + WHEN i.type = 0 THEN ''HEAP'' + WHEN i.type = 3 THEN ''XML INDEX'' + ELSE ''INDEX'' + END, -- ObjectType + (SELECT COALESCE(c1.[name], '''') + FROM sys.columns AS c1 + INNER JOIN sys.index_columns AS ic1 ON c1.object_id = ic1.object_id + AND c1.column_id = ic1.column_id + AND ic1.key_ordinal = 1 + WHERE ic1.object_id = i.object_id + AND ic1.index_id = i.index_id) + + CASE + WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 2) IS NULL THEN '''' + ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 2) + END + + CASE + WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 3) IS NULL THEN '''' + ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 3) + END + + CASE + WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 4) IS NULL THEN '''' + ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 4) + END + + CASE + WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 5) IS NULL THEN '''' + ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 5) + END + + CASE + WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 6) IS NULL THEN '''' + ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 6) + END + + CASE + WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 7) IS NULL THEN '''' + ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 7) + END + + CASE + WHEN INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 8) IS NULL THEN '''' + ELSE '', '' + INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.index_id, 8) + END, -- AllColName + (SELECT COALESCE(c1.[name], '''') + FROM sys.columns AS c1 + INNER JOIN sys.index_columns AS ic1 ON c1.[object_id] = ic1.[object_id] + AND c1.[column_id] = ic1.[column_id] + AND ic1.[key_ordinal] = 1 + WHERE ic1.[object_id] = i.[object_id] + AND ic1.[index_id] = i.[index_id]), -- ColName1 + CASE + WHEN INDEX_COL(''['' + u.name + ''].[''+ o.name + '']'', i.index_id, 2) IS NULL THEN '''' + ELSE INDEX_COL(''['' + u.[name] + ''].['' + o.[name] + '']'', i.[index_id],2) + END, -- ColName2 + ps.used_page_count * 8, -- IndexSizeKB' + CHAR(13); + + IF @MajorVersion >= 10 + SET @loadIndexSQL = @loadIndexSQL + 'i.has_filter'; + ELSE + SET @loadIndexSQL = @loadIndexSQL + '0'; + + SET @loadIndexSQL = @loadIndexSQL + ', -- HasFilter' + CHAR(13); + + IF @MajorVersion >= 9 + SET @loadIndexSQL = @loadIndexSQL + 'CASE WHEN (SELECT COUNT(*) FROM sys.index_columns ic WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1) >= 1 THEN 1 ELSE 0 END'; + ELSE + SET @loadIndexSQL = @loadIndexSQL + '0'; + + SET @loadIndexSQL = @loadIndexSQL + ' -- HasIncludedColumn + FROM sys.objects o WITH (NOLOCK) + INNER JOIN sys.schemas u WITH (NOLOCK) ON o.schema_id = u.schema_id + LEFT OUTER JOIN sys.indexes i WITH (NOLOCK) ON o.object_id = i.object_id + LEFT OUTER JOIN sys.dm_db_partition_stats ps WITH (NOLOCK) ON ps.[object_id] = i.[object_id] AND ps.[index_id] = i.[index_id] + WHERE o.[type] = ''U'' + AND o.[name] NOT IN (''dtproperties'') + AND i.[name] NOT LIKE ''_WA_Sys_%''; +'; + +EXEC sp_executesql @loadIndexSQL; + +----------- +--SELECT 'Listing Possible Redundant Index keys' AS [Comments]; + +SELECT DISTINCT i.TableName, i.IndexName,i.IndexType, i.ConstraintType, i.AllColName, i.IndexSizeKB, i.HasFilter, i.HasIncludedColumn + FROM #AllIndexes AS i + JOIN #AllIndexes AS i2 ON i.TableID = i2.TableID + AND i.ColName1 = i2.ColName1 + AND i.IndexName <> i2.IndexName + AND i.IndexType <> 'XML' + ORDER BY i.TableName, i.AllColName; + DROP TABLE #AllIndexes; \ No newline at end of file diff --git a/index-get-statistics-detail.sql b/index-get-statistics-detail.sql new file mode 100644 index 0000000..ecc8f18 --- /dev/null +++ b/index-get-statistics-detail.sql @@ -0,0 +1,43 @@ +USE [DBName]; + +-- whats stats exist for the table +--EXEC sp_helpstats @objname = 'User'; +SELECT o.name AS TblName + ,s.name AS StatName + ,s.stats_id + ,sc.stats_column_id + ,c.name AS ColName + ,s.auto_created + ,s.filter_definition + ,sp.last_updated + ,sp.rows + ,sp.rows_sampled + ,sp.steps + ,sp.modification_counter +FROM sys.stats s + JOIN sys.stats_columns sc ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id + JOIN sys.columns c ON sc.object_id = c.object_id AND sc.column_id = c.column_id + JOIN sys.objects o ON s.object_id = o.object_id + CROSS APPLY sys.dm_db_stats_properties (s.object_id, s.stats_id) sp +WHERE o.name = '[TblName]' +ORDER BY o.name + ,s.stats_id + ,sc.stats_column_id; + +-- statistics info (including histogram) +DBCC SHOW_STATISTICS ('[TblName]', '[StatName]'); + +-- \/\/ CARDINALITY ESTIMATOR HELPER \/\/ -- + +--How to calculate row estimates for multiple single column statistics (CE assumes a correlation) +--Find Histogram bucket for param value then calculate % Rows: EQ_ROWS/ROWS or AVG_RANGE_ROWS/ROWS +--EstimatedRows calc wi/ percentage order from MOST to LEAST selective: A% * SQRT(B%) * SQRT(SQRT(C%)) * Rows = EstimatedRows + +--How to calculate row estimates for multi-column statistics +--Find Histogram bucket for multi-column statistic (will be equivalent to 1st column in statistic): Rows +--Find Histogram bucket for 2nd, 3rdor 4th column statistic and calculate % Rows: EQ_ROWS/ROWS or AVG_RANGE_ROWS/ROWS +--Rows * SQRT(A%) * SQRT(SQRT(B%)) = EstimatedRows + +--Filtered Statistics +--Why? B/c statistics Histogram limited to 200 steps. +--Works for literal values or OPTION RECOMPILE but not for params (b/c query plan reuse) diff --git a/performance-tuning/index-find-tables-without-clustered-indexes.sql b/index-get-tables-without-clustered-indexes.sql similarity index 92% rename from performance-tuning/index-find-tables-without-clustered-indexes.sql rename to index-get-tables-without-clustered-indexes.sql index e988f82..94a74c0 100644 --- a/performance-tuning/index-find-tables-without-clustered-indexes.sql +++ b/index-get-tables-without-clustered-indexes.sql @@ -1,40 +1,40 @@ -DECLARE @l_SQL NVARCHAR(MAX) - , @l_DBName NVARCHAR(128); - --- comment out SET if you want to check against ALL databases -SET @l_DBName = 'geography'; - -CREATE TABLE #DB_FILE_INFO ( - DBName NVARCHAR(128) - , TblName NVARCHAR(128) -); - -SET @l_SQL = 'USE [?]; - INSERT INTO #DB_FILE_INFO (DBName, TblName) - SELECT DB_NAME() - , o.name - FROM sys.objects o - WHERE o.type=''U'' - AND NOT EXISTS(SELECT 1 FROM sys.indexes i - WHERE o.object_id = i.object_id - AND i.type_desc = ''CLUSTERED'') - ORDER BY 1'; - -EXEC sp_msforeachdb @l_SQL; - -IF @l_DBName IS NOT NULL - DELETE - FROM #DB_FILE_INFO - WHERE DBName <> @l_DBName - OR TblName = 'dtproperties'; -ELSE - -- remove system databases - DELETE - FROM #DB_FILE_INFO - WHERE DBName IN ('master', 'model', 'msdb', 'tempdb', 'reportserver', 'reportservertempdb') - OR TblName = 'dtproperties' - -SELECT * -FROM #DB_FILE_INFO; - +DECLARE @l_SQL NVARCHAR(MAX) + , @l_DBName NVARCHAR(128); + +-- comment out SET if you want to check against ALL databases +SET @l_DBName = 'DBName'; + +CREATE TABLE #DB_FILE_INFO ( + DBName NVARCHAR(128) + , TblName NVARCHAR(128) +); + +SET @l_SQL = 'USE [?]; + INSERT INTO #DB_FILE_INFO (DBName, TblName) + SELECT DB_NAME() + , o.name + FROM sys.objects o + WHERE o.type=''U'' + AND NOT EXISTS(SELECT 1 FROM sys.indexes i + WHERE o.object_id = i.object_id + AND i.type_desc = ''CLUSTERED'') + ORDER BY 1'; + +EXEC sp_msforeachdb @l_SQL; + +IF @l_DBName IS NOT NULL + DELETE + FROM #DB_FILE_INFO + WHERE DBName <> @l_DBName + OR TblName = 'dtproperties'; +ELSE + -- remove system databases + DELETE + FROM #DB_FILE_INFO + WHERE DBName IN ('master', 'model', 'msdb', 'tempdb', 'reportserver', 'reportservertempdb') + OR TblName = 'dtproperties' + +SELECT * +FROM #DB_FILE_INFO; + DROP TABLE #DB_FILE_INFO; \ No newline at end of file diff --git a/index-get-usage-detail.sql b/index-get-usage-detail.sql new file mode 100644 index 0000000..0a08991 --- /dev/null +++ b/index-get-usage-detail.sql @@ -0,0 +1,197 @@ + +DECLARE @sql_indxinfo NVARCHAR(2000) + ,@sql_indxsize NVARCHAR(2000) + ,@Version VARCHAR(50) = LEFT(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR(128)),2) + ,@IsHadrEnabled TINYINT = CONVERT(TINYINT,SERVERPROPERTY ('IsHadrEnabled')) + ,@RoleDesc NVARCHAR(60) = 'PRIMARY'; + +if OBJECT_ID('tempdb..#IndxInfo') is not null drop table #IndxInfo; +create table #IndxInfo ( + databaseid INT NOT NULL + ,objectid INT NOT NULL + ,indexid INT NOT NULL + ,databasename VARCHAR(128) NOT NULL + ,schemaname VARCHAR(128) NOT NULL + ,tablename VARCHAR(128) NOT NULL + ,indexname VARCHAR(128) NULL + ,indextype TINYINT NOT NULL + ,columns VARCHAR(2000) NULL + ,included_columns VARCHAR(2000) NULL + ,is_unique BIT NOT NULL + ,is_primary_key BIT NOT NULL + ,is_unique_constraint BIT NOT NULL + ,is_disabled BIT NOT NULL + ,has_filter BIT NOT NULL + ,filter_definition VARCHAR(2000) NULL + ,auto_created BIT NULL + ,fill_factor TINYINT NOT NULL + ,is_padded BIT NOT NULL + ,last_user_seek DATETIME NULL + ,last_user_scan DATETIME NULL + ,last_user_lookup DATETIME NULL + ,last_user_update DATETIME NULL + ,user_seeks BIGINT NULL + ,user_scans BIGINT NULL + ,user_lookups BIGINT NULL + ,user_updates BIGINT NULL +); + +if OBJECT_ID('tempdb..#IndxSize') is not null drop table #IndxSize; +create table #IndxSize ( + databaseid INT NOT NULL + ,objectid INT NOT NULL + ,indexid INT NOT NULL + ,partitions INT NOT NULL + ,rows BIGINT NOT NULL + ,total_pages BIGINT NOT NULL + ,used_pages BIGINT NOT NULL + ,in_row_data_pages BIGINT NOT NULL + ,lob_data_pages BIGINT NOT NULL + ,row_overflow_data_pages BIGINT NOT NULL + ,data_compression TINYINT NOT NULL +); + +SET @sql_indxinfo = N'USE [?]; +IF DB_ID() > 4 +INSERT #IndxInfo +SELECT DB_ID() + ,i.object_id + ,i.index_id + ,DB_NAME() + ,SCHEMA_NAME(o.schema_id) + ,o.name + ,i.name + ,i.type + ,STUFF(( + SELECT CASE WHEN ic.is_descending_key = 1 THEN '', '' + c.name + ''(-)'' ELSE '', '' + c.name END + FROM sys.index_columns ic + JOIN sys.columns c + ON c.object_id = ic.object_id + AND c.column_id = ic.column_id + WHERE ic.object_id = i.object_id + AND ic.index_id = i.index_id + AND ic.is_included_column = 0 + ORDER BY ic.key_ordinal + FOR XML PATH('''') + ), 1, 2, '''') + ,STUFF(( + SELECT CASE WHEN ic.is_descending_key = 1 THEN '', '' + c.name + ''(-)'' ELSE '', '' + c.name END + FROM sys.index_columns ic + JOIN sys.columns c + ON c.object_id = ic.object_id + AND c.column_id = ic.column_id + WHERE ic.object_id = i.object_id + AND ic.index_id = i.index_id + AND ic.is_included_column = 1 + ORDER BY ic.key_ordinal + FOR XML PATH('''') + ), 1, 2, '''') + ,i.is_unique + ,i.is_primary_key + ,i.is_unique_constraint + ,i.is_disabled + ,i.has_filter + ,i.filter_definition' ++ CASE WHEN @Version > 13 THEN ' ,i.auto_created' ELSE ' ,NULL' END + +' ,i.fill_factor + ,i.is_padded + ,u.last_user_seek + ,u.last_user_scan + ,u.last_user_lookup + ,u.last_user_update + ,u.user_seeks + ,u.user_scans + ,u.user_lookups + ,u.user_updates +FROM sys.objects o + JOIN sys.indexes i ON o.object_id = i.object_id + LEFT JOIN sys.dm_db_index_usage_stats u ON i.object_id = u.object_id and i.index_id = u.index_id and u.database_id = DB_ID() +WHERE OBJECTPROPERTY(o.object_id,''IsUserTable'') = 1;' + +SET @sql_indxsize = N'USE [?]; +IF DB_ID() > 4 +INSERT #IndxSize +SELECT DB_ID() + ,i.object_id + ,i.index_id + ,COUNT(p.partition_id) + ,SUM(p.rows) + ,SUM(a.used_pages) + ,SUM(a.total_pages) + ,SUM(a.in_row) + ,SUM(a.lob) + ,SUM(a.row_overflow) + ,p.data_compression +FROM sys.indexes i + JOIN sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id + JOIN ( + SELECT container_id + ,SUM(used_pages) as used_pages + ,SUM(total_pages) as total_pages + ,SUM(CASE WHEN type = 1 THEN data_pages ELSE 0 END) as in_row + ,SUM(CASE WHEN type = 2 THEN data_pages ELSE 0 END) as lob + ,SUM(CASE WHEN type = 3 THEN data_pages ELSE 0 END) as row_overflow + FROM sys.allocation_units + GROUP BY container_id + ) a ON p.partition_id = a.container_id +WHERE OBJECTPROPERTY(i.object_id,''IsUserTable'') = 1 +GROUP BY i.object_id + ,i.index_id + ,p.data_compression;' + +IF @IsHadrEnabled = 0 +OR ( + @IsHadrEnabled = 1 + AND EXISTS ( + SELECT 1 + FROM sys.dm_hadr_availability_replica_states AS a + JOIN sys.availability_replicas AS b + ON b.replica_id = a.replica_id + WHERE b.replica_server_name = @@SERVERNAME + AND a.role_desc = @RoleDesc + ) +) +BEGIN + EXEC sp_msforeachdb @sql_indxinfo; + EXEC sp_msforeachdb @sql_indxsize; +END; + +SELECT @@SERVERNAME AS servername + ,i.databasename + ,i.schemaname + ,i.tablename + ,i.indexname + ,i.indextype + ,i.columns + ,i.included_columns + ,i.is_unique + ,i.is_primary_key + ,i.is_unique_constraint + ,i.is_disabled + ,i.has_filter + ,i.filter_definition + ,i.auto_created + ,i.fill_factor + ,i.is_padded + ,s.partitions + ,s.rows + ,s.total_pages + ,s.used_pages + ,s.in_row_data_pages + ,s.lob_data_pages + ,s.row_overflow_data_pages + ,s.data_compression + ,i.last_user_seek + ,i.last_user_scan + ,i.last_user_lookup + ,i.last_user_update + ,i.user_seeks + ,i.user_scans + ,i.user_lookups + ,i.user_updates +FROM #IndxInfo i + JOIN #IndxSize s + ON s.databaseid = i.databaseid + AND s.objectid = i.objectid + AND s.indexid = i.indexid +WHERE i.databaseid > 4; diff --git a/index-get-usage.sql b/index-get-usage.sql new file mode 100644 index 0000000..e074446 --- /dev/null +++ b/index-get-usage.sql @@ -0,0 +1,12 @@ +SELECT OBJECT_NAME(S.[OBJECT_ID]) AS [OBJECT NAME], + I.[NAME] AS [INDEX NAME], + USER_SEEKS, + USER_SCANS, + USER_LOOKUPS, + USER_UPDATES +FROM SYS.DM_DB_INDEX_USAGE_STATS AS S + INNER JOIN SYS.INDEXES AS I + ON I.[OBJECT_ID] = S.[OBJECT_ID] + AND I.INDEX_ID = S.INDEX_ID +WHERE OBJECTPROPERTY(S.[OBJECT_ID],'IsUserTable') = 1 +AND S.database_id = DB_ID() diff --git a/linked-server-get-list.sql b/linked-server-get-list.sql new file mode 100644 index 0000000..125459a --- /dev/null +++ b/linked-server-get-list.sql @@ -0,0 +1,25 @@ + +SELECT @@SERVERNAME AS servername + ,s.name AS linkedservername + ,s.product AS productname + ,s.provider AS OLEDBprovidername + ,s.data_source AS OLEDBdatasource + ,s.is_remote_login_enabled + ,s.is_rpc_out_enabled + ,s.is_data_access_enabled + ,s.is_collation_compatible + ,s.uses_remote_collation + ,s.collation_name + ,s.lazy_schema_validation + ,s.is_system + ,s.is_remote_proc_transaction_promotion_enabled + ,s.modify_date as linkedserver_modify_date + ,ll.uses_self_credential + ,c.name AS local_login + ,ll.remote_name + ,ll.modify_date as login_modify_date +FROM sys.Servers s + LEFT OUTER JOIN sys.linked_logins ll ON ll.server_id = s.server_id + LEFT OUTER JOIN sys.server_principals c ON c.principal_id = ll.local_principal_id +WHERE s.server_id > 0; -- 0 = local server + diff --git a/server-config/linked-server-grant-access-to-windows-group.sql b/linked-server-grant-access-to-windows-group.sql similarity index 97% rename from server-config/linked-server-grant-access-to-windows-group.sql rename to linked-server-grant-access-to-windows-group.sql index d261220..f90aee3 100644 --- a/server-config/linked-server-grant-access-to-windows-group.sql +++ b/linked-server-grant-access-to-windows-group.sql @@ -1,24 +1,24 @@ -USE master; -GO - -DECLARE @LinkedServerName NVARCHAR(128) = N'' - ,@RemoteUser NVARCHAR(128) = N'' - ,@RemotePwd NVARCHAR(128) = N'' - ,@WindowsGroupName NVARCHAR(128) = N''; - --- drop table #LoginsList -CREATE TABLE #LoginsList ( - [Account Name] NVARCHAR(128) - ,Type NVARCHAR(128) - ,Privilege NVARCHAR(128) - ,[Mapped Login Name] NVARCHAR(128) - ,[Permission Path] NVARCHAR(128) -); - -INSERT #LoginsList ([Account Name], Type, Privilege, [Mapped Login Name], [Permission Path]) -EXEC sys.xp_logininfo @acctname = @WindowsGroupName, @option = 'members'; - -SELECT 'EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname = N''' + @LinkedServerName + ''', @locallogin = N''' - + [Account Name] + ''', @useself = N''False'', @rmtuser = N''' + @RemoteUser + ''', @rmtpassword = N''' - + @RemotePwd + ''';' -FROM #LoginsList; +USE master; +GO + +DECLARE @LinkedServerName NVARCHAR(128) = N'' + ,@RemoteUser NVARCHAR(128) = N'' + ,@RemotePwd NVARCHAR(128) = N'' + ,@WindowsGroupName NVARCHAR(128) = N''; + +-- drop table #LoginsList +CREATE TABLE #LoginsList ( + [Account Name] NVARCHAR(128) + ,Type NVARCHAR(128) + ,Privilege NVARCHAR(128) + ,[Mapped Login Name] NVARCHAR(128) + ,[Permission Path] NVARCHAR(128) +); + +INSERT #LoginsList ([Account Name], Type, Privilege, [Mapped Login Name], [Permission Path]) +EXEC sys.xp_logininfo @acctname = @WindowsGroupName, @option = 'members'; + +SELECT 'EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname = N''' + @LinkedServerName + ''', @locallogin = N''' + + [Account Name] + ''', @useself = N''False'', @rmtuser = N''' + @RemoteUser + ''', @rmtpassword = N''' + + @RemotePwd + ''';' +FROM #LoginsList; diff --git a/performance-tuning/explore-plan-cache.sql b/performance-tuning/explore-plan-cache.sql deleted file mode 100644 index d526aa1..0000000 --- a/performance-tuning/explore-plan-cache.sql +++ /dev/null @@ -1,19 +0,0 @@ -SELECT SUBSTRING( ST.text, (QS.statement_start_offset / 2) + 1, ((CASE QS.statement_end_offset - WHEN -1 THEN DATALENGTH(ST.text) - ELSE QS.statement_end_offset - END - QS.statement_start_offset - ) / 2 - ) + 1 - ) AS "Statement Text" - ,QS.total_worker_time / QS.execution_count / 1000 AS "Average Worker Time (ms)" - ,QS.execution_count AS "Execution Count" - ,QS.total_worker_time / 1000 AS "Total Worker Time (ms)" - ,QS.total_logical_reads AS "Total Logical Reads" - ,QS.total_logical_reads / QS.execution_count AS "Average Logical Reads" - ,QS.total_elapsed_time / 1000 AS "Total Elapsed Time (ms)" - ,QS.total_elapsed_time / QS.execution_count / 1000 AS "Average Elapsed Time (ms)" - ,QP.query_plan AS "Query Plan (double click to open)" -FROM sys.dm_exec_query_stats QS - CROSS APPLY sys.dm_exec_sql_text(QS.sql_handle) ST - CROSS APPLY sys.dm_exec_query_plan(QS.plan_handle) QP -ORDER BY QS.total_elapsed_time / QS.execution_count DESC; \ No newline at end of file diff --git a/performance-tuning/find-CPU-intensive-queries.sql b/performance-tuning/find-CPU-intensive-queries.sql deleted file mode 100644 index 9438e25..0000000 --- a/performance-tuning/find-CPU-intensive-queries.sql +++ /dev/null @@ -1,27 +0,0 @@ -DECLARE @l_RowCount INT; - -SET @l_RowCount = 100; - -SELECT TOP (@l_RowCount) - RANK() OVER (ORDER BY deqs.total_worker_time DESC) AS Rank - ,CONVERT(DECIMAL(38, 2), CONVERT(FLOAT, deqs.total_worker_time) / 1000) AS [Total CPU Time (ms)] - ,deqs.execution_count AS [Execution Count] - ,CONVERT(DECIMAL(38, 2), (CONVERT(FLOAT, deqs.total_worker_time) / deqs.execution_count) / 1000) AS [Average CPU Time (ms)] - ,SUBSTRING( execText.text -- starting value for substring - ,CASE WHEN deqs.statement_start_offset = 0 - OR deqs.statement_start_offset IS NULL THEN 1 - ELSE deqs.statement_start_offset / 2 + 1 - END -- ending value for substring - ,CASE WHEN deqs.statement_end_offset = 0 - OR deqs.statement_end_offset = -1 - OR deqs.statement_end_offset IS NULL THEN LEN(execText.text) - ELSE deqs.statement_end_offset / 2 - END - CASE WHEN deqs.statement_start_offset = 0 - OR deqs.statement_start_offset IS NULL THEN 1 - ELSE deqs.statement_start_offset / 2 - END + 1 - ) AS [Query Text] - ,execText.text AS [Object Text] -FROM sys.dm_exec_query_stats deqs - CROSS APPLY sys.dm_exec_sql_text(deqs.plan_handle) AS execText -ORDER BY deqs.total_worker_time DESC; diff --git a/performance-tuning/find-CPU-utilization.sql b/performance-tuning/find-CPU-utilization.sql deleted file mode 100644 index dd96bec..0000000 --- a/performance-tuning/find-CPU-utilization.sql +++ /dev/null @@ -1,64 +0,0 @@ -DECLARE @ts_now BIGINT - ,@span INT = 30; -- number minutes of recent hist to return - -SELECT @ts_now = cpu_ticks / (cpu_ticks / ms_ticks) -FROM sys.dm_os_sys_info; - -SELECT TOP (@span) - y.SQLProcessUtilization AS [SQL Server CPU Utilization (%)] - ,y.SystemIdle AS [System Idle Process (%)] - ,100 - y.SystemIdle - y.SQLProcessUtilization AS [Other Process CPU Utilization (%)] - ,DATEADD(ms, -1 * (@ts_now - y.timestamp), GETDATE()) AS [Event Time] -FROM ( - SELECT x.record.value('(./Record/@id)[1]', 'int') AS record_id - ,x.record.value( - '(./Record/SchedulerMonitorEvent/ - SystemHealth/SystemIdle)[1]', 'int' - ) AS SystemIdle - ,x.record.value( - '(./Record/SchedulerMonitorEvent/ - SystemHealth/ProcessUtilization)[1]', 'int' - ) AS SQLProcessUtilization - ,x.timestamp - FROM ( - SELECT timestamp - ,CONVERT(XML, record) AS record - FROM sys.dm_os_ring_buffers - WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR' - AND record LIKE N'%%' - ) AS x - ) AS y -ORDER BY y.record_id DESC; - - ---You can also monitor the SQL Server schedulers using the sys.dm_os_schedulers view to see if the number of runnable tasks ---is typically nonzero. A nonzero value indicates that tasks have to wait for their time slice to run; high values for this ---counter are a symptom of a CPU bottleneck. You can use the following query to list all the schedulers and look at the ---number of runnable tasks. -SELECT scheduler_id - ,current_tasks_count - ,runnable_tasks_count -FROM sys.dm_os_schedulers -WHERE scheduler_id < 255 -AND runnable_tasks_count > 0; - - ---The following query gives you a high-level view of which currently cached batches or procedures are using the most CPU. The ---query aggregates the CPU consumed by all statements with the same plan__handle (meaning that they are part of the same batch ---or procedure). If a given plan_handle has more than one statement, you may have to drill in further to find the specific query ---that is the largest contributor to the overall CPU usage. -SELECT TOP (50) - SUM(qs.total_worker_time) AS total_cpu_time - ,SUM(qs.execution_count) AS total_execution_count - ,COUNT(*) AS number_of_statements - ,SUM(qs.total_worker_time) / SUM(qs.execution_count) AS avg_cpu_time_per_exec - ,qs.plan_handle -FROM sys.dm_exec_query_stats qs -GROUP BY qs.plan_handle -ORDER BY SUM(qs.total_worker_time) DESC; - - ---SELECT * FROM sys.dm_exec_query_plan ( 0x05000F00B987BE0DA035DDFE0300000001000000000000000000000000000000000000000000000000000000 ) ---SELECT OBJECT_NAME(644197345) - - diff --git a/performance-tuning/find-IO-latency.sql b/performance-tuning/find-IO-latency.sql deleted file mode 100644 index 7a5f5d3..0000000 --- a/performance-tuning/find-IO-latency.sql +++ /dev/null @@ -1,31 +0,0 @@ -SELECT - --virtual file latency - CASE WHEN vfs.num_of_reads = 0 THEN 0 - ELSE (vfs.io_stall_read_ms / vfs.num_of_reads) - END AS ReadLatency - ,CASE WHEN vfs.io_stall_write_ms = 0 THEN 0 - ELSE (vfs.io_stall_write_ms / vfs.num_of_writes) - END AS WriteLatency - ,CASE WHEN (vfs.num_of_reads = 0 AND vfs.num_of_writes = 0) THEN 0 - ELSE (vfs.io_stall / (vfs.num_of_reads + vfs.num_of_writes)) - END AS Latency - --avg bytes per IOP - ,CASE WHEN vfs.num_of_reads = 0 THEN 0 - ELSE (vfs.num_of_bytes_read / vfs.num_of_reads) - END AS AvgBPerRead - ,CASE WHEN vfs.io_stall_write_ms = 0 THEN 0 - ELSE (vfs.num_of_bytes_written / vfs.num_of_writes) - END AS AvgBPerWrite - ,CASE WHEN (vfs.num_of_reads = 0 AND vfs.num_of_writes = 0) THEN 0 - ELSE ((vfs.num_of_bytes_read + vfs.num_of_bytes_written) / (vfs.num_of_reads + vfs.num_of_writes)) - END AS AvgBPerTransfer - ,LEFT(mf.physical_name, 2) AS Drive - ,DB_NAME(vfs.database_id) AS DB - --vfs.*, - ,mf.physical_name - ,SUBSTRING(mf.physical_name, LEN(mf.physical_name) - CHARINDEX('\', REVERSE(mf.physical_name)) + 2, 100) -FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS vfs - JOIN sys.master_files AS mf - ON vfs.database_id = mf.database_id - AND vfs.file_id = mf.file_id -ORDER BY Latency DESC; \ No newline at end of file diff --git a/performance-tuning/find-IO-user-tables.sql b/performance-tuning/find-IO-user-tables.sql deleted file mode 100644 index 23e3576..0000000 --- a/performance-tuning/find-IO-user-tables.sql +++ /dev/null @@ -1,93 +0,0 @@ -DECLARE @TblName NVARCHAR(128) - ,@TblId INT; - -SET @TblName = NULL; - -IF @TblName IS NOT NULL - SET @TblId = OBJECT_ID(@TblName); - -DECLARE @IndxCols TABLE ( - TblId INT - ,IndxId INT - ,Columns NVARCHAR(4000) - ,[Included Columns] NVARCHAR(4000) -); - -INSERT INTO @IndxCols (TblId, IndxId, Columns, [Included Columns]) -SELECT i.object_id - ,i.index_id - ,STUFF(( - SELECT CASE WHEN ic.is_descending_key = 1 THEN ', ' + c.name + '(-)' - ELSE ', ' + c.name - END - FROM sys.index_columns ic - INNER JOIN sys.columns c - ON c.object_id = ic.object_id - AND c.column_id = ic.column_id - WHERE ic.object_id = i.object_id - AND ic.index_id = i.index_id - AND ic.is_included_column = 0 - ORDER BY ic.key_ordinal - FOR XML PATH('') - ), 1, 2, '' - ) AS Columns - ,STUFF(( - SELECT CASE WHEN ic.is_descending_key = 1 THEN ', ' + c.name + '(-)' - ELSE ', ' + c.name - END - FROM sys.index_columns ic - INNER JOIN sys.columns c - ON c.object_id = ic.object_id - AND c.column_id = ic.column_id - WHERE ic.object_id = i.object_id - AND ic.index_id = i.index_id - AND ic.is_included_column = 1 - ORDER BY ic.key_ordinal - FOR XML PATH('') - ), 1, 2, '' - ) AS [Included Columns] -FROM sys.indexes i -WHERE OBJECTPROPERTY(i.object_id, 'IsUserTable') = 1 -AND i.object_id = ISNULL(@TblId, i.object_id); - - -SELECT OBJECT_NAME(s.object_id) AS TblName - ,i.name AS IndxName - ,i.index_id AS IndxId - ,i.type_desc AS IndxType - ,i.is_primary_key AS PK - ,i.is_unique AS AK - ,d.name AS FileGroup - ,c.Columns AS IndxColumns - ,c.[Included Columns] AS IncludedColumns - ,SUM(s.user_seeks + s.user_scans + s.user_lookups) AS TotalReads - ,SUM(s.user_updates) AS TotalWrites -FROM sys.dm_db_index_usage_stats AS s - INNER JOIN sys.indexes AS i - ON s.object_id = i.object_id - AND i.index_id = s.index_id - INNER JOIN sys.data_spaces AS d - ON i.data_space_id = d.data_space_id - INNER JOIN @IndxCols c - ON i.object_id = c.TblId - AND i.index_id = c.IndxId -WHERE OBJECTPROPERTY(s.object_id, 'IsUserTable') = 1 -AND s.database_id = DB_ID() -AND s.object_id = ISNULL(@TblId, s.object_id) -AND i.index_id IN (0, 1) -- heap, ci -GROUP BY OBJECT_NAME(s.object_id) - ,i.name - ,i.index_id - ,i.type_desc - ,i.is_unique - ,i.is_primary_key - ,d.name - ,c.Columns - ,c.[Included Columns] -HAVING SUM(s.user_seeks + s.user_scans + s.user_lookups) + SUM(s.user_updates) > 0 -AND SUM(s.user_updates) = 0 -ORDER BY OBJECT_NAME(s.object_id) - ,i.index_id - ,TotalWrites DESC - ,TotalReads DESC -OPTION (RECOMPILE); diff --git a/performance-tuning/find-TempDb-allocation-page-contention.sql b/performance-tuning/find-TempDb-allocation-page-contention.sql deleted file mode 100644 index 11af6e1..0000000 --- a/performance-tuning/find-TempDb-allocation-page-contention.sql +++ /dev/null @@ -1,16 +0,0 @@ -SELECT session_id - ,wait_type - ,wait_duration_ms - ,blocking_session_id - ,resource_description - ,CASE WHEN CAST(RIGHT(resource_description, LEN(resource_description) - CHARINDEX(':', resource_description, 3)) AS INT) - - 1 % 8088 = 0 THEN 'Is PFS Page' - WHEN CAST(RIGHT(resource_description, LEN(resource_description) - CHARINDEX(':', resource_description, 3)) AS INT) - - 2 % 511232 = 0 THEN 'Is GAM Page' - WHEN CAST(RIGHT(resource_description, LEN(resource_description) - CHARINDEX(':', resource_description, 3)) AS INT) - - 3 % 511232 = 0 THEN 'Is SGAM Page' - ELSE 'Is Not PFS, GAM, or SGAM page' - END AS ResourceType -FROM sys.dm_os_waiting_tasks -WHERE wait_type LIKE 'PAGE%LATCH_%' -AND resource_description LIKE '2:%'; \ No newline at end of file diff --git a/performance-tuning/find-active-open-transactions.sql b/performance-tuning/find-active-open-transactions.sql deleted file mode 100644 index 0bb0464..0000000 --- a/performance-tuning/find-active-open-transactions.sql +++ /dev/null @@ -1,15 +0,0 @@ --- Find active open transactions - -SELECT est.session_id AS [Session ID] - ,est.transaction_id AS [Transaction ID] - ,tas.name AS [Transaction Name] - ,tds.database_id AS [Database ID] -FROM sys.dm_tran_active_transactions tas - INNER JOIN sys.dm_tran_database_transactions tds - ON (tas.transaction_id = tds.transaction_id) - INNER JOIN sys.dm_tran_session_transactions est - ON (est.transaction_id = tas.transaction_id) -WHERE est.is_user_transaction = 1 -- user -AND tas.transaction_state = 2 -- active -AND tds.database_transaction_begin_time IS NOT NULL; --- Time at which the database became involved in the transaction, You can apply filter here diff --git a/performance-tuning/find-active-orphan-transactions.sql b/performance-tuning/find-active-orphan-transactions.sql deleted file mode 100644 index c4013b7..0000000 --- a/performance-tuning/find-active-orphan-transactions.sql +++ /dev/null @@ -1,13 +0,0 @@ -SELECT des.session_id - ,des.login_time - ,des.last_request_start_time - ,des.last_request_end_time - ,des.host_name - ,des.login_name -FROM sys.dm_exec_sessions des - INNER JOIN sys.dm_tran_session_transactions dtst - ON des.session_id = dtst.session_id - LEFT JOIN sys.dm_exec_requests der - ON dtst.session_id = der.session_id -WHERE der.session_id IS NULL -ORDER BY des.session_id; \ No newline at end of file diff --git a/performance-tuning/find-blocking-queries.sql b/performance-tuning/find-blocking-queries.sql deleted file mode 100644 index 60af17d..0000000 --- a/performance-tuning/find-blocking-queries.sql +++ /dev/null @@ -1,28 +0,0 @@ --- https://blog.sqlauthority.com/2010/10/06/sql-server-quickest-way-to-identify-blocking-query-and-resolution-dirty-solution/ - -SELECT db.name AS DBName - ,tl.request_session_id - ,ec1. - ,wt.blocking_session_id - ,OBJECT_NAME(p.object_id) AS BlockedObjectName - ,tl.resource_type - ,h1.text AS RequestingText - ,h2.text AS BlockingText - ,tl.request_mode - ,tl.request_status - ,wt.wait_type - ,wt.wait_duration_ms -FROM sys.dm_tran_locks tl - INNER JOIN sys.databases db - ON db.database_id = tl.resource_database_id - INNER JOIN sys.dm_os_waiting_tasks wt - ON tl.lock_owner_address = wt.resource_address - INNER JOIN sys.partitions p - ON p.hobt_id = tl.resource_associated_entity_id - INNER JOIN sys.dm_exec_connections ec1 - ON ec1.session_id = tl.request_session_id - INNER JOIN sys.dm_exec_connections ec2 - ON ec2.session_id = wt.blocking_session_id - CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) h1 - CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) h2; -GO \ No newline at end of file diff --git a/performance-tuning/find-buffer-cache-hit-ratio.sql b/performance-tuning/find-buffer-cache-hit-ratio.sql deleted file mode 100644 index e5008b7..0000000 --- a/performance-tuning/find-buffer-cache-hit-ratio.sql +++ /dev/null @@ -1,9 +0,0 @@ -SELECT CASE WHEN t2.cntr_value = 0 THEN 0 - ELSE CONVERT(DECIMAL(38, 2), CAST(t1.cntr_value AS FLOAT) / CAST(t2.cntr_value AS FLOAT) * 100.0) - END AS [Buffer Cache Hit Ratio (%)] -FROM sys.dm_os_performance_counters t1 - INNER JOIN sys.dm_os_performance_counters t2 - ON t1.object_name = t2.object_name -WHERE t1.object_name LIKE '%Buffer Manager%' -AND t1.counter_name = 'Buffer cache hit ratio' -AND t2.counter_name = 'Buffer cache hit ratio base'; \ No newline at end of file diff --git a/performance-tuning/find-cache-hit-ratios.sql b/performance-tuning/find-cache-hit-ratios.sql deleted file mode 100644 index c8faf27..0000000 --- a/performance-tuning/find-cache-hit-ratios.sql +++ /dev/null @@ -1,31 +0,0 @@ -DECLARE @PERF_LARGE_RAW_FRACTION INT = 537003264 - ,@PERF_LARGE_RAW_BASE INT = 1073939712; - -SELECT dopc_fraction.object_name AS [Performance object] - ,dopc_fraction.instance_name AS [Counter instance] - ,dopc_fraction.counter_name AS [Counter name] - --when divisor is 0, return I return NULL to indicate - --divide by 0/no values captured - ,CONVERT( DECIMAL(38, 2), CAST(dopc_fraction.cntr_value AS FLOAT) / CAST(CASE dopc_base.cntr_value - WHEN 0 THEN NULL - ELSE dopc_base.cntr_value - END AS FLOAT) - ) AS Value -FROM sys.dm_os_performance_counters AS dopc_base - JOIN sys.dm_os_performance_counters AS dopc_fraction - ON dopc_base.cntr_type = @PERF_LARGE_RAW_BASE - AND dopc_fraction.cntr_type = @PERF_LARGE_RAW_FRACTION - AND dopc_base.object_name = dopc_fraction.object_name - AND dopc_base.instance_name = dopc_fraction.instance_name - AND ( - REPLACE(UPPER(dopc_base.counter_name), 'BASE', '') = UPPER(dopc_fraction.counter_name) - --Worktables From Cache has "odd" name where - --Ratio was left off - OR REPLACE(UPPER(dopc_base.counter_name), 'BASE', '') = REPLACE( - UPPER(dopc_fraction.counter_name) - ,'RATIO', '' - ) - ) -ORDER BY dopc_fraction.object_name - ,dopc_fraction.instance_name - ,dopc_fraction.counter_name; diff --git a/performance-tuning/find-cumulative-wait-stats.sql b/performance-tuning/find-cumulative-wait-stats.sql deleted file mode 100644 index e59844f..0000000 --- a/performance-tuning/find-cumulative-wait-stats.sql +++ /dev/null @@ -1,41 +0,0 @@ -WITH Waits AS ( - SELECT wait_type - ,wait_time_ms / 1000.0 AS WaitS - ,(wait_time_ms - signal_wait_time_ms) / 1000.0 AS ResourceS - ,signal_wait_time_ms / 1000.0 AS SignalS - ,waiting_tasks_count AS WaitCount - ,100.0 * wait_time_ms / SUM(wait_time_ms) OVER () AS Percentage - ,ROW_NUMBER() OVER (ORDER BY wait_time_ms DESC) AS RowNum - FROM sys.dm_os_wait_stats - WHERE wait_type NOT IN (N'CLR_SEMAPHORE', N'LAZYWRITER_SLEEP', N'RESOURCE_QUEUE', N'SQLTRACE_BUFFER_FLUSH' - ,N'SLEEP_TASK', N'SLEEP_SYSTEMTASK', N'WAITFOR', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION' - ,N'CHECKPOINT_QUEUE', N'REQUEST_FOR_DEADLOCK_SEARCH', N'XE_TIMER_EVENT' - ,N'XE_DISPATCHER_JOIN', N'LOGMGR_QUEUE', N'FT_IFTS_SCHEDULER_IDLE_WAIT' - ,N'BROKER_TASK_STOP', N'CLR_MANUAL_EVENT', N'CLR_AUTO_EVENT' - ,N'DISPATCHER_QUEUE_SEMAPHORE', N'TRACEWRITE', N'XE_DISPATCHER_WAIT', N'BROKER_TO_FLUSH' - ,N'BROKER_EVENTHANDLER', N'FT_IFTSHC_MUTEX', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP' - ,N'DIRTY_PAGE_POLL', N'SP_SERVER_DIAGNOSTICS_SLEEP' - ) -) - -SELECT W1.wait_type AS WaitType - ,CAST(W1.WaitS AS DECIMAL(14, 2)) AS Wait_S - ,CAST(W1.ResourceS AS DECIMAL(14, 2)) AS Resource_S - ,CAST(W1.SignalS AS DECIMAL(14, 2)) AS Signal_S - ,W1.WaitCount AS WaitCount - ,CAST(W1.Percentage AS DECIMAL(4, 2)) AS Percentage - ,CAST((W1.WaitS / W1.WaitCount) AS DECIMAL(14, 4)) AS AvgWait_S - ,CAST((W1.ResourceS / W1.WaitCount) AS DECIMAL(14, 4)) AS AvgRes_S - ,CAST((W1.SignalS / W1.WaitCount) AS DECIMAL(14, 4)) AS AvgSig_S -FROM Waits AS W1 - INNER JOIN Waits AS W2 - ON W2.RowNum <= W1.RowNum -GROUP BY W1.RowNum - ,W1.wait_type - ,W1.WaitS - ,W1.ResourceS - ,W1.SignalS - ,W1.WaitCount - ,W1.Percentage -HAVING SUM(W2.Percentage) - W1.Percentage < 95; -- percentage threshold -GO diff --git a/performance-tuning/find-memory-usage.sql b/performance-tuning/find-memory-usage.sql deleted file mode 100644 index e13d9fc..0000000 --- a/performance-tuning/find-memory-usage.sql +++ /dev/null @@ -1,186 +0,0 @@ -/*============================================================================ - Script to report Memory usage details of a SQL Server instance - Author: Sakthivel Chidambaram, Microsoft http://blogs.msdn.com/b/sqlsakthi - - Date: June 2012 - Version: V2 - - V1: Initial Release - V2: Added PLE, Memory grants pending, Checkpoint, Lazy write,Free list counters - - THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF - ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED - TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A - PARTICULAR PURPOSE. - -============================================================================*/ --- We don't need the row count -SET NOCOUNT ON; - --- Get size of SQL Server Page in bytes -DECLARE @pg_size INT - ,@Instancename VARCHAR(50); -SELECT @pg_size = low -FROM master..spt_values -WHERE number = 1 -AND type = 'E'; - --- Extract perfmon counters to a temporary table -IF OBJECT_ID('tempdb..#perfmon_counters') IS NOT NULL - DROP TABLE #perfmon_counters; -SELECT * -INTO #perfmon_counters -FROM sys.dm_os_performance_counters; - --- Get SQL Server instance name -SELECT @Instancename = LEFT(object_name, (CHARINDEX(':', object_name))) -FROM #perfmon_counters -WHERE counter_name = 'Buffer cache hit ratio'; - --- Print Memory usage details -PRINT '----------------------------------------------------------------------------------------------------'; -PRINT 'Memory usage details for SQL Server instance ' + @@SERVERNAME + ' (' - + CAST(SERVERPROPERTY('productversion') AS VARCHAR) + ' - ' + SUBSTRING(@@VERSION, CHARINDEX('X', @@VERSION), 4) - + ' - ' + CAST(SERVERPROPERTY('edition') AS VARCHAR) + ')'; -PRINT '----------------------------------------------------------------------------------------------------'; -SELECT 'Memory visible to the Operating System'; ---SELECT CEILING(physical_memory_in_bytes / 1048576.0) AS [Physical Memory_MB] --- ,CEILING(physical_memory_in_bytes / 1073741824.0) AS [Physical Memory_GB] --- ,CEILING(virtual_memory_in_bytes / 1073741824.0) AS [Virtual Memory GB] -SELECT CEILING(physical_memory_kb / 1024.0) AS [Physical Memory_MB] - ,CEILING(physical_memory_kb / 1048576.0) AS [Physical Memory_GB] - ,CEILING(virtual_memory_kb / 1048576.0) AS [Virtual Memory GB] -FROM sys.dm_os_sys_info; -SELECT 'Buffer Pool Usage at the Moment'; ---SELECT (bpool_committed * 8) / 1024.0 AS BPool_Committed_MB --- ,(bpool_commit_target * 8) / 1024.0 AS BPool_Commit_Tgt_MB --- ,(bpool_visible * 8) / 1024.0 AS BPool_Visible_MB -SELECT (committed_kb * 8) / 1024.0 AS BPool_Committed_MB - ,(committed_target_kb * 8) / 1024.0 AS BPool_Commit_Tgt_MB - ,(visible_target_kb * 8) / 1024.0 AS BPool_Visible_MB -FROM sys.dm_os_sys_info; -SELECT 'Total Memory used by SQL Server Buffer Pool as reported by Perfmon counters'; -SELECT cntr_value AS Mem_KB - ,cntr_value / 1024.0 AS Mem_MB - ,(cntr_value / 1048576.0) AS Mem_GB -FROM #perfmon_counters -WHERE counter_name = 'Total Server Memory (KB)'; -SELECT 'Memory needed as per current Workload for SQL Server instance'; -SELECT cntr_value AS Mem_KB - ,cntr_value / 1024.0 AS Mem_MB - ,(cntr_value / 1048576.0) AS Mem_GB -FROM #perfmon_counters -WHERE counter_name = 'Target Server Memory (KB)'; -SELECT 'Total amount of dynamic memory the server is using for maintaining connections'; -SELECT cntr_value AS Mem_KB - ,cntr_value / 1024.0 AS Mem_MB - ,(cntr_value / 1048576.0) AS Mem_GB -FROM #perfmon_counters -WHERE counter_name = 'Connection Memory (KB)'; -SELECT 'Total amount of dynamic memory the server is using for locks'; -SELECT cntr_value AS Mem_KB - ,cntr_value / 1024.0 AS Mem_MB - ,(cntr_value / 1048576.0) AS Mem_GB -FROM #perfmon_counters -WHERE counter_name = 'Lock Memory (KB)'; -SELECT 'Total amount of dynamic memory the server is using for the dynamic SQL cache'; -SELECT cntr_value AS Mem_KB - ,cntr_value / 1024.0 AS Mem_MB - ,(cntr_value / 1048576.0) AS Mem_GB -FROM #perfmon_counters -WHERE counter_name = 'SQL Cache Memory (KB)'; -SELECT 'Total amount of dynamic memory the server is using for query optimization'; -SELECT cntr_value AS Mem_KB - ,cntr_value / 1024.0 AS Mem_MB - ,(cntr_value / 1048576.0) AS Mem_GB -FROM #perfmon_counters -WHERE counter_name = 'Optimizer Memory (KB) '; -SELECT 'Total amount of dynamic memory used for hash, sort and create index operations.'; -SELECT cntr_value AS Mem_KB - ,cntr_value / 1024.0 AS Mem_MB - ,(cntr_value / 1048576.0) AS Mem_GB -FROM #perfmon_counters -WHERE counter_name = 'Granted Workspace Memory (KB) '; -SELECT 'Total Amount of memory consumed by cursors'; -SELECT cntr_value AS Mem_KB - ,cntr_value / 1024.0 AS Mem_MB - ,(cntr_value / 1048576.0) AS Mem_GB -FROM #perfmon_counters -WHERE counter_name = 'Cursor memory usage' -AND instance_name = '_Total'; -SELECT 'Number of pages in the buffer pool (includes database, free, and stolen).'; -SELECT cntr_value AS [8KB_Pages] - ,(cntr_value * @pg_size) / 1024.0 AS Pages_in_KB - ,(cntr_value * @pg_size) / 1048576.0 AS Pages_in_MB -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Buffer Manager' -AND counter_name = 'Total pages'; -SELECT 'Number of Data pages in the buffer pool'; -SELECT cntr_value AS [8KB_Pages] - ,(cntr_value * @pg_size) / 1024.0 AS Pages_in_KB - ,(cntr_value * @pg_size) / 1048576.0 AS Pages_in_MB -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Buffer Manager' -AND counter_name = 'Database pages'; -SELECT 'Number of Free pages in the buffer pool'; -SELECT cntr_value AS [8KB_Pages] - ,(cntr_value * @pg_size) / 1024.0 AS Pages_in_KB - ,(cntr_value * @pg_size) / 1048576.0 AS Pages_in_MB -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Buffer Manager' -AND counter_name = 'Free pages'; -SELECT 'Number of Reserved pages in the buffer pool'; -SELECT cntr_value AS [8KB_Pages] - ,(cntr_value * @pg_size) / 1024.0 AS Pages_in_KB - ,(cntr_value * @pg_size) / 1048576.0 AS Pages_in_MB -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Buffer Manager' -AND counter_name = 'Reserved pages'; -SELECT 'Number of Stolen pages in the buffer pool'; -SELECT cntr_value AS [8KB_Pages] - ,(cntr_value * @pg_size) / 1024.0 AS Pages_in_KB - ,(cntr_value * @pg_size) / 1048576.0 AS Pages_in_MB -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Buffer Manager' -AND counter_name = 'Stolen pages'; -SELECT 'Number of Plan Cache pages in the buffer pool'; -SELECT cntr_value AS [8KB_Pages] - ,(cntr_value * @pg_size) / 1024.0 AS Pages_in_KB - ,(cntr_value * @pg_size) / 1048576.0 AS Pages_in_MB -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Plan Cache' -AND counter_name = 'Cache Pages' -AND instance_name = '_Total'; -SELECT 'Page Life Expectancy - Number of seconds a page will stay in the buffer pool without references'; -SELECT cntr_value AS [Page Life in seconds] - ,CASE WHEN (cntr_value > 300) THEN 'PLE is Healthy' - ELSE 'PLE is not Healthy' - END AS [PLE Status] -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Buffer Manager' -AND counter_name = 'Page life expectancy'; -SELECT 'Number of requests per second that had to wait for a free page'; -SELECT cntr_value AS [Free list stalls/sec] -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Buffer Manager' -AND counter_name = 'Free list stalls/sec'; -SELECT 'Number of pages flushed to disk/sec by a checkpoint or other operation that require all dirty pages to be flushed'; -SELECT cntr_value AS [Checkpoint pages/sec] -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Buffer Manager' -AND counter_name = 'Checkpoint pages/sec'; -SELECT 'Number of buffers written per second by the buffer manager"s lazy writer'; -SELECT cntr_value AS [Lazy writes/sec] -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Buffer Manager' -AND counter_name = 'Lazy writes/sec'; -SELECT 'Total number of processes waiting for a workspace memory grant'; -SELECT cntr_value AS [Memory Grants Pending] -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Memory Manager' -AND counter_name = 'Memory Grants Pending'; -SELECT 'Total number of processes that have successfully acquired a workspace memory grant'; -SELECT cntr_value AS [Memory Grants Outstanding] -FROM #perfmon_counters -WHERE object_name = @Instancename + 'Memory Manager' -AND counter_name = 'Memory Grants Outstanding'; diff --git a/performance-tuning/find-objects-in-memory.sql b/performance-tuning/find-objects-in-memory.sql deleted file mode 100644 index 3a8ed5e..0000000 --- a/performance-tuning/find-objects-in-memory.sql +++ /dev/null @@ -1,65 +0,0 @@ --- Note: querying sys.dm_os_buffer_descriptors --- requires the VIEW_SERVER_STATE permission. - -DECLARE @total_buffer INT; - -SELECT @total_buffer = cntr_value -FROM sys.dm_os_performance_counters -WHERE RTRIM(object_name) LIKE '%Buffer Manager' -AND counter_name = 'Total Pages'; - -;WITH src AS ( - SELECT database_id - ,COUNT_BIG(*) AS db_buffer_pages - FROM sys.dm_os_buffer_descriptors - --WHERE database_id BETWEEN 5 AND 32766 - GROUP BY database_id -) -SELECT CASE src.database_id - WHEN 32767 THEN 'Resource DB' - ELSE DB_NAME(src.database_id) - END AS db_name - ,src.db_buffer_pages - ,src.db_buffer_pages / 128 AS db_buffer_MB - ,CONVERT(DECIMAL(6, 3), src.db_buffer_pages * 100.0 / @total_buffer) AS db_buffer_percent -FROM src -ORDER BY db_buffer_MB DESC; - - -USE rp_prod; -GO - -;WITH src AS ( - SELECT o.name AS Object - ,o.type_desc AS Type - ,COALESCE(i.name, '') AS [Index] - ,i.type_desc AS Index_Type - ,p.object_id - ,p.index_id - ,au.allocation_unit_id - FROM sys.partitions AS p - INNER JOIN sys.allocation_units AS au - ON p.hobt_id = au.container_id - INNER JOIN sys.objects AS o - ON p.object_id = o.object_id - INNER JOIN sys.indexes AS i - ON o.object_id = i.object_id - AND p.index_id = i.index_id - WHERE au.type IN (1, 2, 3) - AND o.is_ms_shipped = 0 - ) -SELECT src.Object - ,src.Type - ,src.[Index] - ,src.Index_Type - ,COUNT_BIG(b.page_id) AS buffer_pages - ,COUNT_BIG(b.page_id) / 128 AS buffer_mb -FROM src - INNER JOIN sys.dm_os_buffer_descriptors AS b - ON src.allocation_unit_id = b.allocation_unit_id -WHERE b.database_id = DB_ID() -GROUP BY src.Object - ,src.Type - ,src.[Index] - ,src.Index_Type -ORDER BY buffer_pages DESC; \ No newline at end of file diff --git a/performance-tuning/find-plan-cache-worst-queries.sql b/performance-tuning/find-plan-cache-worst-queries.sql deleted file mode 100644 index 15fd9f3..0000000 --- a/performance-tuning/find-plan-cache-worst-queries.sql +++ /dev/null @@ -1,125 +0,0 @@ ---****************** --- (C) 2013, Brent Ozar Unlimited. --- See http://BrentOzar.com/go/eula for the End User Licensing Agreement. - ---This script suitable only for test purposes. ---Scripts may contain treacherous commands that are bad for production servers! ---****************** - - ---Let's look at the top ranking queries in the plan cache ---We're looking by CPU ---This query works with only 2008 and higher -DECLARE @DBID SMALLINT = DB_ID('rp_prod'); - -;WITH top_queries_by_hash AS ( - SELECT TOP (25) - qs.query_hash - ,COUNT(DISTINCT qs.plan_handle) AS number_of_plans - ,COUNT(DISTINCT qs.query_plan_hash) AS distinct_plans - ,MAX(qs.plan_handle) AS max_plan_handle - ,MAX(qs.plan_generation_num) AS max_plan_generation_number - ,MIN(qs.creation_time) AS min_creation_time - ,MAX(qs.last_execution_time) AS max_last_execution_time - ,SUM(qs.execution_count) AS execution_count - ,SUM(qs.total_worker_time) AS total_worker_time - ,SUM(qs.total_physical_reads) AS total_physical_reads - ,SUM(qs.total_logical_writes) AS total_logical_writes - ,SUM(qs.total_logical_reads) AS total_logical_reads - ,SUM(qs.total_clr_time) AS total_clr_time - ,SUM(qs.total_elapsed_time) AS total_elapsed_time - FROM sys.dm_exec_query_stats qs - CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st - WHERE st.dbid = @DBID - GROUP BY qs.query_hash - ORDER BY total_worker_time DESC -) -SELECT tq.number_of_plans AS [# Plans] - ,tq.distinct_plans AS [Distinct Plans] - ,tq.total_worker_time / tq.execution_count AS [Avg CPU] - ,tq.total_worker_time AS [Total CPU] - ,CAST(ROUND(100.00 * tq.total_worker_time / (SELECT SUM(total_worker_time) FROM sys.dm_exec_query_stats), 2) AS MONEY) AS [% CPU] - ,CAST(tq.total_elapsed_time / tq.execution_count / 1000. AS BIGINT) AS [Avg Duration ms] - ,CAST(ROUND(tq.total_elapsed_time / 1000., 2) AS BIGINT) AS [Total Duration ms] - ,CAST(ROUND(100.00 * tq.total_elapsed_time / (SELECT SUM(total_elapsed_time) FROM sys.dm_exec_query_stats), 2) AS MONEY) AS [% Duration] - ,tq.total_logical_reads / tq.execution_count AS [Avg Reads] - ,tq.total_logical_reads AS [Total Reads] - ,CAST(ROUND(100.00 * tq.total_logical_reads / (SELECT SUM(total_logical_reads) FROM sys.dm_exec_query_stats), 2) AS MONEY) AS [% Reads] - ,tq.execution_count AS [Execution Count] - ,CAST(ROUND(100.00 * tq.execution_count / (SELECT SUM(execution_count) FROM sys.dm_exec_query_stats), 2) AS MONEY) AS [% Executions] - ,CASE DATEDIFF(mi, tq.min_creation_time, tq.max_last_execution_time) - WHEN 0 THEN 0 - ELSE - CAST((1.00 * tq.execution_count / DATEDIFF(mi, tq.min_creation_time, tq.max_last_execution_time)) AS MONEY) - END AS [Executions/Min] - ,tq.min_creation_time AS [Earliest Plan Created] - ,tq.max_last_execution_time AS [Last Execution Time] - ,tq.query_hash AS [Query Hash] - ,OBJECT_NAME(st.objectid) AS [SP Name] - ,SUBSTRING( st.text, (qs.statement_start_offset / 2) + 1, ((CASE qs.statement_end_offset - WHEN -1 THEN DATALENGTH(st.text) - ELSE qs.statement_end_offset - END - qs.statement_start_offset - ) / 2 - ) + 1 - ) AS query_text - ,qp.query_plan -FROM top_queries_by_hash tq - JOIN sys.dm_exec_query_stats qs - ON tq.query_hash = qs.query_hash - AND tq.max_plan_handle = qs.plan_handle - CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st - CROSS APPLY sys.dm_exec_query_plan(tq.max_plan_handle) AS qp ---ORDER BY [Total CPU] DESC -ORDER BY [Avg Duration ms] DESC -OPTION (RECOMPILE); ---To order by [Total Reads], change it in the top CTE as well as here -GO - - - ---Query #1 ---Action plan: Indexing on Production.Transation history ---Research the ant-pattern in the where clause - - - - - - - - - - - ---Query #2 ---Action plan: Easy first step-- indexes on Person.Address - - - - - - - - - - - ---Query #3 ---Action plan: Test parameterization - - - - - - - - ---Query #4 ---Action Plan: Identify how to cache - - - - - - diff --git a/performance-tuning/find-procedure-performance.sql b/performance-tuning/find-procedure-performance.sql deleted file mode 100644 index a214aa6..0000000 --- a/performance-tuning/find-procedure-performance.sql +++ /dev/null @@ -1,100 +0,0 @@ -USE rp_prod; -GO - -DECLARE @l_SPName sysname; ---SET @l_SPName = 'GetLoansForDeal' - --- Get Top 100 executed SP's ordered by execution count -SELECT TOP (100) - qt.text AS [SP Name] - ,qs.execution_count AS [Execution Count] - ,qs.execution_count / DATEDIFF(SECOND, qs.creation_time, GETDATE()) AS [Calls/Second] - ,qs.total_worker_time / qs.execution_count AS AvgWorkerTime - ,qs.total_worker_time AS TotalWorkerTime - ,qs.total_elapsed_time / qs.execution_count AS AvgElapsedTime - ,qs.max_logical_reads - ,qs.max_logical_writes - ,qs.total_physical_reads - ,DATEDIFF(MINUTE, qs.creation_time, GETDATE()) AS [Age in Cache] -FROM sys.dm_exec_query_stats AS qs - CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt -WHERE qt.dbid = DB_ID() -- Filter by current database -ORDER BY qs.execution_count DESC; - --- Get Top 20 executed SP's ordered by total worker time (CPU pressure) -SELECT TOP (20) - qt.text AS [SP Name] - ,qs.total_worker_time AS TotalWorkerTime - ,qs.total_worker_time / qs.execution_count AS AvgWorkerTime - ,qs.execution_count AS [Execution Count] - ,ISNULL(qs.execution_count / DATEDIFF(SECOND, qs.creation_time, GETDATE()), 0) AS [Calls/Second] - ,ISNULL(qs.total_elapsed_time / qs.execution_count, 0) AS AvgElapsedTime - ,qs.max_logical_reads - ,qs.max_logical_writes - ,DATEDIFF(MINUTE, qs.creation_time, GETDATE()) AS [Age in Cache] -FROM sys.dm_exec_query_stats AS qs - CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt -WHERE qt.dbid = DB_ID() -- Filter by current database -ORDER BY qs.total_worker_time DESC; - --- Get Top 20 executed SP's ordered by logical reads (memory pressure) -SELECT TOP (20) - qt.text AS [SP Name] - ,qs.total_logical_reads - ,qs.execution_count AS [Execution Count] - ,qs.total_logical_reads / qs.execution_count AS AvgLogicalReads - ,qs.execution_count / DATEDIFF(SECOND, qs.creation_time, GETDATE()) AS [Calls/Second] - ,qs.total_worker_time / qs.execution_count AS AvgWorkerTime - ,qs.total_worker_time AS TotalWorkerTime - ,qs.total_elapsed_time / qs.execution_count AS AvgElapsedTime - ,qs.total_logical_writes - ,qs.max_logical_reads - ,qs.max_logical_writes - ,qs.total_physical_reads - ,DATEDIFF(MINUTE, qs.creation_time, GETDATE()) AS [Age in Cache] - ,qt.dbid -FROM sys.dm_exec_query_stats AS qs - CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt -WHERE qt.dbid = DB_ID() -- Filter by current database -ORDER BY qs.total_logical_reads DESC; - --- Get Top 20 executed SP's ordered by physical reads (read I/O pressure) -SELECT TOP (20) - qt.text AS [SP Name] - ,qs.total_physical_reads - ,qs.total_physical_reads / qs.execution_count AS [Avg Physical Reads] - ,qs.execution_count AS [Execution Count] - ,qs.execution_count / DATEDIFF(SECOND, qs.creation_time, GETDATE()) AS [Calls/Second] - ,qs.total_worker_time / qs.execution_count AS AvgWorkerTime - ,qs.total_worker_time AS TotalWorkerTime - ,qs.total_elapsed_time / qs.execution_count AS AvgElapsedTime - ,qs.max_logical_reads - ,qs.max_logical_writes - ,DATEDIFF(MINUTE, qs.creation_time, GETDATE()) AS [Age in Cache] - ,qt.dbid -FROM sys.dm_exec_query_stats AS qs - CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt -WHERE qt.dbid = DB_ID() -- Filter by current database -ORDER BY qs.total_physical_reads DESC; - --- Get Top 20 executed SP's ordered by logical writes/minute -SELECT TOP (20) - qt.text AS [SP Name] - ,qs.total_logical_writes - ,qs.total_logical_writes / NULLIF(qs.execution_count, 0) AS AvgLogicalWrites - ,qs.total_logical_writes / DATEDIFF(MINUTE, qs.creation_time, GETDATE()) AS [Logical Writes/Min] - ,qs.execution_count AS [Execution Count] - ,qs.execution_count / DATEDIFF(SECOND, qs.creation_time, GETDATE()) AS [Calls/Second] - ,qs.total_worker_time / NULLIF(qs.execution_count, 0) AS AvgWorkerTime - ,qs.total_worker_time AS TotalWorkerTime - ,qs.total_elapsed_time / NULLIF(qs.execution_count, 0) AS AvgElapsedTime - ,qs.max_logical_reads - ,qs.max_logical_writes - ,qs.total_physical_reads - ,DATEDIFF(MINUTE, qs.creation_time, GETDATE()) AS [Age in Cache] - ,qs.total_physical_reads / NULLIF(qs.execution_count, 0) AS [Avg Physical Reads] - ,qt.dbid -FROM sys.dm_exec_query_stats AS qs - CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt -WHERE qt.dbid = DB_ID() -- Filter by current database -ORDER BY qs.total_logical_writes DESC; diff --git a/performance-tuning/find-procedure-worst-statement.sql b/performance-tuning/find-procedure-worst-statement.sql deleted file mode 100644 index ca07318..0000000 --- a/performance-tuning/find-procedure-worst-statement.sql +++ /dev/null @@ -1,20 +0,0 @@ -DECLARE @sql_handle VARBINARY(64); - -SELECT @sql_handle = sql_handle -FROM sys.dm_exec_procedure_stats -WHERE object_id = OBJECT_ID('dbo.p_dv_get_raked_tranche_nonsense'); - -SELECT CAST(qp.query_plan AS XML) AS XML_Plan - ,SUBSTRING( - st.text, qs.statement_start_offset / 2 + 1 - ,((CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(st.text) - ELSE qs.statement_end_offset - END - ) - qs.statement_start_offset - ) / 2 + 1 - ) AS SqlText - ,qs.* -FROM sys.dm_exec_query_stats qs - CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st - CROSS APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) qp -WHERE qs.sql_handle = @sql_handle; diff --git a/performance-tuning/index-get-IO-counts.sql b/performance-tuning/index-get-IO-counts.sql deleted file mode 100644 index 7cf7ddd..0000000 --- a/performance-tuning/index-get-IO-counts.sql +++ /dev/null @@ -1,96 +0,0 @@ -DECLARE @TblName NVARCHAR(128) - , @IndxId INT - , @ColList NVARCHAR(2000) - , @ColIncList NVARCHAR(2000) - , @TblId INT; - -SET @TblName = NULL; - -IF @TblName IS NOT NULL - SET @TblId = OBJECT_ID(@TblName); - -DECLARE @IndxCols TABLE ( - TblId INT - , IndxId INT - , [Columns] NVARCHAR(4000) - , [Included Columns] NVARCHAR(4000) -); - -INSERT INTO @IndxCols ( - TblId - , IndxId - , [Columns] - , [Included Columns] -) -SELECT i.object_id - , i.index_id - , [Columns] = STUFF(( - SELECT CASE WHEN ic.is_descending_key = 1 THEN ', ' + c.name + '(-)' - ELSE ', ' + c.name - END - FROM sys.index_columns ic - INNER JOIN sys.columns c - ON c.object_id = ic.object_id - AND c.column_id = ic.column_id - WHERE ic.object_id = i.object_id - AND ic.index_id = i.index_id - AND ic.is_included_column = 0 - ORDER BY ic.key_ordinal - FOR XML PATH ('') - ),1,2,'') - , [Included Columns] = STUFF(( - SELECT CASE WHEN ic.is_descending_key = 1 THEN ', ' + c.name + '(-)' - ELSE ', ' + c.name - END - FROM sys.index_columns ic - INNER JOIN sys.columns c - ON c.object_id = ic.object_id - AND c.column_id = ic.column_id - WHERE ic.object_id = i.object_id - AND ic.index_id = i.index_id - AND ic.is_included_column = 1 - ORDER BY ic.key_ordinal - FOR XML PATH ('') - ),1,2,'') -FROM sys.indexes i -WHERE OBJECTPROPERTY(i.[object_id],'IsUserTable') = 1 -AND i.[object_id] = ISNULL(@TblId, i.[object_id]); - - -SELECT TblName = OBJECT_NAME(s.[object_id]) - , IndxName = i.name - , IndxId = i.index_id - , IndxType = i.type_desc - , PK = i.is_primary_key - , AK = i.is_unique - , FileGroup =d.name - , IndxColumns = c.[Columns] - , IncludedColumns = c.[Included Columns] - , TotalReads = SUM(user_seeks + user_scans + user_lookups) - , TotalWrites = SUM(user_updates) -FROM sys.dm_db_index_usage_stats AS s - INNER JOIN sys.indexes AS i - ON s.[object_id] = i.[object_id] - AND i.index_id = s.index_id - INNER JOIN sys.data_spaces AS d - ON i.data_space_id = d.data_space_id - INNER JOIN @IndxCols c - ON i.object_id = c.TblId - AND i.index_id = c.IndxId -WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 -AND s.database_id = DB_ID() -AND s.[object_id] = ISNULL(@TblId, s.[object_id]) -GROUP BY OBJECT_NAME(s.[object_id]) - , i.name - , i.index_id - , i.type_desc - , i.is_unique - , i.is_primary_key - , d.name - , c.[Columns] - , c.[Included Columns] -ORDER BY OBJECT_NAME(s.[object_id]) - , i.index_id - , TotalWrites DESC - , TotalReads DESC -OPTION (RECOMPILE); diff --git a/performance-tuning/index-plan-cache-usage.sql b/performance-tuning/index-plan-cache-usage.sql deleted file mode 100644 index 711a07d..0000000 --- a/performance-tuning/index-plan-cache-usage.sql +++ /dev/null @@ -1,107 +0,0 @@ -USE [?]; -GO - -CREATE TABLE #PlanCacheIndexes ( - StatementText VARCHAR(4000) - ,DatabaseName VARCHAR(128) - ,SchemaName VARCHAR(128) - ,TableName VARCHAR(128) - ,IndexName VARCHAR(128) - ,Indextype VARCHAR(128) - ,QueryPlan XML - ,UseCounts BIGINT -); - -SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - -DECLARE @TableName AS NVARCHAR(128) = 'TableName'; - --- Make sure the name passed is appropriately quoted -IF (LEFT(@TableName, 1) <> '[' AND RIGHT(@TableName, 1) <> ']') - SET @TableName = QUOTENAME(@TableName); --- Handle the case where the left or right was quoted manually but not the opposite side -IF LEFT(@TableName, 1) <> '[' - SET @TableName = '[' + @TableName; -IF RIGHT(@TableName, 1) <> ']' - SET @TableName = @TableName + ']'; - --- Collect parallel plan information --- Dig into the plan cache and find all plans using Indexes -WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan') -INSERT INTO #PlanCacheIndexes ( - StatementText - ,DatabaseName - ,SchemaName - ,TableName - ,IndexName - ,Indextype - ,QueryPlan - ,UseCounts -) -SELECT stmt.value('(@StatementText)[1]', 'varchar(max)') AS SQL_Text - ,obj.value('(@Database)[1]', 'varchar(128)') AS DatabaseName - ,obj.value('(@Schema)[1]', 'varchar(128)') AS SchemaName - ,obj.value('(@Table)[1]', 'varchar(128)') AS TableName - ,obj.value('(@Index)[1]', 'varchar(128)') AS IndexName - ,obj.value('(@IndexKind)[1]', 'varchar(128)') AS IndexKind - ,qp.query_plan - ,cp.usecounts -FROM sys.dm_exec_cached_plans AS cp - CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp - CROSS APPLY query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS batch(stmt) - CROSS APPLY stmt.nodes('.//IndexScan/Object[@Table=sql:variable("@TableName")]') AS TableName(obj) -OPTION (MAXDOP 1, RECOMPILE); -GO - -DECLARE @TableName AS NVARCHAR(128) = 'TableName'; - --- Return plan information -SELECT 'Plan Cache Indexes' AS ResultType - ,REPLACE(REPLACE(IndexName, '[', ''), ']', '') AS IndexName - ,Indextype - ,COUNT(IndexName) AS IndexUsageInstances - ,SUM(UseCounts) AS TimesIndexUsed -FROM #PlanCacheIndexes -GROUP BY IndexName - ,Indextype -ORDER BY SUM(UseCounts) DESC; - - --- Return Index usage stats for indexes that are not used in the plan cache -WITH IndexesUsed AS ( - SELECT DISTINCT - REPLACE(REPLACE(IndexName, '[', ''), ']', '') AS IndexName - FROM #PlanCacheIndexes -) -SELECT 'Index Usage Not In Plan Cache' AS ResultType - ,I.name AS IndexName - ,IUS.user_seeks + IUS.user_scans + IUS.user_lookups AS UserReads - ,IUS.user_updates -FROM sys.dm_db_index_usage_stats IUS - INNER JOIN sys.indexes I - ON IUS.object_id = I.object_id - AND I.index_id = IUS.index_id - LEFT OUTER JOIN IndexesUsed IU - ON I.name = IU.IndexName -WHERE i.object_id = OBJECT_ID(@TableName) -AND IU.IndexName IS NULL; - - --- find out that last time the index stats where reset --- How old are the index usage stats? -WITH IndexesUsed AS ( - SELECT DISTINCT - REPLACE(REPLACE(IndexName, '[', ''), ']', '') AS IndexName - FROM #PlanCacheIndexes -) -SELECT 'Index Stats Age' AS ResultType - ,I.name AS IndexName - ,CASE WHEN IU.IndexName IS NOT NULL THEN 'Y' - ELSE '' - END AS Cached - ,DATEDIFF(HOUR, STATS_DATE(I.object_id, I.index_id), GETDATE()) AS StatsAge_HRs -FROM sys.indexes I - LEFT OUTER JOIN IndexesUsed IU - ON I.name = IU.IndexName -WHERE I.object_id = OBJECT_ID(@TableName); -GO diff --git a/performance-tuning/plan-cache-flush.sql b/performance-tuning/plan-cache-flush.sql deleted file mode 100644 index 6c7c254..0000000 --- a/performance-tuning/plan-cache-flush.sql +++ /dev/null @@ -1,93 +0,0 @@ --- Eight different ways to clear the plan cache --- Glenn Berry --- SQLskills.com --- https://www.sqlskills.com/blogs/glenn/eight-different-ways-to-clear-the-sql-server-plan-cache/ - - --- Example 1 *********************** --- Remove all elements from the plan cache for the entire instance -DBCC FREEPROCCACHE; - - --- Example 2 *********************** --- Flush the plan cache for the entire instance and suppress the regular completion message --- "DBCC execution completed. If DBCC printed error messages, contact your system administrator." -DBCC FREEPROCCACHE WITH NO_INFOMSGS; - - --- Example 3 *********************** --- Flush the ad hoc and prepared plan cache for the entire instance -DBCC FREESYSTEMCACHE('SQL Plans'); - - --- Example 4 *********************** --- Flush the ad hoc and prepared plan cache for one resource pool - --- Get Resource Pool information -SELECT name AS [Resource Pool Name] - ,cache_memory_kb / 1024.0 AS [cache_memory (MB)] - ,used_memory_kb / 1024.0 AS [used_memory (MB)] -FROM sys.dm_resource_governor_resource_pools; - --- Flush the ad hoc and prepared plan cache for one resource pool -DBCC FREESYSTEMCACHE('SQL Plans', 'LimitedIOPool'); - - --- Example 5 ********************** --- Flush the entire plan cache for one resource pool - --- Get Resource Pool information -SELECT name AS [Resource Pool Name] - ,cache_memory_kb / 1024.0 AS [cache_memory (MB)] - ,used_memory_kb / 1024.0 AS [used_memory (MB)] -FROM sys.dm_resource_governor_resource_pools; - - --- Flush the plan cache for one resource pool -DBCC FREEPROCCACHE('LimitedIOPool'); - - --- Example 6 ********************** --- Remove all elements from the plan cache for one database (does not work in SQL Azure) - --- Get DBID from one database name first -DECLARE @intDBID INT; -SET @intDBID = (SELECT dbid FROM master.sys.sysdatabases WHERE name = N'rp_util'); - --- Flush the plan cache for one database only -DBCC FLUSHPROCINDB(@intDBID); - - --- Example 7 ********************** --- Clear plan cache for the current database - -USE rp_util; -GO --- Clear plan cache for the current database --- New in SQL Server 2016 and SQL Azure -ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE; - - - --- Example 8 ********************** --- Remove one query plan from the cache - -USE rp_util; -GO - --- Run a stored procedure or query -EXEC dbo.uspGetEmployeeManagers 9; - --- Find the plan handle for that query --- OPTION (RECOMPILE) keeps this query from going into the plan cache -SELECT cp.plan_handle - ,cp.objtype - ,cp.usecounts - ,DB_NAME(st.dbid) AS DatabaseName -FROM sys.dm_exec_cached_plans AS cp - CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) AS st -WHERE OBJECT_NAME(st.objectid) LIKE N'%uspGetEmployeeManagers%' -OPTION (RECOMPILE); - --- Remove the specific query plan from the cache using the plan handle from the above query -DBCC FREEPROCCACHE(0x050011007A2CC30E204991F30200000001000000000000000000000000000000000000000000000000000000); diff --git a/plan-cache-find-implicit-conversions.sql b/plan-cache-find-implicit-conversions.sql new file mode 100644 index 0000000..7485c32 --- /dev/null +++ b/plan-cache-find-implicit-conversions.sql @@ -0,0 +1,31 @@ +/***** +Finding Implicit Column Conversions in the Plan Cache +https://www.sqlskills.com/blogs/jonathan/finding-implicit-column-conversions-in-the-plan-cache/ +*****/ + + SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED + + DECLARE @dbname SYSNAME + SET @dbname = QUOTENAME(DB_NAME()); + + WITH XMLNAMESPACES + (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan') + SELECT + stmt.value('(@StatementText)[1]', 'varchar(max)'), + t.value('(ScalarOperator/Identifier/ColumnReference/@Schema)[1]', 'varchar(128)'), + t.value('(ScalarOperator/Identifier/ColumnReference/@Table)[1]', 'varchar(128)'), + t.value('(ScalarOperator/Identifier/ColumnReference/@Column)[1]', 'varchar(128)'), + ic.DATA_TYPE AS ConvertFrom, + ic.CHARACTER_MAXIMUM_LENGTH AS ConvertFromLength, + t.value('(@DataType)[1]', 'varchar(128)') AS ConvertTo, + t.value('(@Length)[1]', 'int') AS ConvertToLength, + query_plan + FROM sys.dm_exec_cached_plans AS cp + CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp + CROSS APPLY query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS batch(stmt) + CROSS APPLY stmt.nodes('.//Convert[@Implicit="1"]') AS n(t) + JOIN INFORMATION_SCHEMA.COLUMNS AS ic + ON QUOTENAME(ic.TABLE_SCHEMA) = t.value('(ScalarOperator/Identifier/ColumnReference/@Schema)[1]', 'varchar(128)') + AND QUOTENAME(ic.TABLE_NAME) = t.value('(ScalarOperator/Identifier/ColumnReference/@Table)[1]', 'varchar(128)') + AND ic.COLUMN_NAME = t.value('(ScalarOperator/Identifier/ColumnReference/@Column)[1]', 'varchar(128)') + WHERE t.exist('ScalarOperator/Identifier/ColumnReference[@Database=sql:variable("@dbname")][@Schema!="[sys]"]') = 1 diff --git a/plan-cache-find-longest-running-queries.sql b/plan-cache-find-longest-running-queries.sql new file mode 100644 index 0000000..5a66f91 --- /dev/null +++ b/plan-cache-find-longest-running-queries.sql @@ -0,0 +1,16 @@ +/* Execution plan cache */ +SELECT TOP (10) + sqltext.text AS query + ,querystats.execution_count + ,querystats.max_elapsed_time + ,ISNULL(querystats.total_elapsed_time / 1000 / NULLIF(querystats.execution_count, 0), 0) AS avg_elapsed_time + ,querystats.creation_time + ,querystats.last_execution_time + ,ISNULL(querystats.execution_count / 1000 / NULLIF(DATEDIFF(SECOND, querystats.creation_time, GETDATE()), 0), 0) AS freq_per_second + ,CAST(query_plan AS XML) AS plan_xml +FROM sys.dm_exec_query_stats as querystats + CROSS APPLY sys.dm_exec_text_query_plan (querystats.plan_handle, querystats.statement_start_offset, querystats.statement_end_offset) as textplan + CROSS APPLY sys.dm_exec_sql_text(querystats.sql_handle) AS sqltext +ORDER BY querystats.max_elapsed_time DESC +OPTION (RECOMPILE); +GO \ No newline at end of file diff --git a/plan-cache-find-query-using-index.sql b/plan-cache-find-query-using-index.sql new file mode 100644 index 0000000..302e588 --- /dev/null +++ b/plan-cache-find-query-using-index.sql @@ -0,0 +1,27 @@ +/* Execution plan cache */ +DECLARE @IndxName NVARCHAR(200) = N'%IndxName%'; + +SELECT + querystats.plan_handle, + querystats.query_hash, + SUBSTRING(sqltext.text, (querystats.statement_start_offset / 2) + 1, + (CASE querystats.statement_end_offset + WHEN -1 THEN DATALENGTH(sqltext.text) + ELSE querystats.statement_end_offset + END - querystats.statement_start_offset) / 2 + 1) AS sqltext, + querystats.execution_count, + querystats.total_logical_reads, + querystats.total_logical_writes, + querystats.creation_time, + querystats.last_execution_time, + CAST(query_plan AS xml) as plan_xml +FROM sys.dm_exec_query_stats as querystats +CROSS APPLY sys.dm_exec_text_query_plan + (querystats.plan_handle, querystats.statement_start_offset, querystats.statement_end_offset) + as textplan +CROSS APPLY sys.dm_exec_sql_text(querystats.sql_handle) AS sqltext +WHERE + textplan.query_plan like @IndxName +ORDER BY querystats.last_execution_time DESC +OPTION (RECOMPILE); +GO \ No newline at end of file diff --git a/query-default-trace.sql b/query-default-trace.sql new file mode 100644 index 0000000..093759c --- /dev/null +++ b/query-default-trace.sql @@ -0,0 +1,59 @@ +/* +http://jasonbrimhall.info/2018/12/28/sql-servers-black-box-recorder-def-trace/ +*/ + +-- generic +DECLARE @path NVARCHAR(260); + +SELECT @path=path +FROM sys.traces +WHERE is_default = 1; + +SELECT DISTINCT + TE.name AS EventName, DT.DatabaseName, DT.ApplicationName, DT.ObjectName, DT.LoginName, DT.StartTime +FROM fn_trace_gettable (@path, DEFAULT) DT + INNER JOIN sys.trace_events AS TE + ON DT.EventClass = te.trace_event_id; + +-- events and categories that are configured for capture in the default trace +SELECT te.name AS EventName + ,tca.name AS CategoryName + , CASE tca.type WHEN '0' THEN 'Normal' + WHEN '1' THEN 'Connection' + WHEN '2' THEN 'ERROR' END AS CategoryType + , t.path AS TracePath + , oa.logical_operator,oa.comparison_operator, oa.value AS FilteredValue + FROM sys.traces t + CROSS APPLY (SELECT DISTINCT gei.eventid FROM sys.fn_trace_geteventinfo(t.id) gei) ca + INNER JOIN sys.trace_events te + ON te.trace_event_id = ca.eventid + INNER JOIN sys.trace_categories tca + ON te.category_id = tca.category_id + OUTER APPLY (SELECT gfi.columnid,gfi.logical_operator,gfi.comparison_operator,gfi.value FROM sys.fn_trace_getfilterinfo(t.id) gfi) oa + WHERE t.is_default = 1 + + +-- server configs Audited via Def Trace +SELECT T.StartTime + , T.SPID + , T.LoginName + , T.HostName + , T.ApplicationName + , T.DatabaseName + --, ObjectName,sv.number AS ObjTypeVal, sv.name [ObjectType] + --, T.TextData + , ConfigOption = SUBSTRING(T.TextData,CHARINDEX('''',T.TextData)+1,CHARINDEX(' changed from ',T.TextData)-CHARINDEX('''',T.TextData)-2) + , PrevValue = SUBSTRING(T.TextData,CHARINDEX('from ',T.TextData)+5,CHARINDEX('to ',T.TextData)-CHARINDEX('from ',T.TextData)-5) + , NewValue = SUBSTRING(T.TextData,CHARINDEX('to ',T.TextData)+3,CHARINDEX('. Run',T.TextData)-CHARINDEX('to ',T.TextData)-3) + , EventName = te.name + , T.EventClass + FROM sys.fn_trace_gettable(CONVERT(VARCHAR(150), + ( SELECT REVERSE(SUBSTRING(REVERSE(path), + CHARINDEX('\',REVERSE(path)),256)) + 'log.trc' + FROM sys.traces + WHERE is_default = 1)), DEFAULT) AS T + INNER JOIN sys.trace_events AS te + ON T.EventClass = te.trace_event_id + WHERE T.EventClass = 22 + AND T.TextData LIKE '%config%' + ORDER BY T.StartTime DESC; \ No newline at end of file diff --git a/query-store-enable.sql b/query-store-enable.sql new file mode 100644 index 0000000..5f09498 --- /dev/null +++ b/query-store-enable.sql @@ -0,0 +1,2 @@ + +ALTER DATABASE [databasename] SET QUERY_STORE = ON (OPERATION_MODE = READ_WRITE); diff --git a/query-store-find-failed-plan-forcing.sql b/query-store-find-failed-plan-forcing.sql new file mode 100644 index 0000000..15555cb --- /dev/null +++ b/query-store-find-failed-plan-forcing.sql @@ -0,0 +1,16 @@ +SELECT qsqt.query_sql_text, + OBJECT_NAME(qsq.object_id) AS ProcedureName, + qsq.query_id, + qsp.query_plan_hash, + CAST(qsp.query_plan AS XML) AS query_plan, + qsp.is_forced_plan, + qsp.is_natively_compiled, + qsp.force_failure_count, + qsp.last_force_failure_reason_desc +FROM sys.query_store_query qsq + INNER JOIN sys.query_store_query_text qsqt ON qsqt.query_text_id = qsq.query_text_id + INNER JOIN sys.query_store_plan qsp ON qsp.query_id = qsq.query_id +WHERE qsp.is_forced_plan = 1 +AND qsp.force_failure_count > 0 +ORDER BY qsp.query_plan_hash + ,qsq.last_execution_time DESC diff --git a/query-store-find-good-values-for-CostThresholdForParallelism.sql b/query-store-find-good-values-for-CostThresholdForParallelism.sql new file mode 100644 index 0000000..6cf5bf1 --- /dev/null +++ b/query-store-find-good-values-for-CostThresholdForParallelism.sql @@ -0,0 +1,23 @@ +/******************************************************************************** +NEED TO COPY IN query_ids FROM query-store-find-most-freq-run-queries.sql +********************************************************************************/ + +DECLARE @Top INT = 5 + ,@FromTime DATETIME = '2018-12-17 00:00:00' + ,@ToTime DATETIME = GETDATE(); + +SELECT * FROM +(SELECT qsq.query_id, qsrt.avg_duration, + 5+10*(DATEDIFF(HOUR, @FromTime, qsrsi.start_time)) AS CostThreshold + FROM sys.query_store_query qsq + INNER JOIN sys.query_store_query_text qsqt ON qsqt.query_text_id = qsq.query_text_id + INNER JOIN sys.query_store_plan qsp ON qsp.query_id = qsq.query_id + INNER JOIN sys.query_store_runtime_stats qsrt ON qsrt.plan_id = qsp.plan_id + INNER JOIN sys.query_store_runtime_stats_interval qsrsi ON qsrsi.runtime_stats_interval_id = qsrt.runtime_stats_interval_id +WHERE qsq.query_id IN (17, 18, 62551, 51, 62578) + AND qsrsi.start_time >= @FromTime AND qsrsi.start_time < @ToTime +) AS RawStats +PIVOT ( + avg(avg_duration) + FOR query_id IN ([17], [18], [62551], [51], [62578]) +) AS QueryPerformanceOverTime diff --git a/query-store-find-high-cpu-queries.sql b/query-store-find-high-cpu-queries.sql new file mode 100644 index 0000000..2f03036 --- /dev/null +++ b/query-store-find-high-cpu-queries.sql @@ -0,0 +1,14 @@ +SELECT TOP 10 rs.avg_cpu_time , qt.query_sql_text, + q.query_id, qt.query_text_id, p.plan_id, rs.runtime_stats_id, + rsi.start_time, rsi.end_time, rs.avg_rowcount, rs.count_executions +FROM sys.query_store_query_text AS qt +JOIN sys.query_store_query AS q + ON qt.query_text_id = q.query_text_id +JOIN sys.query_store_plan AS p + ON q.query_id = p.query_id +JOIN sys.query_store_runtime_stats AS rs + ON p.plan_id = rs.plan_id +JOIN sys.query_store_runtime_stats_interval AS rsi + ON rsi.runtime_stats_interval_id = rs.runtime_stats_interval_id +WHERE rsi.start_time >= DATEADD(hour, -1, GETUTCDATE()) +ORDER BY rs.avg_cpu_time DESC; \ No newline at end of file diff --git a/query-store-find-most-freq-run-queries.sql b/query-store-find-most-freq-run-queries.sql new file mode 100644 index 0000000..ab3c17a --- /dev/null +++ b/query-store-find-most-freq-run-queries.sql @@ -0,0 +1,18 @@ +DECLARE @Top INT = 5 + ,@FromTime DATETIME = '2019-01-01 00:00:00' + ,@ToTime DATETIME = GETDATE(); + +SELECT TOP(@Top) qsp.query_id, + OBJECT_NAME(qsq.object_id) AS sproc, + qsqt.query_sql_text, + SUM(qsrt.count_executions) as count_executions + FROM sys.query_store_query qsq + INNER JOIN sys.query_store_query_text qsqt ON qsqt.query_text_id = qsq.query_text_id + INNER JOIN sys.query_store_plan qsp ON qsp.query_id = qsq.query_id + INNER JOIN sys.query_store_runtime_stats qsrt ON qsrt.plan_id = qsp.plan_id + INNER JOIN sys.query_store_runtime_stats_interval qsrsi ON qsrsi.runtime_stats_interval_id = qsrt.runtime_stats_interval_id +WHERE qsrsi.start_time >= @FromTime AND qsrsi.start_time < @ToTime +GROUP BY qsp.query_id, + OBJECT_NAME(qsq.object_id), + qsqt.query_sql_text +ORDER BY SUM(qsrt.count_executions) DESC; diff --git a/query-store-find-query-using-index.sql b/query-store-find-query-using-index.sql new file mode 100644 index 0000000..5791412 --- /dev/null +++ b/query-store-find-query-using-index.sql @@ -0,0 +1,31 @@ +/* Query Store */ +DECLARE @IndxName NVARCHAR(200) = N'%IndxName%'; + +SELECT + qsq.query_id, + qsq.query_hash, + (SELECT TOP 1 qsqt.query_sql_text FROM sys.query_store_query_text qsqt + WHERE qsqt.query_text_id = MAX(qsq.query_text_id)) AS sqltext, + SUM(qrs.count_executions) AS execution_count, + SUM(qrs.count_executions) * AVG(qrs.avg_logical_io_reads) as est_logical_reads, + SUM(qrs.count_executions) * AVG(qrs.avg_logical_io_writes) as est_writes, + MIN(qrs.last_execution_time AT TIME ZONE 'Eastern Standard Time') as min_execution_time_EST, + MAX(qrs.last_execution_time AT TIME ZONE 'Eastern Standard Time') as last_execution_time_EST, + SUM(qsq.count_compiles) AS sum_compiles, + TRY_CONVERT(XML, (SELECT TOP 1 qsp2.query_plan from sys.query_store_plan qsp2 + WHERE qsp2.query_id=qsq.query_id + ORDER BY qsp2.plan_id DESC)) AS query_plan +FROM sys.query_store_query qsq +JOIN sys.query_store_plan qsp on qsq.query_id=qsp.query_id +CROSS APPLY (SELECT TRY_CONVERT(XML, qsp.query_plan) AS query_plan_xml) AS qpx +JOIN sys.query_store_runtime_stats qrs on qsp.plan_id = qrs.plan_id +JOIN sys.query_store_runtime_stats_interval qsrsi on qrs.runtime_stats_interval_id=qsrsi.runtime_stats_interval_id +WHERE + qsp.query_plan like @IndxName + AND qsp.query_plan not like '%query_store_runtime_stats%' /* Not a query store query */ + AND qsp.query_plan not like '%dm_exec_sql_text%' /* Not a query searching the plan cache */ +GROUP BY + qsq.query_id, qsq.query_hash +ORDER BY est_logical_reads DESC +OPTION (RECOMPILE); +GO \ No newline at end of file diff --git a/query-store-find-query-with-run-stats.sql b/query-store-find-query-with-run-stats.sql new file mode 100644 index 0000000..8426750 --- /dev/null +++ b/query-store-find-query-with-run-stats.sql @@ -0,0 +1,22 @@ +/***** SCRIPT NEEDS EITHER @proc OR @sql_text TO WORK *****/ +DECLARE @proc VARCHAR(200) = 'SprocName' + ,@sql_text VARCHAR(MAX) = NULL; + +SELECT q.query_id, + q.last_execution_time, + OBJECT_NAME(q.object_id) AS sproc, + qt.query_sql_text, + qsrt.avg_duration, + qsrt.count_executions, + qsrt.avg_cpu_time, + qsrt.avg_logical_io_reads, + qsrtsi.start_time +FROM sys.query_store_query q + INNER JOIN sys.query_store_query_text qt ON qt.query_text_id = q.query_text_id + INNER JOIN sys.query_store_plan qsp ON qsp.query_id = q.query_id + INNER JOIN sys.query_store_runtime_stats qsrt ON qsrt.plan_id = qsp.plan_id + INNER JOIN sys.query_store_runtime_stats_interval qsrtsi ON qsrtsi.runtime_stats_interval_id = qsrt.runtime_stats_interval_id +WHERE (@proc IS NULL OR q.object_id = OBJECT_ID(@proc)) +AND (@sql_text IS NULL OR qt.query_sql_text LIKE '%' + @sql_text + '%') +ORDER BY q.query_id + ,q.last_execution_time DESC; \ No newline at end of file diff --git a/query-store-find-query.sql b/query-store-find-query.sql new file mode 100644 index 0000000..8962fc3 --- /dev/null +++ b/query-store-find-query.sql @@ -0,0 +1,19 @@ +/***** SCRIPT NEEDS EITHER @proc OR @sql_text TO WORK *****/ +DECLARE @proc VARCHAR(200) = 'SprocName' + ,@sql_text VARCHAR(MAX) = NULL--''; + +SELECT q.query_id, + q.query_hash, + q.initial_compile_start_time, + q.last_compile_start_time, + q.last_execution_time, + OBJECT_NAME(q.object_id) AS sproc, + qt.query_sql_text +FROM sys.query_store_query q + INNER JOIN sys.query_store_query_text qt ON qt.query_text_id = q.query_text_id +WHERE (@proc IS NULL OR q.object_id = OBJECT_ID(@proc)) +AND (@sql_text IS NULL OR qt.query_sql_text LIKE '%' + @sql_text + '%') +ORDER BY q.last_execution_time DESC; + +--MarketDataServer.SecurityMaster_SyncSecurityIDs +--366609 diff --git a/query-store-get-forced-plans.sql b/query-store-get-forced-plans.sql new file mode 100644 index 0000000..f4b3deb --- /dev/null +++ b/query-store-get-forced-plans.sql @@ -0,0 +1,77 @@ + +DECLARE @sql_querystore NVARCHAR(2000) + ,@IsHadrEnabled TINYINT = CONVERT(TINYINT,SERVERPROPERTY ('IsHadrEnabled')) + ,@RoleDesc NVARCHAR(60) = 'PRIMARY' + ,@Version VARCHAR(50) = LEFT(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR(128)),2); + +if OBJECT_ID('tempdb..#query_store') is not null drop table #query_store; +CREATE TABLE #query_store ( + databasename NVARCHAR(128) DEFAULT DB_NAME() + ,query_sql_text NVARCHAR(MAX) + ,query_sproc NVARCHAR(128) + ,query_id BIGINT + ,query_plan_hash BINARY(8) + ,query_plan XML + ,is_forced_plan BIT + ,is_natively_compiled BIT + ,force_failure_count BIGINT + ,last_force_failure_reason_desc NVARCHAR(128) + ,plan_forcing_type_desc NVARCHAR(60) +); + +SET @sql_querystore = 'USE [?]; +IF DB_ID() > 4 +INSERT #query_store ( + query_sql_text + ,query_sproc + ,query_id + ,query_plan_hash + ,query_plan + ,is_forced_plan + ,is_natively_compiled + ,force_failure_count + ,last_force_failure_reason_desc + ,plan_forcing_type_desc +) +SELECT qsqt.query_sql_text, + OBJECT_NAME(qsq.object_id) AS ProcedureName, + qsq.query_id, + qsp.query_plan_hash, + CAST(qsp.query_plan AS XML) AS query_plan, + qsp.is_forced_plan, + qsp.is_natively_compiled, + qsp.force_failure_count, + qsp.last_force_failure_reason_desc,' + + CASE WHEN @Version > 13 THEN ' qsp.plan_forcing_type_desc' ELSE ' NULL' END + ' +FROM sys.query_store_query qsq + INNER JOIN sys.query_store_query_text qsqt ON qsqt.query_text_id = qsq.query_text_id + INNER JOIN sys.query_store_plan qsp ON qsp.query_id = qsq.query_id +WHERE qsp.is_forced_plan = 1' + +IF @IsHadrEnabled = 0 +OR ( + @IsHadrEnabled = 1 + AND EXISTS ( + SELECT 1 + FROM sys.dm_hadr_availability_replica_states AS a + JOIN sys.availability_replicas AS b + ON b.replica_id = a.replica_id + WHERE b.replica_server_name = @@SERVERNAME + AND a.role_desc = @RoleDesc + ) +) + EXEC sp_msforeachdb @sql_querystore; + +SELECT @@SERVERNAME AS servername + ,databasename + ,query_sql_text + ,query_sproc + ,query_id + ,CONVERT(VARCHAR(48),query_plan_hash,2) AS query_plan_hash + ,query_plan + ,is_forced_plan + ,is_natively_compiled + ,force_failure_count + ,last_force_failure_reason_desc + ,plan_forcing_type_desc +FROM #query_store; diff --git a/query-store-get-runtime-intervals.sql b/query-store-get-runtime-intervals.sql new file mode 100644 index 0000000..f3451e0 --- /dev/null +++ b/query-store-get-runtime-intervals.sql @@ -0,0 +1,4 @@ +SELECT * +FROM sys.query_store_runtime_stats_interval +ORDER BY runtime_stats_interval_id; +GO \ No newline at end of file diff --git a/security-find-ownerships.sql b/security-find-ownerships.sql new file mode 100644 index 0000000..41c8a30 --- /dev/null +++ b/security-find-ownerships.sql @@ -0,0 +1,22 @@ +-- Drop Login issues for logins tied to SQL Server Availability Groups +-- https://www.mssqltips.com/sqlservertip/5201/drop-login-issues-for-logins-tied-to-sql-server-availability-groups/ + +select * from sys.server_principals where name in ('emaplan\mhursh', 'emaplan\nhughes', 'emaplan\kbarrett', 'emaplan\bblackwell') +select e.*, p.name +from sys.endpoints e +left join master.sys.server_principals p on e.principal_id = p.principal_id +where e.principal_id <> 1 +SELECT pm.class, pm.class_desc, pm.major_id, pm.minor_id, + pm.grantee_principal_id, pm.grantor_principal_id, + pm.[type], pm.[permission_name], pm.[state],pm.state_desc, + pr.[name] AS [owner], gr.[name] AS grantee +FROM sys.server_permissions pm + JOIN sys.server_principals pr ON pm.grantor_principal_id = pr.principal_id + JOIN sys.server_principals gr ON pm.grantee_principal_id = gr.principal_id +WHERE pr.[name] <> 'sa' +SELECT ag.[name] AS AG_name, ag.group_id, r.replica_id, r.owner_sid, p.[name] as owner_name +FROM sys.availability_groups ag + JOIN sys.availability_replicas r ON ag.group_id = r.group_id + JOIN sys.server_principals p ON r.owner_sid = p.[sid] +WHERE p.[name] <> 'sa' +SELECT [name] AS dbname FROM sys.databases WHERE SUSER_SNAME(owner_sid) <> 'sa' diff --git a/server-info/security-find-permission-changes-in-default-trace.sql b/security-find-permission-changes-from-default-trace.sql similarity index 98% rename from server-info/security-find-permission-changes-in-default-trace.sql rename to security-find-permission-changes-from-default-trace.sql index 75fe874..39c6aca 100644 --- a/server-info/security-find-permission-changes-in-default-trace.sql +++ b/security-find-permission-changes-from-default-trace.sql @@ -1,32 +1,32 @@ -DECLARE @tracefile VARCHAR(500); - --- Get path of default trace file -SELECT @tracefile = CAST(value AS VARCHAR(500)) -FROM::fn_trace_getinfo(DEFAULT) -WHERE traceid = 1 -AND property = 2; - --- Get security changes from the default trace -SELECT trcdata.EventClass AS EventId - ,cat.name AS EventCategory - ,evt.name AS EventName - ,trcdata.* -FROM::fn_trace_gettable(@tracefile, DEFAULT) trcdata -- DEFAULT means all trace files will be read - INNER JOIN sys.trace_events evt - ON trcdata.EventClass = evt.trace_event_id - INNER JOIN sys.trace_categories cat - ON evt.category_id = cat.category_id -WHERE trcdata.EventClass IN ( - 102 -- Audit Database Scope GDR: GRANT, DENY, REVOKE issued for a statement - ,103 -- Audit Object GDR Event: GRANT, DENY, REVOKE issued for an object - ,104 -- Audit AddLogin Event: SQL Server login is added or removed - ,105 -- Audit Login GDR Event: Windows login is added or removed - ,106 -- Audit Login Change Property Event: property of a login, except passwords, is modified - ,107 -- Audit Login Change Password Event: SQL Server login password is changed - ,108 -- Audit Add Login to Server Role Event: login is added or removed from a fixed server role - ,109 -- Audit Add DB User Event: login is added or removed as a database user (Windows or SQL Server) to a database - ,110 -- Audit Add Member to DB Role Event: login is added or removed as a database user (fixed or user-defined) to a database - ,111 -- Audit Add Role Event: login is added or removed as a database user to a database - ,112 -- Audit App Role Change Password Event: password of an application role is changed - ) -ORDER BY trcdata.StartTime; +DECLARE @tracefile VARCHAR(500); + +-- Get path of default trace file +SELECT @tracefile = CAST(value AS VARCHAR(500)) +FROM::fn_trace_getinfo(DEFAULT) +WHERE traceid = 1 +AND property = 2; + +-- Get security changes from the default trace +SELECT trcdata.EventClass AS EventId + ,cat.name AS EventCategory + ,evt.name AS EventName + ,trcdata.* +FROM::fn_trace_gettable(@tracefile, DEFAULT) trcdata -- DEFAULT means all trace files will be read + INNER JOIN sys.trace_events evt + ON trcdata.EventClass = evt.trace_event_id + INNER JOIN sys.trace_categories cat + ON evt.category_id = cat.category_id +WHERE trcdata.EventClass IN ( + 102 -- Audit Database Scope GDR: GRANT, DENY, REVOKE issued for a statement + ,103 -- Audit Object GDR Event: GRANT, DENY, REVOKE issued for an object + ,104 -- Audit AddLogin Event: SQL Server login is added or removed + ,105 -- Audit Login GDR Event: Windows login is added or removed + ,106 -- Audit Login Change Property Event: property of a login, except passwords, is modified + ,107 -- Audit Login Change Password Event: SQL Server login password is changed + ,108 -- Audit Add Login to Server Role Event: login is added or removed from a fixed server role + ,109 -- Audit Add DB User Event: login is added or removed as a database user (Windows or SQL Server) to a database + ,110 -- Audit Add Member to DB Role Event: login is added or removed as a database user (fixed or user-defined) to a database + ,111 -- Audit Add Role Event: login is added or removed as a database user to a database + ,112 -- Audit App Role Change Password Event: password of an application role is changed + ) +ORDER BY trcdata.StartTime; diff --git a/database-info/security-ad-group-members.sql b/security-get-ad-group-members.sql similarity index 97% rename from database-info/security-ad-group-members.sql rename to security-get-ad-group-members.sql index 3120470..1d4c710 100644 --- a/database-info/security-ad-group-members.sql +++ b/security-get-ad-group-members.sql @@ -1,196 +1,196 @@ --- ORIGINAL SCRIPT CREDITS -- ------------------------------------------------------------- --- The SQLBlimp AD Access Identification Script --- By John F. Tamburo 2016-01-06 --- Feel free to use this - Freely given to the SQL community ------------------------------------------------------------- --- HISTORY -- --- 02242016 - modified to just breakdown Windows Groups - -set nocount on; -declare @ctr nvarchar(max) = '', @AcctName sysname = '' - --- Create a table to store xp_logininfo commands --- We have to individually execute them in case the login no longer exists - -create table #ExecuteQueue(AcctName sysname,CommandToRun nvarchar(max)); - --- Create a command list for windows-based SQL Logins -insert into #ExecuteQueue(AcctName,CommandToRun) -SELECT [name] - ,CONVERT(NVARCHAR(MAX), 'INSERT INTO #LoginsList EXEC xp_logininfo ''' - + [name] + ''', ''all''; --insert group information' + CHAR(13) - + CHAR(10) - + CASE WHEN [type] = 'G' - THEN ' INSERT INTO #LoginsList EXEC xp_logininfo ''' + [name] - + ''', ''members''; --insert member information' + CHAR(13) - + CHAR(10) - ELSE '-- ' + RTRIM([name]) + ' IS NOT A GROUP BABY!' + CHAR(13) - + CHAR(10) - END) AS CMD_TO_RUN -FROM sys.server_principals -WHERE 1 = 1 - AND type = 'G' -- *Windows* Groups - AND name NOT LIKE '%##%' -- Eliminate Microsoft - AND name NOT LIKE 'NT SERVICE\%' -- xp_logininfo does not work with NT SERVICE accounts -ORDER BY name - ,type_desc; - --- Create the table that the commands above will fill. -create table #LoginsList( - [Account Name] nvarchar(128), - [Type] nvarchar(128), - [Privilege] nvarchar(128), - [Mapped Login Name] nvarchar(128), - [Permission Path] nvarchar(128) ); - --- Jeff Moden: Please forgive me for the RBAR! (:-D) -declare cur cursor for select AcctName, CommandToRun from #ExecuteQueue - -open cur -fetch next from cur into @AcctName,@ctr -while @@FETCH_STATUS = 0 -begin - BEGIN TRY - print @ctr - EXEC sp_executesql @ctr - END TRY - BEGIN CATCH - print ERROR_MESSAGE() + CHAR(13) + CHAR(10); - IF ERROR_MESSAGE() like '%0x534%' -- Windows SQL Login no longer in AD - BEGIN - print '0x534 Logic' - insert into #LoginsList([Account Name],[Type],[Privilege],[Mapped Login Name],[Permission Path]) - select @AcctName AccountName,'DELETED Windows User','user',@AcctName MappedLogin,@AcctName PermissionPath - END - ELSE - print ERROR_MESSAGE(); - END CATCH - fetch next from cur into @AcctName,@ctr - Print '-------------------------------' -END; - --- Clean up cursor -close cur; -deallocate cur; - ----- Add SQL Logins to the result ---insert into #LoginsList([Account Name],[Type],[Privilege],[Mapped Login Name],[Permission Path]) ---SELECT [name] AccountName --- ,'user' --- ,'user' --- ,[name] MappedLogin --- ,[name] PermissionPath ---FROM sys.server_principals ---WHERE 1 = 1 --- AND ( --- type = 'S' -- SQL Server Logins only --- AND name NOT LIKE '%##%' --- ) -- Eliminate Microsoft --- OR ( --- type IN ('U', 'G') --- AND [name] LIKE 'NT SERVICE\%' --- ) -- capture NT Service information ---ORDER BY [name]; - --- Get Server Roles into the mix --- Add column to table -alter table #LoginsList add Server_Roles nvarchar(max); - --- Fill column with server roles -update LL -set - Server_Roles = ISNULL(STUFF((SELECT ', ' + CONVERT(VARCHAR(500),role.name) - FROM sys.server_role_members - JOIN sys.server_principals AS role - ON sys.server_role_members.role_principal_id = role.principal_id - JOIN sys.server_principals AS member - ON sys.server_role_members.member_principal_id = member.principal_id - WHERE member.name= (case when [Permission Path] is not null then [Permission Path] else [Account Name] end) - FOR XML PATH('')),1,1,''),'public') -from #LoginsList LL; - ----- Create a table to hold the users of each database. ---create table #DB_Users( --- DBName sysname --- , UserName sysname --- , LoginType sysname --- , AssociatedRole varchar(max) --- ,create_date datetime --- ,modify_date datetime ---) - ----- Iterate the each database for its users and store them in the table. ---INSERT #DB_Users ---EXEC sp_MSforeachdb ---' ---use [?] ---SELECT ''?'' AS DB_Name, ---ISNULL(case prin.name when ''dbo'' then prin.name + '' (''+ (select SUSER_SNAME(owner_sid) from master.sys.databases where name =''?'') + '')'' else prin.name end,'''') AS UserName, ---prin.type_desc AS LoginType, ---isnull(USER_NAME(mem.role_principal_id),'''') AS AssociatedRole ,create_date,modify_date ---FROM sys.database_principals prin ---LEFT OUTER JOIN sys.database_role_members mem ON prin.principal_id=mem.member_principal_id ---WHERE prin.sid IS NOT NULL ---and prin.sid NOT IN (0x00) ---and prin.is_fixed_role <> 1 ---AND prin.name is not null ---AND prin.name NOT LIKE ''##%''' - ----- Refine the user permissions into a concatenated field by DB and user ---SELECT --- dbname --- ,username --- ,logintype --- ,create_date --- ,modify_date --- ,STUFF((SELECT ', ' + CONVERT(VARCHAR(500),associatedrole) --- FROM #DB_Users user2 --- WHERE user1.DBName=user2.DBName --- AND user1.UserName=user2.UserName --- FOR XML PATH('')),1,1,'') AS Permissions_user ---into #UserPermissions ---FROM #DB_Users user1 ---where logintype != 'DATABASE_ROLE' ---GROUP BY --- dbname --- ,username --- ,logintype --- ,create_date --- ,modify_date ---ORDER BY DBName,username - ----- Report out the results ---Select --- DISTINCT --- LL.[Account Name] --- ,@@SERVERNAME as [Database Server] --- ,UP.dbname as [Database Name] --- ,coalesce(LoginType,LL.type) as LoginType --- --,LL.Privilege --- ,LL.Server_Roles --- ,LL.[Permission Path] --- ,UP.Permissions_user as [User Privileges] ---from #LoginsList LL ---left join #UserPermissions UP --- on LL.[Permission Path] = UP.UserName ----- Comment out the where clause to see all logins that have no database users ----- and their server roles. ----- where exists(select 1 from #LoginsList U2 where U2.[Account Name] = UP.[UserName]) ---order by --- LL.[Account Name] --- ,UP.DBName; -SELECT DISTINCT - @@SERVERNAME AS [Database Server] - ,LL.[Permission Path] - ,LL.[Account Name] - ,LL.Server_Roles -FROM #LoginsList LL -ORDER BY LL.[Permission Path] - ,LL.[Account Name]; - --- Clean up my mess -drop table #ExecuteQueue; -drop table #LoginsList; ---drop table #DB_Users; +-- ORIGINAL SCRIPT CREDITS -- +------------------------------------------------------------ +-- The SQLBlimp AD Access Identification Script +-- By John F. Tamburo 2016-01-06 +-- Feel free to use this - Freely given to the SQL community +------------------------------------------------------------ +-- HISTORY -- +-- 02242016 - modified to just breakdown Windows Groups + +set nocount on; +declare @ctr nvarchar(max) = '', @AcctName sysname = '' + +-- Create a table to store xp_logininfo commands +-- We have to individually execute them in case the login no longer exists + +create table #ExecuteQueue(AcctName sysname,CommandToRun nvarchar(max)); + +-- Create a command list for windows-based SQL Logins +insert into #ExecuteQueue(AcctName,CommandToRun) +SELECT [name] + ,CONVERT(NVARCHAR(MAX), 'INSERT INTO #LoginsList EXEC xp_logininfo ''' + + [name] + ''', ''all''; --insert group information' + CHAR(13) + + CHAR(10) + + CASE WHEN [type] = 'G' + THEN ' INSERT INTO #LoginsList EXEC xp_logininfo ''' + [name] + + ''', ''members''; --insert member information' + CHAR(13) + + CHAR(10) + ELSE '-- ' + RTRIM([name]) + ' IS NOT A GROUP BABY!' + CHAR(13) + + CHAR(10) + END) AS CMD_TO_RUN +FROM sys.server_principals +WHERE 1 = 1 + AND type = 'G' -- *Windows* Groups + AND name NOT LIKE '%##%' -- Eliminate Microsoft + AND name NOT LIKE 'NT SERVICE\%' -- xp_logininfo does not work with NT SERVICE accounts +ORDER BY name + ,type_desc; + +-- Create the table that the commands above will fill. +create table #LoginsList( + [Account Name] nvarchar(128), + [Type] nvarchar(128), + [Privilege] nvarchar(128), + [Mapped Login Name] nvarchar(128), + [Permission Path] nvarchar(128) ); + +-- Jeff Moden: Please forgive me for the RBAR! (:-D) +declare cur cursor for select AcctName, CommandToRun from #ExecuteQueue + +open cur +fetch next from cur into @AcctName,@ctr +while @@FETCH_STATUS = 0 +begin + BEGIN TRY + print @ctr + EXEC sp_executesql @ctr + END TRY + BEGIN CATCH + print ERROR_MESSAGE() + CHAR(13) + CHAR(10); + IF ERROR_MESSAGE() like '%0x534%' -- Windows SQL Login no longer in AD + BEGIN + print '0x534 Logic' + insert into #LoginsList([Account Name],[Type],[Privilege],[Mapped Login Name],[Permission Path]) + select @AcctName AccountName,'DELETED Windows User','user',@AcctName MappedLogin,@AcctName PermissionPath + END + ELSE + print ERROR_MESSAGE(); + END CATCH + fetch next from cur into @AcctName,@ctr + Print '-------------------------------' +END; + +-- Clean up cursor +close cur; +deallocate cur; + +---- Add SQL Logins to the result +--insert into #LoginsList([Account Name],[Type],[Privilege],[Mapped Login Name],[Permission Path]) +--SELECT [name] AccountName +-- ,'user' +-- ,'user' +-- ,[name] MappedLogin +-- ,[name] PermissionPath +--FROM sys.server_principals +--WHERE 1 = 1 +-- AND ( +-- type = 'S' -- SQL Server Logins only +-- AND name NOT LIKE '%##%' +-- ) -- Eliminate Microsoft +-- OR ( +-- type IN ('U', 'G') +-- AND [name] LIKE 'NT SERVICE\%' +-- ) -- capture NT Service information +--ORDER BY [name]; + +-- Get Server Roles into the mix +-- Add column to table +alter table #LoginsList add Server_Roles nvarchar(max); + +-- Fill column with server roles +update LL +set + Server_Roles = ISNULL(STUFF((SELECT ', ' + CONVERT(VARCHAR(500),role.name) + FROM sys.server_role_members + JOIN sys.server_principals AS role + ON sys.server_role_members.role_principal_id = role.principal_id + JOIN sys.server_principals AS member + ON sys.server_role_members.member_principal_id = member.principal_id + WHERE member.name= (case when [Permission Path] is not null then [Permission Path] else [Account Name] end) + FOR XML PATH('')),1,1,''),'public') +from #LoginsList LL; + +---- Create a table to hold the users of each database. +--create table #DB_Users( +-- DBName sysname +-- , UserName sysname +-- , LoginType sysname +-- , AssociatedRole varchar(max) +-- ,create_date datetime +-- ,modify_date datetime +--) + +---- Iterate the each database for its users and store them in the table. +--INSERT #DB_Users +--EXEC sp_MSforeachdb +--' +--use [?] +--SELECT ''?'' AS DB_Name, +--ISNULL(case prin.name when ''dbo'' then prin.name + '' (''+ (select SUSER_SNAME(owner_sid) from master.sys.databases where name =''?'') + '')'' else prin.name end,'''') AS UserName, +--prin.type_desc AS LoginType, +--isnull(USER_NAME(mem.role_principal_id),'''') AS AssociatedRole ,create_date,modify_date +--FROM sys.database_principals prin +--LEFT OUTER JOIN sys.database_role_members mem ON prin.principal_id=mem.member_principal_id +--WHERE prin.sid IS NOT NULL +--and prin.sid NOT IN (0x00) +--and prin.is_fixed_role <> 1 +--AND prin.name is not null +--AND prin.name NOT LIKE ''##%''' + +---- Refine the user permissions into a concatenated field by DB and user +--SELECT +-- dbname +-- ,username +-- ,logintype +-- ,create_date +-- ,modify_date +-- ,STUFF((SELECT ', ' + CONVERT(VARCHAR(500),associatedrole) +-- FROM #DB_Users user2 +-- WHERE user1.DBName=user2.DBName +-- AND user1.UserName=user2.UserName +-- FOR XML PATH('')),1,1,'') AS Permissions_user +--into #UserPermissions +--FROM #DB_Users user1 +--where logintype != 'DATABASE_ROLE' +--GROUP BY +-- dbname +-- ,username +-- ,logintype +-- ,create_date +-- ,modify_date +--ORDER BY DBName,username + +---- Report out the results +--Select +-- DISTINCT +-- LL.[Account Name] +-- ,@@SERVERNAME as [Database Server] +-- ,UP.dbname as [Database Name] +-- ,coalesce(LoginType,LL.type) as LoginType +-- --,LL.Privilege +-- ,LL.Server_Roles +-- ,LL.[Permission Path] +-- ,UP.Permissions_user as [User Privileges] +--from #LoginsList LL +--left join #UserPermissions UP +-- on LL.[Permission Path] = UP.UserName +---- Comment out the where clause to see all logins that have no database users +---- and their server roles. +---- where exists(select 1 from #LoginsList U2 where U2.[Account Name] = UP.[UserName]) +--order by +-- LL.[Account Name] +-- ,UP.DBName; +SELECT DISTINCT + @@SERVERNAME AS [Database Server] + ,LL.[Permission Path] + ,LL.[Account Name] + ,LL.Server_Roles +FROM #LoginsList LL +ORDER BY LL.[Permission Path] + ,LL.[Account Name]; + +-- Clean up my mess +drop table #ExecuteQueue; +drop table #LoginsList; +--drop table #DB_Users; --drop table #UserPermissions; \ No newline at end of file diff --git a/database-info/security-audit.sql b/security-get-db-audit.sql similarity index 95% rename from database-info/security-audit.sql rename to security-get-db-audit.sql index 0cb73c9..c26a118 100644 --- a/database-info/security-audit.sql +++ b/security-get-db-audit.sql @@ -1,144 +1,144 @@ -SET NOCOUNT ON; - -DECLARE @Login NVARCHAR(128) - , @ModDate DATETIME - , @Database NVARCHAR(128) - , @SQL NVARCHAR(MAX); - ---SET @Login = 'applogin'; -SET @ModDate = '3/1/2017'; ---SET @Database = 'rp_prod'; - ------ DATABASE PERMISSIONS ----- -IF EXISTS (SELECT 1 FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[#DB]') AND type in (N'U')) - DROP TABLE [tempdb].[dbo].[#DB]; - -CREATE TABLE #DB ( - [Database] NVARCHAR(128) - , [PermissionState] NVARCHAR(60) - , [Permission] NVARCHAR(128) - , [Object] NVARCHAR(128) - , [Login] NVARCHAR(128) - , LoginType NVARCHAR(60) - , [LastModified] DATETIME -); - -SET @SQL = 'USE [?]; -INSERT INTO #DB ( - [Database] - , [PermissionState] - , [Permission] - , [Object] - , [Login] - , LoginType - , [LastModified] -) -SELECT [Database] = DB_NAME() - , [PermissionState] = p.state_desc - , [Permission] = p.permission_name - , [Object] = CASE WHEN p.class = 0 THEN ''DB: '' + DB_NAME(p.major_id) - WHEN p.class = 3 THEN ''Schema: '' + s.name - ELSE ''Object: '' + OBJECT_NAME(p.major_id) - END - , [Login] = dp.name - , LoginType = dp.type_desc - , [LastModified] = dp.modify_date -FROM sys.database_principals dp - INNER JOIN sys.database_permissions p ON dp.principal_id = p.grantee_principal_id - LEFT OUTER JOIN sys.objects so ON p.major_id = so.object_id AND p.class = 1 - LEFT OUTER JOIN sys.schemas s ON p.major_id = s.schema_id AND p.class = 3 -WHERE dp.name = ISNULL(' + CASE WHEN @Login IS NOT NULL THEN '''' + @Login + '''' ELSE 'NULL' END + ', dp.name) -AND dp.modify_date >= ISNULL(' + CASE WHEN @ModDate IS NOT NULL THEN '''' + CONVERT(VARCHAR,@ModDate) + '''' ELSE 'NULL' END + ',dp.modify_date);'; - -EXECUTE sp_MSforeachdb @SQL; - ------ ROLE MEMBERS ----- -IF EXISTS (SELECT 1 FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[#RM]') AND type in (N'U')) - DROP TABLE [tempdb].[dbo].[#RM]; - -CREATE TABLE #RM ( - [Database] NVARCHAR(128) - , [Role] NVARCHAR(128) - , [Login] NVARCHAR(512) - , [LastModified] DATETIME -); - -SET @SQL = 'USE [?]; -SET QUOTED_IDENTIFIER ON; -INSERT INTO #RM ( - [Database] - , [Role] - , [Login] - , [LastModified] -) -SELECT [Database] = DB_NAME() - , [Role] - , [Login] - , [LastModified] -FROM ( - SELECT [Role] = sp.name - , [Login] = STUFF(( - SELECT '','' + sp2.name - FROM sys.database_role_members rm - INNER JOIN sys.database_principals sp2 ON rm.member_principal_id = sp2.principal_id - WHERE rm.role_principal_id = sp.principal_id - AND sp2.name = ISNULL(' + CASE WHEN @Login IS NOT NULL THEN '''' + @Login + '''' ELSE 'NULL' END + ', sp2.name) - AND sp2.modify_date >= ISNULL(' + CASE WHEN @ModDate IS NOT NULL THEN '''' + CONVERT(VARCHAR,@ModDate) + '''' ELSE 'NULL' END + ', sp2.modify_date) - ORDER BY sp2.name - FOR XML PATH(''''),TYPE).value(''.'',''VARCHAR(MAX)''),1,1,'''') - , [LastModified] = sp.modify_date - FROM sys.database_principals sp - WHERE sp.type IN (''R'',''A'') --DATABASE_ROLE,APPLICATION_ROLE - ) x -WHERE x.[Login] IS NOT NULL;'; - -EXECUTE sp_MSforeachdb @SQL; - -SELECT [ServerLogin] = sp.name - , [LoginType] = sp.type_desc - , [ServerRole] = STUFF(( - SELECT ',' + sp2.name - FROM master.sys.server_role_members rm - INNER JOIN master.sys.server_principals sp2 ON rm.role_principal_id = sp2.principal_id - WHERE sp.principal_id = rm.member_principal_id - FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') - , [DefaultDB] = sp.default_database_name -FROM master.sys.server_principals sp -WHERE sp.is_disabled = 0 -AND sp.name = ISNULL(@Login, sp.name) -AND sp.type_desc IN ('WINDOWS_GROUP','WINDOWS_LOGIN','SQL_LOGIN') -AND sp.name NOT LIKE 'NT AUTHORITY\%' -AND sp.name NOT LIKE 'NT SERVICE\%' -ORDER BY sp.name; - -SELECT DISTINCT - db.[Database] - ,db.Object - ,db.Login - ,db.LoginType - ,STUFF(( - SELECT ',' + csv.Permission - FROM #DB csv - WHERE db.[Database] = csv.[Database] - AND db.Object = csv.Object - AND db.Login = csv.Login - AND csv.Permission != 'CONNECT' - FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') -FROM #DB db -WHERE db.[Database] NOT IN ('master','model','msdb','tempdb','reportserver','reportservertempdb') -AND db.LoginType IN ('SQL_USER','WINDOWS_GROUP','WINDOWS_USER','DATABASE_ROLE') -AND db.Permission != 'CONNECT' -AND db.Login NOT IN ('public','guest') -ORDER BY db.[Database] - ,db.Login - ,db.Object; - -SELECT [Database] - , [Role] - , [Login] -FROM #RM -WHERE [Database] NOT IN ('master','model','msdb','tempdb','reportserver','reportservertempdb') -ORDER BY [Database] - , [Role] - , [Login]; - +SET NOCOUNT ON; + +DECLARE @Login NVARCHAR(128) + , @ModDate DATETIME + , @Database NVARCHAR(128) + , @SQL NVARCHAR(MAX); + +--SET @Login = 'LoginName'; +SET @ModDate = '3/1/2017'; +--SET @Database = 'DBName'; + +----- DATABASE PERMISSIONS ----- +IF EXISTS (SELECT 1 FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[#DB]') AND type in (N'U')) + DROP TABLE [tempdb].[dbo].[#DB]; + +CREATE TABLE #DB ( + [Database] NVARCHAR(128) + , [PermissionState] NVARCHAR(60) + , [Permission] NVARCHAR(128) + , [Object] NVARCHAR(128) + , [Login] NVARCHAR(128) + , LoginType NVARCHAR(60) + , [LastModified] DATETIME +); + +SET @SQL = 'USE [?]; +INSERT INTO #DB ( + [Database] + , [PermissionState] + , [Permission] + , [Object] + , [Login] + , LoginType + , [LastModified] +) +SELECT [Database] = DB_NAME() + , [PermissionState] = p.state_desc + , [Permission] = p.permission_name + , [Object] = CASE WHEN p.class = 0 THEN ''DB: '' + DB_NAME(p.major_id) + WHEN p.class = 3 THEN ''Schema: '' + s.name + ELSE ''Object: '' + OBJECT_NAME(p.major_id) + END + , [Login] = dp.name + , LoginType = dp.type_desc + , [LastModified] = dp.modify_date +FROM sys.database_principals dp + INNER JOIN sys.database_permissions p ON dp.principal_id = p.grantee_principal_id + LEFT OUTER JOIN sys.objects so ON p.major_id = so.object_id AND p.class = 1 + LEFT OUTER JOIN sys.schemas s ON p.major_id = s.schema_id AND p.class = 3 +WHERE dp.name = ISNULL(' + CASE WHEN @Login IS NOT NULL THEN '''' + @Login + '''' ELSE 'NULL' END + ', dp.name) +AND dp.modify_date >= ISNULL(' + CASE WHEN @ModDate IS NOT NULL THEN '''' + CONVERT(VARCHAR,@ModDate) + '''' ELSE 'NULL' END + ',dp.modify_date);'; + +EXECUTE sp_MSforeachdb @SQL; + +----- ROLE MEMBERS ----- +IF EXISTS (SELECT 1 FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[#RM]') AND type in (N'U')) + DROP TABLE [tempdb].[dbo].[#RM]; + +CREATE TABLE #RM ( + [Database] NVARCHAR(128) + , [Role] NVARCHAR(128) + , [Login] NVARCHAR(512) + , [LastModified] DATETIME +); + +SET @SQL = 'USE [?]; +SET QUOTED_IDENTIFIER ON; +INSERT INTO #RM ( + [Database] + , [Role] + , [Login] + , [LastModified] +) +SELECT [Database] = DB_NAME() + , [Role] + , [Login] + , [LastModified] +FROM ( + SELECT [Role] = sp.name + , [Login] = STUFF(( + SELECT '','' + sp2.name + FROM sys.database_role_members rm + INNER JOIN sys.database_principals sp2 ON rm.member_principal_id = sp2.principal_id + WHERE rm.role_principal_id = sp.principal_id + AND sp2.name = ISNULL(' + CASE WHEN @Login IS NOT NULL THEN '''' + @Login + '''' ELSE 'NULL' END + ', sp2.name) + AND sp2.modify_date >= ISNULL(' + CASE WHEN @ModDate IS NOT NULL THEN '''' + CONVERT(VARCHAR,@ModDate) + '''' ELSE 'NULL' END + ', sp2.modify_date) + ORDER BY sp2.name + FOR XML PATH(''''),TYPE).value(''.'',''VARCHAR(MAX)''),1,1,'''') + , [LastModified] = sp.modify_date + FROM sys.database_principals sp + WHERE sp.type IN (''R'',''A'') --DATABASE_ROLE,APPLICATION_ROLE + ) x +WHERE x.[Login] IS NOT NULL;'; + +EXECUTE sp_MSforeachdb @SQL; + +SELECT [ServerLogin] = sp.name + , [LoginType] = sp.type_desc + , [ServerRole] = STUFF(( + SELECT ',' + sp2.name + FROM master.sys.server_role_members rm + INNER JOIN master.sys.server_principals sp2 ON rm.role_principal_id = sp2.principal_id + WHERE sp.principal_id = rm.member_principal_id + FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') + , [DefaultDB] = sp.default_database_name +FROM master.sys.server_principals sp +WHERE sp.is_disabled = 0 +AND sp.name = ISNULL(@Login, sp.name) +AND sp.type_desc IN ('WINDOWS_GROUP','WINDOWS_LOGIN','SQL_LOGIN') +AND sp.name NOT LIKE 'NT AUTHORITY\%' +AND sp.name NOT LIKE 'NT SERVICE\%' +ORDER BY sp.name; + +SELECT DISTINCT + db.[Database] + ,db.Object + ,db.Login + ,db.LoginType + ,STUFF(( + SELECT ',' + csv.Permission + FROM #DB csv + WHERE db.[Database] = csv.[Database] + AND db.Object = csv.Object + AND db.Login = csv.Login + AND csv.Permission != 'CONNECT' + FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') +FROM #DB db +WHERE db.[Database] NOT IN ('master','model','msdb','tempdb','reportserver','reportservertempdb') +AND db.LoginType IN ('SQL_USER','WINDOWS_GROUP','WINDOWS_USER','DATABASE_ROLE') +AND db.Permission != 'CONNECT' +AND db.Login NOT IN ('public','guest') +ORDER BY db.[Database] + ,db.Login + ,db.Object; + +SELECT [Database] + , [Role] + , [Login] +FROM #RM +WHERE [Database] NOT IN ('master','model','msdb','tempdb','reportserver','reportservertempdb') +ORDER BY [Database] + , [Role] + , [Login]; + diff --git a/database-info/security-db-breakdown.sql b/security-get-db-breakdown.sql similarity index 96% rename from database-info/security-db-breakdown.sql rename to security-get-db-breakdown.sql index 0590e50..762f396 100644 --- a/database-info/security-db-breakdown.sql +++ b/security-get-db-breakdown.sql @@ -1,175 +1,175 @@ -SET NOCOUNT ON; - -DECLARE @Login NVARCHAR(128) - , @ModDate DATETIME - , @Database NVARCHAR(128) - , @SQL NVARCHAR(MAX); - ---SET @Login = 'applogin'; ---SET @ModDate = '7/21/2016'; -SET @Database = 'rp_util'; - ------ SERVER LOGINS ----- -IF @Database IS NULL - SELECT [ServerLogin] = sp.name - , [LoginType] = sp.type_desc - , [ServerRole] = STUFF(( - SELECT ',' + sp2.name - FROM master.sys.server_role_members rm - INNER JOIN master.sys.server_principals sp2 ON rm.role_principal_id = sp2.principal_id - WHERE sp.principal_id = rm.member_principal_id - FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') - , [DefaultDB] = sp.default_database_name - , [LastModified] = sp.modify_date - FROM master.sys.server_principals sp - WHERE sp.is_disabled = 0 - AND sp.name = ISNULL(@Login, sp.name) - AND sp.modify_date >= ISNULL(@ModDate,sp.modify_date) - ORDER BY sp.name; - ------ DATABASE PERMISSIONS ----- -IF EXISTS (SELECT 1 FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[#DB]') AND type in (N'U')) - DROP TABLE [tempdb].[dbo].[#DB]; - -CREATE TABLE #DB ( - [Database] NVARCHAR(128) - , [PermissionState] NVARCHAR(60) - , [Permission] NVARCHAR(128) - , [Object] NVARCHAR(128) - , [Login] NVARCHAR(128) - , LoginType NVARCHAR(60) - , [LastModified] DATETIME -); - -SET @SQL = 'USE [?]; -INSERT INTO #DB ( - [Database] - , [PermissionState] - , [Permission] - , [Object] - , [Login] - , LoginType - , [LastModified] -) -SELECT [Database] = DB_NAME() - , [PermissionState] = p.state_desc - , [Permission] = p.permission_name - , [Object] = CASE WHEN p.class = 0 THEN ''DB: '' + DB_NAME(p.major_id) - WHEN p.class = 3 THEN ''Schema: '' + s.name - ELSE ''Object: '' + OBJECT_NAME(p.major_id) - END - , [Login] = dp.name - , LoginType = dp.type_desc - , [LastModified] = dp.modify_date -FROM sys.database_principals dp - INNER JOIN sys.database_permissions p ON dp.principal_id = p.grantee_principal_id - LEFT OUTER JOIN sys.objects so ON p.major_id = so.object_id AND p.class = 1 - LEFT OUTER JOIN sys.schemas s ON p.major_id = s.schema_id AND p.class = 3 -WHERE dp.name = ISNULL(' + CASE WHEN @Login IS NOT NULL THEN '''' + @Login + '''' ELSE 'NULL' END + ', dp.name) -AND dp.modify_date >= ISNULL(' + CASE WHEN @ModDate IS NOT NULL THEN '''' + CONVERT(VARCHAR,@ModDate) + '''' ELSE 'NULL' END + ',dp.modify_date);'; - -EXECUTE sp_MSforeachdb @SQL; - -SELECT [Database] - , [PermissionState] - , [Permission] - , [Object] - , [Login] - , LoginType - , [LastModified] -FROM #DB -WHERE [Database] = ISNULL(@Database, [Database]) -AND [Login] != 'public' -ORDER BY [Database] - , [Login] - , [Object]; - ------ ROLE MEMBERS ----- -IF EXISTS (SELECT 1 FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[#RM]') AND type in (N'U')) - DROP TABLE [tempdb].[dbo].[#RM]; - -CREATE TABLE #RM ( - [Database] NVARCHAR(128) - , [Role] NVARCHAR(128) - , [Login] NVARCHAR(512) - , [LastModified] DATETIME -); - -SET @SQL = 'USE [?]; -SET QUOTED_IDENTIFIER ON; -INSERT INTO #RM ( - [Database] - , [Role] - , [Login] - , [LastModified] -) -SELECT [Database] = DB_NAME() - , [Role] - , [Login] - , [LastModified] -FROM ( - SELECT [Role] = sp.name - , [Login] = STUFF(( - SELECT '','' + sp2.name - FROM sys.database_role_members rm - INNER JOIN sys.database_principals sp2 ON rm.member_principal_id = sp2.principal_id - WHERE rm.role_principal_id = sp.principal_id - AND sp2.name = ISNULL(' + CASE WHEN @Login IS NOT NULL THEN '''' + @Login + '''' ELSE 'NULL' END + ', sp2.name) - AND sp2.modify_date >= ISNULL(' + CASE WHEN @ModDate IS NOT NULL THEN '''' + CONVERT(VARCHAR,@ModDate) + '''' ELSE 'NULL' END + ', sp2.modify_date) - ORDER BY sp2.name - FOR XML PATH(''''),TYPE).value(''.'',''VARCHAR(MAX)''),1,1,'''') - , [LastModified] = sp.modify_date - FROM sys.database_principals sp - WHERE sp.type IN (''R'',''A'') --DATABASE_ROLE,APPLICATION_ROLE - ) x -WHERE x.[Login] IS NOT NULL;'; - -EXECUTE sp_MSforeachdb @SQL; - -SELECT [Database] - , [Role] - , [Login] - , [LastModified] -FROM #RM -WHERE [Database] = ISNULL(@Database, [Database]) -ORDER BY [Database] - , [Role] - , [Login]; - ------ ORPHAN USERS ----- -IF EXISTS (SELECT 1 FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[#OU]') AND type in (N'U')) - DROP TABLE [tempdb].[dbo].[#OU]; - -CREATE TABLE #OU ( - [Database] NVARCHAR(128) - , [Login] NVARCHAR(128) - , [LastModified] DATETIME -); - -SET @SQL = 'USE [?]; -SET QUOTED_IDENTIFIER ON; -INSERT INTO #OU ( - [Database] - , [Login] - , [LastModified] -) -SELECT [Database] = DB_NAME() - , d.name - , d.modify_date -FROM sys.database_principals d - LEFT OUTER JOIN sys.server_principals s - ON d.sid = s.sid -WHERE s.sid IS NULL -AND d.type IN (''U'', ''S'') -- WINDOWS_USER, SQL_USER -AND d.name NOT IN (''guest'', ''INFORMATION_SCHEMA'', ''sys'');' - -EXECUTE sp_MSforeachdb @SQL; - -SELECT [Database] - , [Login] - , [LastModified] -FROM #OU -WHERE [Database] = ISNULL(@Database, [Database]) -ORDER BY [Database] - , [Login]; - +SET NOCOUNT ON; + +DECLARE @Login NVARCHAR(128) + , @ModDate DATETIME + , @Database NVARCHAR(128) + , @SQL NVARCHAR(MAX); + +--SET @Login = 'applogin'; +--SET @ModDate = '7/21/2016'; +SET @Database = 'DBName'; + +----- SERVER LOGINS ----- +IF @Database IS NULL + SELECT [ServerLogin] = sp.name + , [LoginType] = sp.type_desc + , [ServerRole] = STUFF(( + SELECT ',' + sp2.name + FROM master.sys.server_role_members rm + INNER JOIN master.sys.server_principals sp2 ON rm.role_principal_id = sp2.principal_id + WHERE sp.principal_id = rm.member_principal_id + FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') + , [DefaultDB] = sp.default_database_name + , [LastModified] = sp.modify_date + FROM master.sys.server_principals sp + WHERE sp.is_disabled = 0 + AND sp.name = ISNULL(@Login, sp.name) + AND sp.modify_date >= ISNULL(@ModDate,sp.modify_date) + ORDER BY sp.name; + +----- DATABASE PERMISSIONS ----- +IF EXISTS (SELECT 1 FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[#DB]') AND type in (N'U')) + DROP TABLE [tempdb].[dbo].[#DB]; + +CREATE TABLE #DB ( + [Database] NVARCHAR(128) + , [PermissionState] NVARCHAR(60) + , [Permission] NVARCHAR(128) + , [Object] NVARCHAR(128) + , [Login] NVARCHAR(128) + , LoginType NVARCHAR(60) + , [LastModified] DATETIME +); + +SET @SQL = 'USE [?]; +INSERT INTO #DB ( + [Database] + , [PermissionState] + , [Permission] + , [Object] + , [Login] + , LoginType + , [LastModified] +) +SELECT [Database] = DB_NAME() + , [PermissionState] = p.state_desc + , [Permission] = p.permission_name + , [Object] = CASE WHEN p.class = 0 THEN ''DB: '' + DB_NAME(p.major_id) + WHEN p.class = 3 THEN ''Schema: '' + s.name + ELSE ''Object: '' + OBJECT_NAME(p.major_id) + END + , [Login] = dp.name + , LoginType = dp.type_desc + , [LastModified] = dp.modify_date +FROM sys.database_principals dp + INNER JOIN sys.database_permissions p ON dp.principal_id = p.grantee_principal_id + LEFT OUTER JOIN sys.objects so ON p.major_id = so.object_id AND p.class = 1 + LEFT OUTER JOIN sys.schemas s ON p.major_id = s.schema_id AND p.class = 3 +WHERE dp.name = ISNULL(' + CASE WHEN @Login IS NOT NULL THEN '''' + @Login + '''' ELSE 'NULL' END + ', dp.name) +AND dp.modify_date >= ISNULL(' + CASE WHEN @ModDate IS NOT NULL THEN '''' + CONVERT(VARCHAR,@ModDate) + '''' ELSE 'NULL' END + ',dp.modify_date);'; + +EXECUTE sp_MSforeachdb @SQL; + +SELECT [Database] + , [PermissionState] + , [Permission] + , [Object] + , [Login] + , LoginType + , [LastModified] +FROM #DB +WHERE [Database] = ISNULL(@Database, [Database]) +AND [Login] != 'public' +ORDER BY [Database] + , [Login] + , [Object]; + +----- ROLE MEMBERS ----- +IF EXISTS (SELECT 1 FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[#RM]') AND type in (N'U')) + DROP TABLE [tempdb].[dbo].[#RM]; + +CREATE TABLE #RM ( + [Database] NVARCHAR(128) + , [Role] NVARCHAR(128) + , [Login] NVARCHAR(512) + , [LastModified] DATETIME +); + +SET @SQL = 'USE [?]; +SET QUOTED_IDENTIFIER ON; +INSERT INTO #RM ( + [Database] + , [Role] + , [Login] + , [LastModified] +) +SELECT [Database] = DB_NAME() + , [Role] + , [Login] + , [LastModified] +FROM ( + SELECT [Role] = sp.name + , [Login] = STUFF(( + SELECT '','' + sp2.name + FROM sys.database_role_members rm + INNER JOIN sys.database_principals sp2 ON rm.member_principal_id = sp2.principal_id + WHERE rm.role_principal_id = sp.principal_id + AND sp2.name = ISNULL(' + CASE WHEN @Login IS NOT NULL THEN '''' + @Login + '''' ELSE 'NULL' END + ', sp2.name) + AND sp2.modify_date >= ISNULL(' + CASE WHEN @ModDate IS NOT NULL THEN '''' + CONVERT(VARCHAR,@ModDate) + '''' ELSE 'NULL' END + ', sp2.modify_date) + ORDER BY sp2.name + FOR XML PATH(''''),TYPE).value(''.'',''VARCHAR(MAX)''),1,1,'''') + , [LastModified] = sp.modify_date + FROM sys.database_principals sp + WHERE sp.type IN (''R'',''A'') --DATABASE_ROLE,APPLICATION_ROLE + ) x +WHERE x.[Login] IS NOT NULL;'; + +EXECUTE sp_MSforeachdb @SQL; + +SELECT [Database] + , [Role] + , [Login] + , [LastModified] +FROM #RM +WHERE [Database] = ISNULL(@Database, [Database]) +ORDER BY [Database] + , [Role] + , [Login]; + +----- ORPHAN USERS ----- +IF EXISTS (SELECT 1 FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[#OU]') AND type in (N'U')) + DROP TABLE [tempdb].[dbo].[#OU]; + +CREATE TABLE #OU ( + [Database] NVARCHAR(128) + , [Login] NVARCHAR(128) + , [LastModified] DATETIME +); + +SET @SQL = 'USE [?]; +SET QUOTED_IDENTIFIER ON; +INSERT INTO #OU ( + [Database] + , [Login] + , [LastModified] +) +SELECT [Database] = DB_NAME() + , d.name + , d.modify_date +FROM sys.database_principals d + LEFT OUTER JOIN sys.server_principals s + ON d.sid = s.sid +WHERE s.sid IS NULL +AND d.type IN (''U'', ''S'') -- WINDOWS_USER, SQL_USER +AND d.name NOT IN (''guest'', ''INFORMATION_SCHEMA'', ''sys'');' + +EXECUTE sp_MSforeachdb @SQL; + +SELECT [Database] + , [Login] + , [LastModified] +FROM #OU +WHERE [Database] = ISNULL(@Database, [Database]) +ORDER BY [Database] + , [Login]; + diff --git a/security-get-db-role-membership.sql b/security-get-db-role-membership.sql new file mode 100644 index 0000000..c41fd3f --- /dev/null +++ b/security-get-db-role-membership.sql @@ -0,0 +1,44 @@ + +DECLARE @db_role_sql NVARCHAR(4000); + +CREATE TABLE #database_role_members ( + [DatabaseName] VARCHAR(128) NOT NULL, + [PrincipalName] VARCHAR(128) NOT NULL, + [IsPrincipalDisabled] BIT NULL, + [IsPrincipalOrphaned] BIT NOT NULL, + [RoleName] VARCHAR(128) NOT NULL, + [IsFixedRole] BIT NOT NULL, + [RoleOwner] VARCHAR(128) NULL, +); + +SET @db_role_sql = N'USE [?]; +INSERT #database_role_members (DatabaseName, PrincipalName, IsPrincipalDisabled, IsPrincipalOrphaned, RoleName, IsFixedRole, RoleOwner) +SELECT DB_NAME() + ,p.name + ,CASE WHEN p.authentication_type <> 0 THEN sp.is_disabled ELSE 0 END + ,CASE WHEN p.type_desc <> ''DATABASE_ROLE'' AND p.authentication_type <> 0 AND sp.sid IS NULL THEN 1 ELSE 0 END + ,r.name + ,r.is_fixed_role + ,r.owning_principal +FROM sys.database_role_members drm + INNER JOIN ( + SELECT rp.principal_id + ,rp.name + ,rp.is_fixed_role + ,suser_sname(op.sid) as owning_principal + FROM sys.database_principals rp + JOIN sys.database_principals op ON rp.owning_principal_id = op.principal_id + WHERE rp.type_desc = ''DATABASE_ROLE'' + ) r ON r.principal_id = drm.role_principal_id + RIGHT JOIN sys.database_principals p ON p.principal_id = drm.member_principal_id + LEFT JOIN sys.server_principals sp ON p.sid = sp.sid +WHERE r.name IS NOT NULL;'; + +EXEC sp_MSforeachdb @db_role_sql; + +SELECT @@SERVERNAME AS ServerName + ,DEFAULT_DOMAIN() AS Domain + ,* +FROM #database_role_members; + +DROP TABLE #database_role_members; diff --git a/database-info/security-role-breakdown.sql b/security-get-server-role-dashboard.sql similarity index 97% rename from database-info/security-role-breakdown.sql rename to security-get-server-role-dashboard.sql index 23f5fb8..359a725 100644 --- a/database-info/security-role-breakdown.sql +++ b/security-get-server-role-dashboard.sql @@ -1,105 +1,105 @@ -/********************************************************************************************** - - SERVER ROLE MEMBERSHIP - -**********************************************************************************************/ - -WITH CTE_Role (name,role,type_desc,default_database_name) -as -( -SELECT PRN.name - ,srvrole.name AS [role] - ,PRN.type_desc - ,PRN.default_database_name -FROM sys.server_role_members membership - INNER JOIN ( - SELECT principal_id, name - FROM sys.server_principals - WHERE type_desc = 'SERVER_ROLE' - ) srvrole ON srvrole.principal_id = membership.role_principal_id - RIGHT JOIN sys.server_principals PRN ON PRN.principal_id = membership.member_principal_id -WHERE PRN.type_desc NOT IN ('SERVER_ROLE') - AND PRN.is_disabled = 0 -UNION ALL -SELECT p.name - ,'ControlServer' - ,p.type_desc AS loginType - ,p.default_database_name -FROM sys.server_principals p - JOIN sys.server_permissions Sp ON p.principal_id = Sp.grantee_principal_id -WHERE Sp.class = 100 - AND Sp.type = 'CL' - AND Sp.state = 'G' -) -SELECT name, -Type_Desc , -default_database_name , -CASE WHEN [public]=1 THEN 'Y' ELSE '' END as 'Public', -CASE WHEN [sysadmin] =1 THEN 'Y' ELSE '' END as 'SysAdmin' , -CASE WHEN [securityadmin] =1 THEN 'Y' ELSE '' END as 'SecurityAdmin', -CASE WHEN [serveradmin] =1 THEN 'Y' ELSE '' END as 'ServerAdmin', -CASE WHEN [setupadmin] =1 THEN 'Y' ELSE '' END as 'SetupAdmin', -CASE WHEN [processadmin] =1 THEN 'Y' ELSE '' END as 'ProcessAdmin', -CASE WHEN [diskadmin] =1 THEN 'Y' ELSE '' END as 'DiskAdmin', -CASE WHEN [dbcreator] =1 THEN 'Y' ELSE '' END as 'DBCreator', -CASE WHEN [bulkadmin] =1 THEN 'Y' ELSE '' END as 'BulkAdmin' , -CASE WHEN [ControlServer] =1 THEN 'Y' ELSE '' END as 'ControlServer' -FROM CTE_Role -PIVOT -( - COUNT(role) For role in ([public],[sysadmin],[securityadmin],[serveradmin],[setupadmin],[processadmin],[diskadmin],[dbcreator],[bulkadmin],[ControlServer]) -) as pvt -WHERE Type_Desc not in ('SERVER_ROLE','CERTIFICATE_MAPPED_LOGIN') -ORDER BY name,type_desc,default_database_name; -go - ---/********************************************************************************************** - --- DATABASE ROLE MEMBERSHIP - ---**********************************************************************************************/ - ---CREATE TABLE #DatabaseRoleMemberShip --- ( --- Username varchar(100), --- UserType varchar(100), --- Rolename varchar(100), --- Databasename varchar(100) - --- ); - ---DECLARE @Cmd as varchar(max) --- ,@PivotColumnHeaders VARCHAR(4000); - ---SET @Cmd = 'USE [?] ;insert into #DatabaseRoleMemberShip ---select u.name,u.type_desc,r.name,''?'' ---FROM sys.database_role_members RM --- INNER JOIN sys.database_principals U ON U.principal_id = RM.member_principal_id --- INNER JOIN sys.database_principals R ON R.principal_id = RM.role_principal_id --- INNER JOIN sys.server_principals S ON S.principal_id = RM.role_principal_id ---where u.Type != ''R'''; - ---EXEC sp_MSforeachdb @command1=@cmd; - --- SELECT @PivotColumnHeaders = --- COALESCE(@PivotColumnHeaders + ',[' + cast(rolename as varchar(max)) + ']','[' + cast(rolename as varchar(max))+ ']' --- ) --- FROM (SELECT DISTINCT rolename from #DatabaseRoleMemberShip )a ORDER BY rolename ASC; - ---SET @Cmd = ---'select ---databasename,username,UserType ,'+@PivotColumnHeaders+' ---from ---( --- select * from #DatabaseRoleMemberShip) as p ---pivot ---( --- count(rolename ) ---for rolename in ('+@PivotColumnHeaders+') )as pvt ---order by databasename,username'; - ---EXECUTE(@Cmd ); - ---DROP TABLE #DatabaseRoleMemberShip; ---GO - +/********************************************************************************************** + + SERVER ROLE MEMBERSHIP + +**********************************************************************************************/ + +WITH CTE_Role (name,role,type_desc,default_database_name) +as +( +SELECT PRN.name + ,srvrole.name AS [role] + ,PRN.type_desc + ,PRN.default_database_name +FROM sys.server_role_members membership + INNER JOIN ( + SELECT principal_id, name + FROM sys.server_principals + WHERE type_desc = 'SERVER_ROLE' + ) srvrole ON srvrole.principal_id = membership.role_principal_id + RIGHT JOIN sys.server_principals PRN ON PRN.principal_id = membership.member_principal_id +WHERE PRN.type_desc NOT IN ('SERVER_ROLE') + AND PRN.is_disabled = 0 +UNION ALL +SELECT p.name + ,'ControlServer' + ,p.type_desc AS loginType + ,p.default_database_name +FROM sys.server_principals p + JOIN sys.server_permissions Sp ON p.principal_id = Sp.grantee_principal_id +WHERE Sp.class = 100 + AND Sp.type = 'CL' + AND Sp.state = 'G' +) +SELECT name, +Type_Desc , +default_database_name , +CASE WHEN [public]=1 THEN 'Y' ELSE '' END as 'Public', +CASE WHEN [sysadmin] =1 THEN 'Y' ELSE '' END as 'SysAdmin' , +CASE WHEN [securityadmin] =1 THEN 'Y' ELSE '' END as 'SecurityAdmin', +CASE WHEN [serveradmin] =1 THEN 'Y' ELSE '' END as 'ServerAdmin', +CASE WHEN [setupadmin] =1 THEN 'Y' ELSE '' END as 'SetupAdmin', +CASE WHEN [processadmin] =1 THEN 'Y' ELSE '' END as 'ProcessAdmin', +CASE WHEN [diskadmin] =1 THEN 'Y' ELSE '' END as 'DiskAdmin', +CASE WHEN [dbcreator] =1 THEN 'Y' ELSE '' END as 'DBCreator', +CASE WHEN [bulkadmin] =1 THEN 'Y' ELSE '' END as 'BulkAdmin' , +CASE WHEN [ControlServer] =1 THEN 'Y' ELSE '' END as 'ControlServer' +FROM CTE_Role +PIVOT +( + COUNT(role) For role in ([public],[sysadmin],[securityadmin],[serveradmin],[setupadmin],[processadmin],[diskadmin],[dbcreator],[bulkadmin],[ControlServer]) +) as pvt +WHERE Type_Desc not in ('SERVER_ROLE','CERTIFICATE_MAPPED_LOGIN') +ORDER BY name,type_desc,default_database_name; +go + +--/********************************************************************************************** + +-- DATABASE ROLE MEMBERSHIP + +--**********************************************************************************************/ + +--CREATE TABLE #DatabaseRoleMemberShip +-- ( +-- Username varchar(100), +-- UserType varchar(100), +-- Rolename varchar(100), +-- Databasename varchar(100) + +-- ); + +--DECLARE @Cmd as varchar(max) +-- ,@PivotColumnHeaders VARCHAR(4000); + +--SET @Cmd = 'USE [?] ;insert into #DatabaseRoleMemberShip +--select u.name,u.type_desc,r.name,''?'' +--FROM sys.database_role_members RM +-- INNER JOIN sys.database_principals U ON U.principal_id = RM.member_principal_id +-- INNER JOIN sys.database_principals R ON R.principal_id = RM.role_principal_id +-- INNER JOIN sys.server_principals S ON S.principal_id = RM.role_principal_id +--where u.Type != ''R'''; + +--EXEC sp_MSforeachdb @command1=@cmd; + +-- SELECT @PivotColumnHeaders = +-- COALESCE(@PivotColumnHeaders + ',[' + cast(rolename as varchar(max)) + ']','[' + cast(rolename as varchar(max))+ ']' +-- ) +-- FROM (SELECT DISTINCT rolename from #DatabaseRoleMemberShip )a ORDER BY rolename ASC; + +--SET @Cmd = +--'select +--databasename,username,UserType ,'+@PivotColumnHeaders+' +--from +--( +-- select * from #DatabaseRoleMemberShip) as p +--pivot +--( +-- count(rolename ) +--for rolename in ('+@PivotColumnHeaders+') )as pvt +--order by databasename,username'; + +--EXECUTE(@Cmd ); + +--DROP TABLE #DatabaseRoleMemberShip; +--GO + diff --git a/security-get-server-role-membership.sql b/security-get-server-role-membership.sql new file mode 100644 index 0000000..4fbec77 --- /dev/null +++ b/security-get-server-role-membership.sql @@ -0,0 +1,20 @@ + +SELECT @@SERVERNAME AS ServerName + ,DEFAULT_DOMAIN() AS Domain + ,p.name AS PrincipalName + ,p.is_disabled AS IsPrincipalDisabled + ,r.name AS RoleName + ,r.is_fixed_role AS IsFixedRole + ,r.is_disabled AS IsRoleDisabled +FROM sys.server_role_members srm + INNER JOIN ( + SELECT principal_id + ,name + ,is_disabled + ,is_fixed_role + FROM sys.server_principals + WHERE type_desc = 'SERVER_ROLE' + ) r ON r.principal_id = srm.role_principal_id + RIGHT JOIN sys.server_principals p ON p.principal_id = srm.member_principal_id +WHERE p.type_desc NOT IN ('SERVER_ROLE') +AND r.name IS NOT NULL; diff --git a/server-config/security-migrate-users.sql b/security-migrate-users.sql similarity index 85% rename from server-config/security-migrate-users.sql rename to security-migrate-users.sql index 5af30c8..14051ac 100644 --- a/server-config/security-migrate-users.sql +++ b/security-migrate-users.sql @@ -1,29 +1,32 @@ - --- Windows logins and groups -SELECT N'CREATE LOGIN [' + sp.name + '] FROM WINDOWS;' -FROM master.sys.server_principals AS sp -WHERE sp.type IN ('U', 'G') -AND sp.is_disabled = 0 -AND sp.name NOT LIKE 'NT [AS]%\%'; - --- SQL Server logins -SELECT N'CREATE LOGIN [' + sp.name + '] WITH PASSWORD=0x' + CONVERT(NVARCHAR(MAX), l.password_hash, 2) - + N' HASHED, CHECK_POLICY=OFF, CHECK_EXPIRATION=OFF, DEFAULT_DATABASE=[' + l.default_database_name - + N'], SID=0x' + CONVERT(NVARCHAR(MAX), sp.sid, 2) + N';' -FROM master.sys.server_principals AS sp - INNER JOIN master.sys.sql_logins AS l - ON sp.sid = l.sid -WHERE sp.type = 'S' -AND sp.is_disabled = 0; - --- Server roles -SELECT N'CREATE SERVER ROLE [' + sp.name + N'];' -FROM sys.server_principals AS sp -WHERE sp.principal_id >= 100 -AND sp.type = 'R'; - --- Permissions -SELECT p.state_desc + N' ' + p.permission_name + N' TO [' + sp.name COLLATE DATABASE_DEFAULT + N'];' -FROM sys.server_permissions AS p - INNER JOIN sys.server_principals AS sp - ON p.grantee_principal_id = sp.principal_id; \ No newline at end of file + +-- Windows logins and groups +SELECT N'CREATE LOGIN [' + sp.name + '] FROM WINDOWS;' +FROM master.sys.server_principals AS sp +WHERE sp.type IN ('U', 'G') +AND sp.is_disabled = 0 +AND sp.name NOT LIKE 'NT [AS]%\%' +ORDER BY sp.name; + +-- SQL Server logins +SELECT N'CREATE LOGIN [' + sp.name + '] WITH PASSWORD=0x' + CONVERT(NVARCHAR(MAX), l.password_hash, 2) + + N' HASHED, CHECK_POLICY=OFF, CHECK_EXPIRATION=OFF, DEFAULT_DATABASE=[' + l.default_database_name + + N'], SID=0x' + CONVERT(NVARCHAR(MAX), sp.sid, 2) + N';' +FROM master.sys.server_principals AS sp + INNER JOIN master.sys.sql_logins AS l + ON sp.sid = l.sid +WHERE sp.type = 'S' +AND sp.is_disabled = 0 +ORDER BY sp.name; + +-- Server roles +SELECT N'CREATE SERVER ROLE [' + sp.name + N'];' +FROM sys.server_principals AS sp +WHERE sp.principal_id >= 100 +AND sp.type = 'R'; + +-- Permissions +SELECT p.state_desc + N' ' + p.permission_name + N' TO [' + sp.name COLLATE DATABASE_DEFAULT + N'];' +FROM sys.server_permissions AS p + INNER JOIN sys.server_principals AS sp + ON p.grantee_principal_id = sp.principal_id +ORDER BY sp.name; \ No newline at end of file diff --git a/server-config/security-generate-sql-login-permissions.sql b/security-script-db-permissions.sql similarity index 97% rename from server-config/security-generate-sql-login-permissions.sql rename to security-script-db-permissions.sql index 52112ce..a21a29f 100644 --- a/server-config/security-generate-sql-login-permissions.sql +++ b/security-script-db-permissions.sql @@ -1,91 +1,91 @@ -SET NOCOUNT ON; - -DECLARE @Login NVARCHAR(128) - ,@SQL VARCHAR(MAX); - -SET @Login = N'applogin'; - --- GRANT SERVER LEVEL PERMISSIONS -- -SELECT pri.name AS Login - ,per.state_desc COLLATE DATABASE_DEFAULT + ' ' + per.permission_name COLLATE DATABASE_DEFAULT + ' TO [' - + pri.name COLLATE DATABASE_DEFAULT + '];' AS GrantServerPermissionSQL -FROM sys.server_permissions per - INNER JOIN sys.server_principals pri - ON per.grantee_principal_id = pri.principal_id -WHERE per.class_desc = 'SERVER' -AND pri.type IN ('S', 'U', 'G') -- SQL_LOGIN, WINDOWS_LOGIN, WINDOWS_GROUP -AND pri.is_disabled = 0 -AND pri.name = ISNULL(@Login, pri.name) -ORDER BY pri.name; - --- GRANT SERVER LEVEL ROLES -- -SELECT pri.name AS Login - ,'EXEC sp_addrolemember @rolename = ''' + rpri.name + ''', @membername = ''' + pri.name + ''';' AS GrantServerRoleSQL -FROM sys.server_principals pri - INNER JOIN sys.server_role_members rm - ON pri.principal_id = rm.member_principal_id - INNER JOIN sys.server_principals rpri - ON rpri.principal_id = rm.role_principal_id -WHERE pri.type IN ('S', 'U', 'G') -- SQL_LOGIN, WINDOWS_LOGIN, WINDOWS_GROUP -AND pri.is_disabled = 0 -AND pri.name = ISNULL(@Login, pri.name); - --- GRANT DATABASE LEVEL PERMISSIONS -- -CREATE TABLE #Logins (sid VARBINARY(85)); - -INSERT INTO #Logins (sid) -SELECT sid -FROM sys.server_principals -WHERE type IN ('S', 'U', 'G') -- SQL_LOGIN, WINDOWS_LOGIN, WINDOWS_GROUP -AND is_disabled = 0 -AND name = ISNULL(@Login, name) -AND principal_id <> 1; -- sa - -CREATE TABLE #DBSecurity (RowId INT IDENTITY(1, 1), DBName NVARCHAR(128), SQLStmt VARCHAR(MAX)); - -SET @SQL = - 'USE [?]; -INSERT INTO #DBSecurity (DBName, SQLStmt) -SELECT DB_NAME() - , ''USE [?];'' -UNION ALL -SELECT DB_NAME() - , ''IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '''''' + dp.name + '''''') AND EXISTS (SELECT 1 FROM sys.server_principals WHERE name = '''''' + sp.name + '''''') CREATE USER ['' + dp.name + ''] FOR LOGIN ['' + sp.name + ''];'' -FROM sys.database_principals dp - INNER JOIN sys.server_principals sp ON dp.sid = sp.sid - INNER JOIN #Logins tmp ON tmp.sid = dp.sid -UNION ALL -SELECT DB_NAME() - , ''EXEC sp_addrolemember @rolename = '''''' + dr.name + '''''', @membername = '''''' + dp.name + '''''';'' -FROM sys.database_principals dp - INNER JOIN sys.database_role_members rm ON rm.member_principal_id = dp.principal_id - INNER JOIN sys.database_principals dr ON rm.role_principal_id = dr.principal_id - INNER JOIN #Logins tmp ON tmp.sid = dp.sid -UNION ALL -SELECT DB_NAME() - , ''IF EXISTS (SELECT 1 FROM sys.objects WHERE name = '''''' + o.name + '''''') AND EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '''''' + dp.name + '''''') '' + p.state_desc + '' '' + p.permission_name + '' ON ['' + s.name + ''].['' + o.name collate database_default + ''] TO ['' + dp.name + ''];'' -FROM sys.database_principals dp - INNER JOIN sys.database_permissions p on p.grantee_principal_id = dp.principal_id - INNER JOIN sys.objects o on p.major_id = o.object_id - INNER JOIN sys.schemas s on o.schema_id = s.schema_id - INNER JOIN #Logins tmp ON tmp.sid = dp.sid; -'; - -EXEC sys.sp_MSforeachdb @SQL; - -SELECT DBName - ,SQLStmt -FROM #DBSecurity -ORDER BY RowId; - -DROP TABLE #Logins; -DROP TABLE #DBSecurity; - --- SET DEFAULT DB -- -SELECT pri.name AS Login - ,'ALTER LOGIN [' + pri.name + '] WITH DEFAULT_DATABASE = [' + pri.default_database_name + '];' AS SetDefaultDBSQL -FROM sys.server_principals pri -WHERE pri.type IN ('S', 'U', 'G') -- SQL_LOGIN, WINDOWS_LOGIN, WINDOWS_GROUP -AND pri.is_disabled = 0 -AND pri.name = ISNULL(@Login, pri.name) -ORDER BY pri.name; +SET NOCOUNT ON; + +DECLARE @Login NVARCHAR(128) + ,@SQL VARCHAR(MAX); + +SET @Login = N'LoginName'; + +-- GRANT SERVER LEVEL PERMISSIONS -- +SELECT pri.name AS Login + ,per.state_desc COLLATE DATABASE_DEFAULT + ' ' + per.permission_name COLLATE DATABASE_DEFAULT + ' TO [' + + pri.name COLLATE DATABASE_DEFAULT + '];' AS GrantServerPermissionSQL +FROM sys.server_permissions per + INNER JOIN sys.server_principals pri + ON per.grantee_principal_id = pri.principal_id +WHERE per.class_desc = 'SERVER' +AND pri.type IN ('S', 'U', 'G') -- SQL_LOGIN, WINDOWS_LOGIN, WINDOWS_GROUP +AND pri.is_disabled = 0 +AND pri.name = ISNULL(@Login, pri.name) +ORDER BY pri.name; + +-- GRANT SERVER LEVEL ROLES -- +SELECT pri.name AS Login + ,'EXEC sp_addrolemember @rolename = ''' + rpri.name + ''', @membername = ''' + pri.name + ''';' AS GrantServerRoleSQL +FROM sys.server_principals pri + INNER JOIN sys.server_role_members rm + ON pri.principal_id = rm.member_principal_id + INNER JOIN sys.server_principals rpri + ON rpri.principal_id = rm.role_principal_id +WHERE pri.type IN ('S', 'U', 'G') -- SQL_LOGIN, WINDOWS_LOGIN, WINDOWS_GROUP +AND pri.is_disabled = 0 +AND pri.name = ISNULL(@Login, pri.name); + +-- GRANT DATABASE LEVEL PERMISSIONS -- +CREATE TABLE #Logins (sid VARBINARY(85)); + +INSERT INTO #Logins (sid) +SELECT sid +FROM sys.server_principals +WHERE type IN ('S', 'U', 'G') -- SQL_LOGIN, WINDOWS_LOGIN, WINDOWS_GROUP +AND is_disabled = 0 +AND name = ISNULL(@Login, name) +AND principal_id <> 1; -- sa + +CREATE TABLE #DBSecurity (RowId INT IDENTITY(1, 1), DBName NVARCHAR(128), SQLStmt VARCHAR(MAX)); + +SET @SQL = + 'USE [?]; +INSERT INTO #DBSecurity (DBName, SQLStmt) +SELECT DB_NAME() + , ''USE [?];'' +UNION ALL +SELECT DB_NAME() + , ''IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '''''' + dp.name + '''''') AND EXISTS (SELECT 1 FROM sys.server_principals WHERE name = '''''' + sp.name + '''''') CREATE USER ['' + dp.name + ''] FOR LOGIN ['' + sp.name + ''];'' +FROM sys.database_principals dp + INNER JOIN sys.server_principals sp ON dp.sid = sp.sid + INNER JOIN #Logins tmp ON tmp.sid = dp.sid +UNION ALL +SELECT DB_NAME() + , ''EXEC sp_addrolemember @rolename = '''''' + dr.name + '''''', @membername = '''''' + dp.name + '''''';'' +FROM sys.database_principals dp + INNER JOIN sys.database_role_members rm ON rm.member_principal_id = dp.principal_id + INNER JOIN sys.database_principals dr ON rm.role_principal_id = dr.principal_id + INNER JOIN #Logins tmp ON tmp.sid = dp.sid +UNION ALL +SELECT DB_NAME() + , ''IF EXISTS (SELECT 1 FROM sys.objects WHERE name = '''''' + o.name + '''''') AND EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '''''' + dp.name + '''''') '' + p.state_desc + '' '' + p.permission_name + '' ON ['' + s.name + ''].['' + o.name collate database_default + ''] TO ['' + dp.name + ''];'' +FROM sys.database_principals dp + INNER JOIN sys.database_permissions p on p.grantee_principal_id = dp.principal_id + INNER JOIN sys.objects o on p.major_id = o.object_id + INNER JOIN sys.schemas s on o.schema_id = s.schema_id + INNER JOIN #Logins tmp ON tmp.sid = dp.sid; +'; + +EXEC sys.sp_MSforeachdb @SQL; + +SELECT DBName + ,SQLStmt +FROM #DBSecurity +ORDER BY RowId; + +DROP TABLE #Logins; +DROP TABLE #DBSecurity; + +-- SET DEFAULT DB -- +SELECT pri.name AS Login + ,'ALTER LOGIN [' + pri.name + '] WITH DEFAULT_DATABASE = [' + pri.default_database_name + '];' AS SetDefaultDBSQL +FROM sys.server_principals pri +WHERE pri.type IN ('S', 'U', 'G') -- SQL_LOGIN, WINDOWS_LOGIN, WINDOWS_GROUP +AND pri.is_disabled = 0 +AND pri.name = ISNULL(@Login, pri.name) +ORDER BY pri.name; diff --git a/server-config/alert-CHECKDB-error.sql b/server-config/alert-CHECKDB-error.sql deleted file mode 100644 index 97f1266..0000000 --- a/server-config/alert-CHECKDB-error.sql +++ /dev/null @@ -1,88 +0,0 @@ -USE rp_util; -GO - --- START: DDL -- -IF OBJECT_ID('T_UTIL_CheckDbLog', 'U') IS NULL - CREATE TABLE dbo.T_UTIL_CheckDbLog ( - CheckDbLogId INT IDENTITY(1, 1) NOT NULL - ,LogDate DATETIME NOT NULL - ,LogText NVARCHAR(MAX) NOT NULL - ,AlertSent BIT NOT NULL CONSTRAINT df_T_UTIL_CheckDbLog_AlertSent DEFAULT 0 - ,Mitigated BIT NOT NULL CONSTRAINT df_T_UTIL_CheckDbLog_Mitigated DEFAULT 0 - ,MitigatedBy NVARCHAR(128) NULL - ,Mitigation NVARCHAR(MAX) NULL - ,CONSTRAINT PK_T_UTIL_CheckDbLog PRIMARY KEY CLUSTERED (CheckDbLogId) WITH FILLFACTOR = 100 ON [PRIMARY] - ); -GO - -IF OBJECT_ID('upd_T_UTIL_CheckDbLog', 'TR') IS NOT NULL - DROP TRIGGER dbo.upd_T_UTIL_CheckDbLog; -GO - -CREATE TRIGGER dbo.upd_T_UTIL_CheckDbLog -ON dbo.T_UTIL_CheckDbLog -INSTEAD OF UPDATE -AS -BEGIN - UPDATE l - SET l.Mitigated = ins.Mitigated - ,l.MitigatedBy = COALESCE(ins.MitigatedBy, SYSTEM_USER) - ,l.Mitigation = ins.Mitigation - FROM dbo.T_UTIL_CheckDbLog l - INNER JOIN INSERTED ins - ON l.CheckDbLogId = ins.CheckDbLogId; -END; -GO --- END: DDL -- - --- START: ALERT -- -USE msdb; -GO - -SET NOCOUNT ON; - -CREATE TABLE #CHECKDBLog (LogDate DATETIME, ProcessInfo NVARCHAR(128), Text NVARCHAR(MAX)); - - -DECLARE @recipients NVARCHAR(100) - ,@query NVARCHAR(MAX); - --- read last 6 log files (catchall in case server has been restarted) -INSERT INTO #CHECKDBLog (LogDate, ProcessInfo, Text) -EXEC sys.xp_readerrorlog 0, 1, 'DBCC CHECKDB'; -INSERT INTO #CHECKDBLog (LogDate, ProcessInfo, Text) -EXEC sys.xp_readerrorlog 1, 1, 'DBCC CHECKDB'; -INSERT INTO #CHECKDBLog (LogDate, ProcessInfo, Text) -EXEC sys.xp_readerrorlog 2, 1, 'DBCC CHECKDB'; -INSERT INTO #CHECKDBLog (LogDate, ProcessInfo, Text) -EXEC sys.xp_readerrorlog 3, 1, 'DBCC CHECKDB'; -INSERT INTO #CHECKDBLog (LogDate, ProcessInfo, Text) -EXEC sys.xp_readerrorlog 4, 1, 'DBCC CHECKDB'; -INSERT INTO #CHECKDBLog (LogDate, ProcessInfo, Text) -EXEC sys.xp_readerrorlog 5, 1, 'DBCC CHECKDB'; - -INSERT INTO rp_util.dbo.T_UTIL_CheckDbLog (LogDate, LogText) -SELECT LogDate - ,Text -FROM #CHECKDBLog -WHERE DATEDIFF(HOUR, LogDate, GETDATE()) <= 24 -AND Text NOT LIKE '%found 0 errors and repaired 0 errors%'; - -IF EXISTS (SELECT 1 FROM rp_util.dbo.T_UTIL_CheckDbLog WHERE AlertSent = 0) -BEGIN - SELECT @recipients = email_address - FROM msdb.dbo.sysoperators - WHERE name = 'DBAs'; - - SET @query = N'SELECT [Text] FROM rp_util.dbo.T_UTIL_CheckDbLog WHERE AlertSent = 0'; - - EXEC msdb.dbo.sp_send_dbmail @recipients = @recipients - ,@subject = 'DBCC CHECKDB found errors' - ,@query = @query - ,@attach_query_result_as_file = 0 - ,@query_result_no_padding = 1 - ,@query_result_header = 0; -END; - -DROP TABLE #CHECKDBLog; --- END: ALERT -- diff --git a/server-config/alert-server-trigger-database-add-or-drop.sql b/server-config/alert-server-trigger-database-add-or-drop.sql deleted file mode 100644 index 55179c8..0000000 --- a/server-config/alert-server-trigger-database-add-or-drop.sql +++ /dev/null @@ -1,59 +0,0 @@ -USE master; -GO - -IF EXISTS (SELECT * FROM sys.server_triggers WHERE parent_class_desc = 'SERVER' AND name = N'DatabaseAudit') -DROP TRIGGER [DatabaseAudit] ON ALL SERVER; -GO - -CREATE TRIGGER [DatabaseAudit] -ON ALL SERVER -FOR CREATE_DATABASE, DROP_DATABASE -AS -DECLARE @data XML, - @tsqlCommand NVARCHAR(MAX), - @eventType NVARCHAR(100), - @serverName NVARCHAR(100), - @loginName NVARCHAR(100), - @username NVARCHAR(100), - @databaseName NVARCHAR(100), - @objectName NVARCHAR(100), - @objectType NVARCHAR(100), - @emailBody NVARCHAR(MAX), - @recipients NVARCHAR(MAX); - -SET @data = EVENTDATA(); - -SET @tsqlCommand = EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)'); -SET @eventType = EVENTDATA().value('(/EVENT_INSTANCE/EventType)[1]','nvarchar(max)'); -SET @serverName = EVENTDATA().value('(/EVENT_INSTANCE/ServerName)[1]','nvarchar(max)'); -SET @loginName = EVENTDATA().value('(/EVENT_INSTANCE/LoginName)[1]','nvarchar(max)'); -SET @userName = EVENTDATA().value('(/EVENT_INSTANCE/UserName)[1]','nvarchar(max)'); -SET @databaseName = EVENTDATA().value('(/EVENT_INSTANCE/DatabaseName)[1]','nvarchar(max)'); -SET @objectName = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(max)'); -SET @objectType = EVENTDATA().value('(/EVENT_INSTANCE/ObjectType)[1]','nvarchar(max)'); - -SET @emailBody = '--------------------------------' + CHAR(13) -+ '- DDL Trigger Activation Report -' + CHAR(13) -+ '--------------------------------------' + CHAR(13) -+ 'Sql Command: ' + ISNULL(@tsqlCommand, 'No Command Given') + CHAR(13) -+ 'Event Type: ' + ISNULL(@eventType, 'No Event Type Given') + CHAR(13) -+ 'Server Name: ' + ISNULL(@serverName, 'No Server Given') + CHAR(13) -+ 'Login Name: ' + ISNULL(@loginName, 'No LOGIN Given') + CHAR(13) -+ 'User Name: ' + ISNULL(@username, 'No User Name Given') + CHAR(13) -+ 'DB Name: ' + ISNULL(@databaseName, 'No Database Given') + CHAR(13) -+ 'Object Name: ' + ISNULL(@objectName, 'No Object Given') + CHAR(13) -+ 'Object Type: ' + ISNULL(@objectType, 'No Type Given') + CHAR(13) -+ '-------------------------------------------'; - -SELECT @recipients = email_address -FROM msdb.dbo.sysoperators -WHERE name = 'DBAs'; - -EXEC msdb.dbo.sp_send_dbmail - @recipients = @recipients - , @subject = 'Database Audit Trigger' - , @body = @emailBody; -GO - -ENABLE TRIGGER [DatabaseAudit] ON ALL SERVER; -GO diff --git a/server-config/alert-sql-agent-job-step-failure.sql b/server-config/alert-sql-agent-job-step-failure.sql deleted file mode 100644 index 919e6f9..0000000 --- a/server-config/alert-sql-agent-job-step-failure.sql +++ /dev/null @@ -1,78 +0,0 @@ -EXECUTE AS LOGIN = 'SA'; - -DECLARE @recipients NVARCHAR(MAX) - ,@subject NVARCHAR(MAX) - ,@body NVARCHAR(MAX) - ,@query NVARCHAR(MAX) - ,@runtime INT = 80000 -- 8 AM - ,@rundate INT; - -SELECT @rundate = - CAST(YEAR(DATEADD(DAY, -1, GETDATE())) AS CHAR(4)) + CASE WHEN LEN(MONTH(DATEADD(DAY, -1, GETDATE()))) = 1 THEN '0' - ELSE '' - END + CAST(MONTH(DATEADD(DAY, -1, GETDATE())) AS VARCHAR(10)) - + CASE WHEN LEN(DAY(DATEADD(DAY, -1, GETDATE()))) = 1 THEN '0' - ELSE '' - END + CAST(DAY(DATEADD(DAY, -1, GETDATE())) AS VARCHAR(10)); - -SELECT @recipients = email_address -FROM msdb.dbo.sysoperators -WHERE name = 'DBAs'; ---SET @recipients = 'nate.hughes@morningstar.com'; - -SET @subject = N'SQL Agent Job Failure on ' + CONVERT(NVARCHAR(128), SERVERPROPERTY('ServerName')); - -IF EXISTS( - SELECT j.name AS job_name - ,s.step_id - ,s.step_name - ,s.subsystem - ,s.database_name - ,s.command - ,s.last_run_outcome - ,h.message - FROM msdb.dbo.sysjobs j - INNER JOIN msdb.dbo.sysjobsteps s - ON s.job_id = j.job_id - LEFT OUTER JOIN msdb.dbo.sysjobhistory h - ON h.job_id = s.job_id - AND h.step_id = s.step_id - WHERE j.enabled = 1 - AND s.last_run_outcome = 0 -- FAILED - AND s.last_run_date >= @rundate - AND s.last_run_time >= @runtime -) -BEGIN - -SET @query = - N'set nocount on; - SELECT ''job_name: '' + j.name - + char(10) + char(10) + ''step_name: '' + s.step_name - --+ char(10) + char(10) + s.subsystem + '' : '' + coalesce(s.database_name,'''') - + char(10) + char(10) + ''err_msg: '' + h.message - --,job_name = j.name - --,s.step_id - --,s.step_name - --,s.subsystem - --,s.database_name - --,s.command - --,s.last_run_outcome - --,h.message - FROM msdb.dbo.sysjobs j - INNER JOIN msdb.dbo.sysjobsteps s ON s.job_id = j.job_id - LEFT OUTER JOIN msdb.dbo.sysjobhistory h - ON h.job_id = s.job_id - AND h.step_id = s.step_id - WHERE j.enabled = 1 - AND s.last_run_outcome = 0 -- FAILED - AND s.last_run_date >= ' + CAST(@rundate AS VARCHAR) + N' - AND s.last_run_time >= ' + CAST(@runtime AS VARCHAR); - -EXEC msdb.dbo.sp_send_dbmail @recipients = @recipients - ,@body = @body - ,@subject = @subject - ,@importance = 'High' - ,@query = @query - ,@query_result_header = 0; - -END; diff --git a/server-config/tempdb-alter-filesize.sql b/server-config/tempdb-alter-filesize.sql deleted file mode 100644 index e486d9e598dc2e18e6496c87f5617679e8bf9ec3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmdUuO$z~06o#L*@*if0k{Gih3mRW#MlmIfjSL%K3;FqY$5+!RN)n4(_q_LmHtw#=9^k>b!*UYiC(MGfsb=gc&&s+{w_q7#=? zq&8r$I4ixciqSo*KpqoIdWJIZ_^HZ`9di=i{@jasb#wFonD0@-7mdsGwx;)E^O)pV zi_2WSjHk1ObKh=iigcHOI=7^Tq@oPIN1*rt0>!^3V10mq^&= 11 + SELECT @sql_memory_model_desc = sql_memory_model_desc + ,@affinity_type_desc = affinity_type_desc + FROM sys.dm_os_sys_info; + +CREATE TABLE #os_sys_info_adds ( + socket_count INT + ,cores_per_socket INT + ,numa_node_count INT + ,softnuma_configuration_desc VARCHAR(60) +); + +IF @Version >= 13 + INSERT #os_sys_info_adds (socket_count, cores_per_socket, numa_node_count, softnuma_configuration_desc) + SELECT socket_count + ,cores_per_socket + ,numa_node_count + ,softnuma_configuration_desc + FROM sys.dm_os_sys_info; + +CREATE TABLE #os_windows_info ( + windows_release VARCHAR(256) + ,windows_service_pack_level VARCHAR(256) + ,host_platform VARCHAR(256) + ,host_distribution VARCHAR(256) +); + +IF @Version >= 14 + INSERT #os_windows_info (windows_release, windows_service_pack_level, host_platform, host_distribution) + SELECT host_release + ,host_service_pack_level + ,host_platform + ,host_distribution + FROM sys.dm_os_host_info +ELSE + INSERT #os_windows_info (windows_release, windows_service_pack_level) + SELECT windows_release + , REPLACE(windows_service_pack_level,'Service Pack ','') + FROM sys.dm_os_windows_info + +SELECT SERVERPROPERTY('ServerName') AS HostName -- Both the Windows server and instance information associated with a specified instance of SQL Server. + ,SERVERPROPERTY('MachineName') AS MachineName -- For a clustered instance, Windows computer name on which the server instance is running. + ,DEFAULT_DOMAIN() AS Domain + ,ec.local_net_address AS IP + ,ec.local_tcp_port AS Port + --,SERVERPROPERTY('Edition') AS Product -- Installed product edition of the instance of SQL Server. + ,CASE WHEN @ProductVersion LIKE '8.%' THEN '2000' + WHEN @ProductVersion LIKE '9.%' THEN '2005' + WHEN @ProductVersion LIKE '10.0%' THEN '2008' + WHEN @ProductVersion LIKE '10.5%' THEN '2008 R2' + WHEN @ProductVersion LIKE '11.%' THEN '2012' + WHEN @ProductVersion LIKE '12.%' THEN '2014' + WHEN @ProductVersion LIKE '13.%' THEN '2016' + WHEN @ProductVersion LIKE '14.%' THEN '2017' + WHEN @ProductVersion LIKE '15.%' THEN '2019' + END + ' ' + + CASE CAST(SERVERPROPERTY('EngineEdition') AS NVARCHAR(128)) + WHEN '2' THEN 'Std' + WHEN '3' THEN 'Ent' + WHEN '4' THEN 'Exp' + END + + CASE WHEN CAST(SERVERPROPERTY('Edition') AS NVARCHAR(128)) LIKE '%64%' THEN ' x64' + ELSE ' x32' + END + AS Product + ,SERVERPROPERTY('ProductLevel') AS SP -- Level of the version of the instance of SQL Server. + ,@ProductVersion AS Version -- Version of the instance of SQL Server, in the form of 'major.minor.build.revision'. + ,ISNULL(SERVERPROPERTY('ProductUpdateLevel'),'') AS CU -- Update level of the current build. + ,CASE WHEN SERVERPROPERTY('IsClustered') = 1 THEN 'Y' ELSE 'N' END AS IsClustered -- Server instance is configured in a failover cluster. + ,CASE WHEN SERVERPROPERTY('IsFullTextInstalled') = 1 THEN 'Y' ELSE 'N' END AS IsFullTextInstalled -- Full-text and semantic indexing components are installed. + ,CASE WHEN SERVERPROPERTY('IsHadrEnabled') = 1 THEN 'Y' ELSE 'N' END AS IsHadrEnabled -- Always On Availability Groups is enabled on this server instance. + ,CAST(ROUND(os.physical_memory_kb / 1024.0 / 1024.0,0) AS INT) AS MemoryGB -- Specifies the total amount of physical memory on the machine. Not nullable. Converted to GB. + ,@sql_memory_model_desc AS MemoryModel + ,mn.memory_nodes AS MemoryNodes + ,@ProcessorNameString AS Processor + ,os.cpu_count AS LogicalCPU + ,tmp_add.socket_count AS SocketCount + ,tmp_add.cores_per_socket AS CoresPerSocket + ,tmp_add.numa_node_count AS NUMANodeCount + ,os.max_workers_count AS MaxWorkersCount + ,@affinity_type_desc AS AffinityType + ,tmp_add.softnuma_configuration_desc AS SoftNUMAConfiguration + ,COALESCE(wi.host_platform + ,CASE WHEN wi.windows_release = '6.1' THEN 'Windows Server 2008 R2' + WHEN wi.windows_release = '6.2' THEN 'windows Server 2012' + WHEN wi.windows_release = '6.3' THEN 'windows Server 2012 R2' + WHEN wi.windows_release = '10.0' THEN 'Windows Server 2016' + ELSE 'UNKNOWN' + END -- https://msdn.microsoft.com/library/ms724832%28vs.85%29.aspx?f=255&MSPPError=-2147217396 + ) AS OS + ,wi.host_distribution AS OSDescription + ,wi.windows_release AS OSVersion -- For Windows, returns the release number. Cannot be NULL. + ,wi.windows_service_pack_level AS OSServicePack -- For Windows, returns the service pack number. Cannot be NULL. + ,@BiosReleaseDate AS BiosDate +FROM sys.dm_os_sys_info os + CROSS JOIN #os_windows_info wi + CROSS JOIN sys.dm_exec_connections ec + CROSS JOIN (select COUNT(*) as memory_nodes from sys.dm_os_memory_nodes where memory_node_id <> 64) mn + CROSS JOIN #os_sys_info_adds tmp_add +WHERE ec.session_id = @@SPID; + +DROP TABLE IF EXISTS #os_sys_info_adds; +DROP TABLE IF EXISTS #os_windows_info; + +DECLARE @LoginAuditing INT + ,@DefaultData NVARCHAR(512) + ,@DefaultLog NVARCHAR(512) + ,@DefaultBackup NVARCHAR(512) + ,@NUMANodes INT + ,@TempDbFiles INT + ,@RegKey VARCHAR(100) + ,@SQLVersion VARCHAR(10) + ,@FailSafeOperator VARCHAR(50) + ,@DatabaseMailProfile VARCHAR(50); + +EXEC master..xp_instance_regread + @rootkey='HKEY_LOCAL_MACHINE', + @key='SOFTWARE\Microsoft\MSSQLServer\MSSQLServer', + @value_name='AuditLevel', + @value=@LoginAuditing OUTPUT; + +IF @Version >= 11 +BEGIN + SET @DefaultData = CAST(SERVERPROPERTY('InstanceDefaultDataPath') AS VARCHAR(128)); + SET @DefaultLog = CAST(SERVERPROPERTY('InstanceDefaultLogPath') AS VARCHAR(128)); +END; +ELSE +BEGIN + EXEC master.dbo.xp_instance_regread + @rootkey='HKEY_LOCAL_MACHINE', + @key='SOFTWARE\Microsoft\MSSQLServer\MSSQLServer', + @value_name='DefaultData', + @value=@DefaultData OUTPUT; + + EXEC master.dbo.xp_instance_regread + @rootkey='HKEY_LOCAL_MACHINE', + @key='SOFTWARE\Microsoft\MSSQLServer\MSSQLServer', + @value_name='DefaultLog', + @value=@DefaultLog OUTPUT; +END; + +EXEC master.dbo.xp_instance_regread + @rootkey='HKEY_LOCAL_MACHINE', + @key='SOFTWARE\Microsoft\MSSQLServer\MSSQLServer', + @value_name='BackupDirectory', + @value=@DefaultBackup OUTPUT; + +SELECT @SQLVersion = LEFT(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR(128)),2) +SET @RegKey = REPLACE('SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL00.MSSQLSERVER\SQLServerAgent', '00', @SQLVersion); +EXECUTE master.sys.xp_regread 'HKEY_LOCAL_MACHINE', @RegKey, 'AlertFailSafeOperator', @FailSafeOperator output; +EXECUTE master.sys.xp_regread 'HKEY_LOCAL_MACHINE', @RegKey, 'DatabaseMailProfile', @DatabaseMailProfile output; + +/* +http://www.sqlpassion.at/archive/2016/10/17/how-many-numa-nodes-do-i-have/ +For every available NUMA node SQL Server creates one dedicated Memory Node (besides Memory Node ID 64, which is always +present for the Dedicated Admin Connection). +*/ + +SELECT @TempDbFiles = COUNT(*) +FROM tempdb.sys.database_files +WHERE type = 0; + +SELECT CAST(ROUND(MAX(os.physical_memory_kb) / 1024.0 / 1024.0,0) AS INT) AS HostMemory_GB + ,CAST(MAX(CASE WHEN config.name = 'min server memory (MB)' THEN config.value END) AS INT) / 1024 AS MinMemory_GB + ,CAST(MAX(CASE WHEN config.name = 'max server memory (MB)' THEN config.value END) AS INT) / 1024 AS MaxMemory_GB + ,MAX(CASE WHEN SERVERPROPERTY('IsIntegratedSecurityOnly') = 0 THEN 'Y' ELSE 'N' END) AS MixedMode + ,MAX(CASE @LoginAuditing + WHEN 0 THEN 'None' + WHEN 1 THEN 'Successful Logins Only' + WHEN 2 THEN 'Failed Logins Only' + WHEN 3 THEN 'Both Failed and Successful Logins' + END) AS LoginAuditing + ,MAX(CASE WHEN config.name = 'cross db ownership chaining' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS CrossDBChaining + ,MAX(CASE WHEN config.name = 'remote access' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS RemoteConnections + ,MAX(CASE WHEN config.name = 'remote proc trans' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS ReqDistTransaction + ,MAX(CASE WHEN config.name = 'fill factor (%)' THEN config.value END) AS DefaultFillFactor + ,MAX(CASE WHEN config.name = 'backup checksum default' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS ChecksumBackup + ,MAX(CASE WHEN config.name = 'backup compression default' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS CompressBackup + ,@DefaultData AS DataPath + ,@DefaultLog AS LogPath + ,@DefaultBackup AS BackupPath + ,MAX(CASE WHEN config.name = 'clr enabled' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS CLREnabled + ,MAX(CASE WHEN config.name = 'clr strict security' AND config.value = 1 THEN 'Y' + WHEN @Version < 14 THEN '' + ELSE 'N' + END) AS CLRStrictSecurity + ,MAX(CASE WHEN config.name = 'filestream access level' THEN CASE CAST(config.value AS INT) + WHEN 0 THEN 'Disabled' + WHEN 1 THEN 'Transact-SQL access enabled' + WHEN 2 THEN 'Full access enabled' + END END) AS FILESTREAMAccessLevel + ,MAX(CASE WHEN config.name = 'server trigger recursion' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS RecursiveTriggers + ,MAX(CASE WHEN config.name = 'optimize for ad hoc workloads' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS OptimizeForAdHocWorkloads + ,MAX(CASE WHEN config.name = 'scan for startup procs' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS ScanForStartupProcs + ,MAX(CASE WHEN config.name = 'cost threshold for parallelism' THEN config.value END) AS CostThresholdParallelism + ,MAX(os.cpu_count) AS HostCPUs + ,MAX(CASE WHEN config.name = 'max degree of parallelism' THEN config.value END) AS MAXDOP + ,@TempDbFiles AS TempDbFiles + ,MAX(CASE WHEN config.name = 'Database Mail XPs' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS DBMailEnabled + ,MAX(CASE WHEN config.name = 'remote admin connections' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS DACEnabled + ,@FailSafeOperator as FailsafeOperator + ,@DatabaseMailProfile as DatabaseMailProfile + ,CAST(SERVERPROPERTY('Collation') AS NVARCHAR(128)) AS Collation +FROM sys.configurations config + CROSS JOIN sys.dm_os_sys_info os; + +---- http://blog.waynesheffield.com/wayne/archive/2017/09/registry-sql-server-startup-parameters/ + +--DECLARE @RegHive VARCHAR(50), +-- @RegKey VARCHAR(100); + +--SET @RegHive = 'HKEY_LOCAL_MACHINE'; +--SET @RegKey = 'Software\Microsoft\MSSQLSERVER\MSSQLServer\Parameters'; + +---- Get all of the arguments / parameters when starting up the service. +--DECLARE @SQLArgs TABLE ( +-- Value VARCHAR(50), +-- Data VARCHAR(500), +-- ArgNum AS CONVERT(INTEGER, REPLACE(Value, 'SQLArg', ''))); + +--INSERT INTO @SQLArgs +--EXECUTE master.sys.xp_instance_regenumvalues @RegHive, @RegKey; + +--SELECT Value AS StartupParam +-- ,Data AS StartupData +--FROM @SQLArgs; + +SELECT value_name AS StartupParam + ,value_data AS StartupData +FROM sys.dm_server_registry +WHERE registry_key LIKE N'%Parameters'; + +DBCC TRACESTATUS; + diff --git a/server-info/server-list-named-instances.sql b/server-get-instances-list.sql similarity index 96% rename from server-info/server-list-named-instances.sql rename to server-get-instances-list.sql index b84cde0..8d3b678 100644 --- a/server-info/server-list-named-instances.sql +++ b/server-get-instances-list.sql @@ -1,17 +1,17 @@ --- http://www.sqlfingers.com/2018/05/how-to-query-all-of-named-instances-for.html --- how many instances are there? - -DECLARE @Instances TABLE ( - Value VARCHAR(100), - InstanceName VARCHAR(100), - Data VARCHAR(100) - ) - -INSERT @Instances -EXECUTE xp_regread - @rootkey = 'HKEY_LOCAL_MACHINE', - @key = 'SOFTWARE\Microsoft\Microsoft SQL Server', - @value_name = 'InstalledInstances' - --- return your data +-- http://www.sqlfingers.com/2018/05/how-to-query-all-of-named-instances-for.html +-- how many instances are there? + +DECLARE @Instances TABLE ( + Value VARCHAR(100), + InstanceName VARCHAR(100), + Data VARCHAR(100) + ) + +INSERT @Instances +EXECUTE xp_regread + @rootkey = 'HKEY_LOCAL_MACHINE', + @key = 'SOFTWARE\Microsoft\Microsoft SQL Server', + @value_name = 'InstalledInstances' + +-- return your data SELECT InstanceName FROM @Instances \ No newline at end of file diff --git a/server-get-last-restart-date.sql b/server-get-last-restart-date.sql new file mode 100644 index 0000000..0042283 --- /dev/null +++ b/server-get-last-restart-date.sql @@ -0,0 +1 @@ +SELECT sqlserver_start_time FROM sys.dm_os_sys_info \ No newline at end of file diff --git a/server-get-policies.sql b/server-get-policies.sql new file mode 100644 index 0000000..4e89697 --- /dev/null +++ b/server-get-policies.sql @@ -0,0 +1,35 @@ + +SELECT @@SERVERNAME as servername + ,p.name as policyname + ,p.date_created as policy_date_created + ,p.created_by as policy_created_by + ,p.date_modified as policy_date_modified + ,p.modified_by as policy_modified_by + ,p.execution_mode + ,s.name as schedulename + ,s.enabled as scheduleenabled + ,s.freq_type + ,s.freq_interval + ,s.freq_subday_type + ,s.freq_subday_interval + ,s.freq_relative_interval + ,s.freq_recurrence_factor + ,s.active_start_date + ,s.active_start_time + ,s.active_end_time + ,p.description + ,p.is_enabled + ,j.name as jobname + ,j.enabled as jobenabled + ,c.name as conditionname + ,c.facet + ,c.expression + ,c.date_created as condition_date_created + ,c.created_by as condition_created_by + ,c.date_modified as condition_date_modified + ,c.modified_by as condition_modified_by +FROM msdb..syspolicy_policies p + LEFT JOIN msdb..sysschedules s ON p.schedule_uid = s.schedule_uid + LEFT JOIN msdb..sysjobs j ON p.job_id = j.job_id + JOIN msdb..syspolicy_conditions c ON p.condition_id = c.condition_id +WHERE p.is_system = 0; diff --git a/server-get-principals.sql b/server-get-principals.sql new file mode 100644 index 0000000..5eafb71 --- /dev/null +++ b/server-get-principals.sql @@ -0,0 +1,15 @@ + +SELECT @@SERVERNAME AS ServerName + ,DEFAULT_DOMAIN() AS Domain + ,p.name AS PrincipalName + ,p.type + ,p.is_disabled + ,p.create_date + ,p.modify_date + ,p.default_database_name + ,p.default_language_name + ,s.is_policy_checked + ,s.is_expiration_checked +FROM sys.server_principals p + LEFT JOIN sys.sql_logins s ON p.sid = s.sid +WHERE p.type IN ('S', 'U', 'G'); /*SQL login, Windows login, Windows group*/ diff --git a/server-get-services.sql b/server-get-services.sql new file mode 100644 index 0000000..e8ffdb1 --- /dev/null +++ b/server-get-services.sql @@ -0,0 +1,18 @@ + +select @@SERVERNAME AS servername + ,DEFAULT_DOMAIN() as domain + ,servicename + ,startup_type + ,status + ,last_startup_time + ,service_account + ,CASE is_clustered + WHEN 'Y' THEN 1 + WHEN 'N' THEN 0 + END AS is_clustered + ,cluster_nodename + ,CASE instant_file_initialization_enabled + WHEN 'Y' THEN 1 + WHEN 'N' THEN 0 + END AS instant_file_initialization_enabled +from sys.dm_server_services; diff --git a/server-config/startup-parameters_get.sql b/server-get-startup-parameters.sql similarity index 96% rename from server-config/startup-parameters_get.sql rename to server-get-startup-parameters.sql index ff66bea..b33cc98 100644 --- a/server-config/startup-parameters_get.sql +++ b/server-get-startup-parameters.sql @@ -1,21 +1,21 @@ --- http://blog.waynesheffield.com/wayne/archive/2017/09/registry-sql-server-startup-parameters/ - -DECLARE @RegHive VARCHAR(50), - @RegKey VARCHAR(100); - -SET @RegHive = 'HKEY_LOCAL_MACHINE'; -SET @RegKey = 'Software\Microsoft\MSSQLSERVER\MSSQLServer\Parameters'; - --- Get all of the arguments / parameters when starting up the service. -DECLARE @SQLArgs TABLE ( - Value VARCHAR(50), - Data VARCHAR(500), - ArgNum AS CONVERT(INTEGER, REPLACE(Value, 'SQLArg', ''))); - -INSERT INTO @SQLArgs - EXECUTE master.sys.xp_instance_regenumvalues @RegHive, @RegKey; - -SELECT * FROM @SQLArgs; - -DBCC TRACESTATUS; - +-- http://blog.waynesheffield.com/wayne/archive/2017/09/registry-sql-server-startup-parameters/ + +DECLARE @RegHive VARCHAR(50), + @RegKey VARCHAR(100); + +SET @RegHive = 'HKEY_LOCAL_MACHINE'; +SET @RegKey = 'Software\Microsoft\MSSQLSERVER\MSSQLServer\Parameters'; + +-- Get all of the arguments / parameters when starting up the service. +DECLARE @SQLArgs TABLE ( + Value VARCHAR(50), + Data VARCHAR(500), + ArgNum AS CONVERT(INTEGER, REPLACE(Value, 'SQLArg', ''))); + +INSERT INTO @SQLArgs + EXECUTE master.sys.xp_instance_regenumvalues @RegHive, @RegKey; + +SELECT * FROM @SQLArgs; + +DBCC TRACESTATUS; + diff --git a/server-get-volumes.sql b/server-get-volumes.sql new file mode 100644 index 0000000..7501389 --- /dev/null +++ b/server-get-volumes.sql @@ -0,0 +1,16 @@ + +SELECT DISTINCT @@SERVERNAME as servername + ,DEFAULT_DOMAIN() as domain + ,s.file_system_type + ,s.volume_mount_point + ,s.logical_volume_name + ,s.total_bytes + ,s.available_bytes + ,s.supports_compression + ,s.supports_alternate_streams + ,s.supports_sparse_files + ,s.is_read_only + ,s.is_compressed +FROM sys.master_files AS f +CROSS APPLY sys.dm_os_volume_stats(f.database_id, f.file_id) s; + diff --git a/server-info/linked-server-list.sql b/server-info/linked-server-list.sql deleted file mode 100644 index 5afa12b..0000000 --- a/server-info/linked-server-list.sql +++ /dev/null @@ -1,20 +0,0 @@ - - -SELECT [SrvId] = s.server_id - , [SrvEnabled] = s.is_data_access_enabled - , [SrvName] = s.name - , [SrvProduct] = s.product - , [SrvProvider] = s.provider - , [SrvDataSource] = s.data_source - , [LocalLogin] = ISNULL(c.name,'') - , [RemoteLogin] = ISNULL(ll.remote_name,'') - , [OutgoingRPCEnabled] = s.is_rpc_out_enabled - , [DTCEnabled] = s.is_remote_proc_transaction_promotion_enabled - , [ModifiedDate] = s.modify_date -FROM sys.Servers s - LEFT OUTER JOIN sys.linked_logins ll ON ll.server_id = s.server_id - LEFT OUTER JOIN sys.server_principals c ON c.principal_id = ll.local_principal_id -WHERE s.server_id > 0 -ORDER BY s.name; - ---exec sp_linkedservers \ No newline at end of file diff --git a/server-info/server-detail-and-config.sql b/server-info/server-detail-and-config.sql deleted file mode 100644 index 442aa6b..0000000 --- a/server-info/server-detail-and-config.sql +++ /dev/null @@ -1,148 +0,0 @@ - -SELECT SERVERPROPERTY('ServerName') AS HostName -- Both the Windows server and instance information associated with a specified instance of SQL Server. - ,SERVERPROPERTY('MachineName') AS MachineName -- For a clustered instance, Windows computer name on which the server instance is running. - ,DEFAULT_DOMAIN() AS Domain - ,ec.local_net_address AS IP - ,ec.local_tcp_port AS Port - --,SERVERPROPERTY('Edition') AS Product -- Installed product edition of the instance of SQL Server. - ,CASE WHEN CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(128)) LIKE '8.%' THEN '2000' - WHEN CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(128)) LIKE '9.%' THEN '2005' - WHEN CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(128)) LIKE '10.0%' THEN '2008' - WHEN CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(128)) LIKE '10.5%' THEN '2008 R2' - WHEN CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(128)) LIKE '11.%' THEN '2012' - WHEN CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(128)) LIKE '12.%' THEN '2014' - WHEN CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(128)) LIKE '13.%' THEN '2016' - END + ' ' + - CASE CAST(SERVERPROPERTY('EngineEdition') AS NVARCHAR(128)) - WHEN '2' THEN 'Std' - WHEN '3' THEN 'Ent' - WHEN '4' THEN 'Exp' - END + - CASE WHEN CAST(SERVERPROPERTY('Edition') AS NVARCHAR(128)) LIKE '%64%' THEN ' x64' - ELSE ' x32' - END - AS Product - ,SERVERPROPERTY('ProductLevel') AS SP -- Level of the version of the instance of SQL Server. - ,SERVERPROPERTY('ProductVersion') AS Version -- Version of the instance of SQL Server, in the form of 'major.minor.build.revision'. - ,ISNULL(SERVERPROPERTY('ProductUpdateLevel'),'') AS CU -- Update level of the current build. - ,ISNULL(SERVERPROPERTY('IsClustered'),0) AS Cluster -- Server instance is configured in a failover cluster. - ,ISNULL(SERVERPROPERTY('IsHadrEnabled'),0) AS AG -- Always On Availability Groups is enabled on this server instance. - ,CAST(ROUND(os.physical_memory_kb / 1024.0 / 1024.0,0) AS INT) AS Memory -- Specifies the total amount of physical memory on the machine. Not nullable. Converted to GB. - ,os.cpu_count AS CPU -- Specifies the number of logical CPUs on the system. Not nullable. - ,wi.windows_release AS OSVersion -- For Windows, returns the release number. Cannot be NULL. - ,CASE WHEN wi.windows_release = 6.1 THEN '2008 R2' - WHEN wi.windows_release = 6.2 THEN '2012' - WHEN wi.windows_release = 6.3 THEN '2012 R2' - WHEN wi.windows_release = 10.0 THEN '2016' - ELSE 'UNKNOWN' - END AS OS -- https://msdn.microsoft.com/library/ms724832%28vs.85%29.aspx?f=255&MSPPError=-2147217396 - ,REPLACE(wi.windows_service_pack_level,'Service Pack ','') AS OSSP -- For Windows, returns the service pack number. Cannot be NULL. -FROM sys.dm_os_sys_info os - CROSS JOIN sys.dm_os_windows_info wi - CROSS JOIN sys.dm_exec_connections ec -WHERE ec.session_id = @@SPID; - - -DECLARE @LoginAuditing INT - ,@DefaultData NVARCHAR(512) - ,@DefaultLog NVARCHAR(512) - ,@DefaultBackup NVARCHAR(512) - ,@NUMANodes INT - ,@TempDbFiles INT; - -EXEC master..xp_instance_regread - @rootkey='HKEY_LOCAL_MACHINE', - @key='SOFTWARE\Microsoft\MSSQLServer\MSSQLServer', - @value_name='AuditLevel', - @value=@LoginAuditing OUTPUT; - -EXEC master.dbo.xp_instance_regread - @rootkey='HKEY_LOCAL_MACHINE', - @key='SOFTWARE\Microsoft\MSSQLServer\MSSQLServer', - @value_name='DefaultData', - @value=@DefaultData OUTPUT; - -EXEC master.dbo.xp_instance_regread - @rootkey='HKEY_LOCAL_MACHINE', - @key='SOFTWARE\Microsoft\MSSQLServer\MSSQLServer', - @value_name='DefaultLog', - @value=@DefaultLog OUTPUT; - -EXEC master.dbo.xp_instance_regread - @rootkey='HKEY_LOCAL_MACHINE', - @key='SOFTWARE\Microsoft\MSSQLServer\MSSQLServer', - @value_name='BackupDirectory', - @value=@DefaultBackup OUTPUT; - -/* -http://www.sqlpassion.at/archive/2016/10/17/how-many-numa-nodes-do-i-have/ -For every available NUMA node SQL Server creates one dedicated Memory Node (besides Memory Node ID 64, which is always -present for the Dedicated Admin Connection). -*/ -SELECT @NUMANodes = COUNT(*) -FROM sys.dm_os_memory_nodes -WHERE memory_node_id <> 64; - -SELECT @TempDbFiles = COUNT(*) -FROM tempdb.sys.database_files -WHERE type = 0; - -SELECT CAST(ROUND(MAX(os.physical_memory_kb) / 1024.0 / 1024.0,0) AS INT) AS HostMemory_GB - ,CAST(MAX(CASE WHEN config.name = 'min server memory (MB)' THEN config.value END) AS INT) / 1024 AS MinMemory_GB - ,CAST(MAX(CASE WHEN config.name = 'max server memory (MB)' THEN config.value END) AS INT) / 1024 AS MaxMemory_GB - ,MAX(CASE WHEN SERVERPROPERTY('IsIntegratedSecurityOnly') = 0 THEN 'Y' ELSE 'N' END) AS MixedMode - ,MAX(CASE @LoginAuditing - WHEN 0 THEN 'None' - WHEN 1 THEN 'Successful Logins Only' - WHEN 2 THEN 'Failed Logins Only' - WHEN 3 THEN 'Both Failed and Successful Logins' - END) AS LoginAuditing - ,MAX(CASE WHEN config.name = 'cross db ownership chaining' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS CrossDBChaining - ,MAX(CASE WHEN config.name = 'remote access' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS RemoteConnections - ,MAX(CASE WHEN config.name = 'remote proc trans' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS ReqDistTransaction - ,MAX(CASE WHEN config.name = 'fill factor (%)' THEN config.value END) AS DefaultFillFactor - ,MAX(CASE WHEN config.name = 'backup compression default' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS CompressBackup - ,@DefaultData AS DataPath - ,@DefaultLog AS LogPath - ,@DefaultBackup AS BackupPath - ,MAX(CASE WHEN config.name = 'filestream access level' THEN CASE CAST(config.value AS INT) - WHEN 0 THEN 'Disabled' - WHEN 1 THEN 'Transact-SQL access enabled' - WHEN 2 THEN 'Full access enabled' - END END) AS FILESTREAMAccessLevel - ,MAX(CASE WHEN config.name = 'server trigger recursion' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS RecursiveTriggers - ,MAX(CASE WHEN config.name = 'optimize for ad hoc workloads' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS OptimizeForAdHocWorkloads - ,MAX(CASE WHEN config.name = 'scan for startup procs' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS ScanForStartupProcs - ,MAX(CASE WHEN config.name = 'cost threshold for parallelism' THEN config.value END) AS CostThresholdParallelism - ,MAX(os.cpu_count) AS HostCPUs - ,@NUMANodes AS NUMANodes - ,MAX(CASE WHEN config.name = 'max degree of parallelism' THEN config.value END) AS MAXDOP - ,@TempDbFiles AS TempDbFiles - ,MAX(CASE WHEN config.name = 'Database Mail XPs' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS DBMailEnabled - ,MAX(CASE WHEN config.name = 'remote admin connections' AND config.value = 1 THEN 'Y' ELSE 'N' END) AS DACEnabled -FROM sys.configurations config - CROSS JOIN sys.dm_os_sys_info os; - --- http://blog.waynesheffield.com/wayne/archive/2017/09/registry-sql-server-startup-parameters/ - -DECLARE @RegHive VARCHAR(50), - @RegKey VARCHAR(100); - -SET @RegHive = 'HKEY_LOCAL_MACHINE'; -SET @RegKey = 'Software\Microsoft\MSSQLSERVER\MSSQLServer\Parameters'; - --- Get all of the arguments / parameters when starting up the service. -DECLARE @SQLArgs TABLE ( - Value VARCHAR(50), - Data VARCHAR(500), - ArgNum AS CONVERT(INTEGER, REPLACE(Value, 'SQLArg', ''))); - -INSERT INTO @SQLArgs -EXECUTE master.sys.xp_instance_regenumvalues @RegHive, @RegKey; - -SELECT Value AS StartupParam - ,Data AS StartupData -FROM @SQLArgs; - -DBCC TRACESTATUS; - diff --git a/server-config/error-message-migration.sql b/server-migrate-error-messages.sql similarity index 97% rename from server-config/error-message-migration.sql rename to server-migrate-error-messages.sql index 56f2962..ead4caa 100644 --- a/server-config/error-message-migration.sql +++ b/server-migrate-error-messages.sql @@ -1,29 +1,29 @@ - -/********** SQL Server 2000 ********** -select 'exec sp_addmessage @msgnum=' + CONVERT(varchar(30),message_id) - + ', @severity=' + CONVERT(varchar(30),severity) - + ', @msgtext=' + '''' + REPLACE([text], CHAR(ASCII('''')), CHAR(ASCII(''''))+CHAR(ASCII(''''))) + '''' - + ', @replace=''replace'';' -from sys.messages -where message_id >= 50000 -********** SQL Server 2000 **********/ - -/********** SQL Server 2005+ **********/ ----- identify missing error messages -- ---select 'exec sp_addmessage @msgnum = ' + CONVERT(varchar(30),s.message_id) --- + ', @severity = ' + CONVERT(varchar(30),s.severity) --- + ', @msgtext = ' + '''' + REPLACE(s.[text], CHAR(ASCII('''')), CHAR(ASCII(''''))+CHAR(ASCII(''''))) + '''' --- + ', @replace = ''replace' + '''' ---FROM [SOURCE SERVER].master.sys.messages s --- LEFT OUTER JOIN sys.messages t ON s.message_id = t.message_id ---WHERE t.message_id IS NULL --- AND s.message_id >= 50000; - --- script out all error messages -- -select 'exec sp_addmessage @msgnum = ' + CONVERT(varchar(30),s.message_id) - + ', @severity = ' + CONVERT(varchar(30),s.severity) - + ', @msgtext = ' + '''' + REPLACE(s.[text], CHAR(ASCII('''')), CHAR(ASCII(''''))+CHAR(ASCII(''''))) + '''' - + ', @replace = ''replace' + '''' -FROM master.sys.messages s -WHERE s.message_id >= 50000; -/********** SQL Server 2005+ **********/ + +/********** SQL Server 2000 ********** +select 'exec sp_addmessage @msgnum=' + CONVERT(varchar(30),message_id) + + ', @severity=' + CONVERT(varchar(30),severity) + + ', @msgtext=' + '''' + REPLACE([text], CHAR(ASCII('''')), CHAR(ASCII(''''))+CHAR(ASCII(''''))) + '''' + + ', @replace=''replace'';' +from sys.messages +where message_id >= 50000 +********** SQL Server 2000 **********/ + +/********** SQL Server 2005+ **********/ +---- identify missing error messages -- +--select 'exec sp_addmessage @msgnum = ' + CONVERT(varchar(30),s.message_id) +-- + ', @severity = ' + CONVERT(varchar(30),s.severity) +-- + ', @msgtext = ' + '''' + REPLACE(s.[text], CHAR(ASCII('''')), CHAR(ASCII(''''))+CHAR(ASCII(''''))) + '''' +-- + ', @replace = ''replace' + '''' +--FROM [SOURCE SERVER].master.sys.messages s +-- LEFT OUTER JOIN sys.messages t ON s.message_id = t.message_id +--WHERE t.message_id IS NULL +-- AND s.message_id >= 50000; + +-- script out all error messages -- +select 'exec sp_addmessage @msgnum = ' + CONVERT(varchar(30),s.message_id) + + ', @severity = ' + CONVERT(varchar(30),s.severity) + + ', @msgtext = ' + '''' + REPLACE(s.[text], CHAR(ASCII('''')), CHAR(ASCII(''''))+CHAR(ASCII(''''))) + '''' + + ', @replace = ''replace' + '''' +FROM master.sys.messages s +WHERE s.message_id >= 50000; +/********** SQL Server 2005+ **********/ diff --git a/server-config/setup-MAXDOP-calc.sql b/server-set-MAXDOP.sql similarity index 95% rename from server-config/setup-MAXDOP-calc.sql rename to server-set-MAXDOP.sql index c09687a..8c01083 100644 --- a/server-config/setup-MAXDOP-calc.sql +++ b/server-set-MAXDOP.sql @@ -1,42 +1,42 @@ -SELECT Config_MAXDOP = value -FROM sys.configurations -WHERE name = 'max degree of parallelism'; -GO - -DECLARE @HyperThreading BIT = 1 -- assume hyperthreading on - , @Rec_MAXDOP SMALLINT; - -DECLARE @CPUs TABLE ( - NUMA_node INT - , CPUs SMALLINT -); - -INSERT INTO @CPUs (NUMA_node, CPUs) -SELECT parent_node_id - , COUNT(cpu_id) -FROM sys.dm_os_schedulers -WHERE [status] = 'VISIBLE ONLINE' -GROUP BY parent_node_id; - -IF (SELECT SUM(CPUs) FROM @CPUs) > 8 - SET @Rec_MAXDOP = 8; -ELSE IF @HyperThreading = 1 - SELECT @Rec_MAXDOP = MIN(CPUs) / 2 - FROM @CPUs; -ELSE - SELECT @Rec_MAXDOP = MIN(CPUs) - FROM @CPUs; - -SELECT Rec_MAXDOP = @Rec_MAXDOP; - -/* -EXEC sys.sp_configure N'show advanced options', N'1' RECONFIGURE WITH OVERRIDE -GO -EXEC sys.sp_configure N'max degree of parallelism', N'8' -GO -RECONFIGURE WITH OVERRIDE -GO -EXEC sys.sp_configure N'show advanced options', N'0' RECONFIGURE WITH OVERRIDE -GO -*/ - +SELECT Config_MAXDOP = value +FROM sys.configurations +WHERE name = 'max degree of parallelism'; +GO + +DECLARE @HyperThreading BIT = 1 -- assume hyperthreading on + , @Rec_MAXDOP SMALLINT; + +DECLARE @CPUs TABLE ( + NUMA_node INT + , CPUs SMALLINT +); + +INSERT INTO @CPUs (NUMA_node, CPUs) +SELECT parent_node_id + , COUNT(cpu_id) +FROM sys.dm_os_schedulers +WHERE [status] = 'VISIBLE ONLINE' +GROUP BY parent_node_id; + +IF (SELECT SUM(CPUs) FROM @CPUs) > 8 + SET @Rec_MAXDOP = 8; +ELSE IF @HyperThreading = 1 + SELECT @Rec_MAXDOP = MIN(CPUs) / 2 + FROM @CPUs; +ELSE + SELECT @Rec_MAXDOP = MIN(CPUs) + FROM @CPUs; + +SELECT Rec_MAXDOP = @Rec_MAXDOP; + +/* +EXEC sys.sp_configure N'show advanced options', N'1' RECONFIGURE WITH OVERRIDE +GO +EXEC sys.sp_configure N'max degree of parallelism', N'8' +GO +RECONFIGURE WITH OVERRIDE +GO +EXEC sys.sp_configure N'show advanced options', N'0' RECONFIGURE WITH OVERRIDE +GO +*/ + diff --git a/server-config/setup-min-max-memory-calc.sql b/server-set-min-max-memory.sql similarity index 97% rename from server-config/setup-min-max-memory-calc.sql rename to server-set-min-max-memory.sql index 4c968b3..d458fa6 100644 --- a/server-config/setup-min-max-memory-calc.sql +++ b/server-set-min-max-memory.sql @@ -1,53 +1,53 @@ -/* -https://straightpathsql.com/archives/2017/02/sql-server-max-memory-best-practices/ -*/ - -DECLARE @AvailableMemory_MB INT - ,@MaxMemory_MB INT - ,@MinMemory_MB INT - ,@AvailableMemory_GB INT; - -SELECT @AvailableMemory_MB = physical_memory_kb / 1024 - ,@AvailableMemory_GB = physical_memory_kb / 1024 / 1024 -FROM master.sys.dm_os_sys_info; - -SELECT @MaxMemory_MB = CAST(value_in_use AS INT) -FROM sys.configurations -WHERE name = 'Max Server Memory (MB)'; - -SELECT @MinMemory_MB = CAST(value_in_use AS INT) -FROM sys.configurations -WHERE name = 'Min Server Memory (MB)'; - -/* -A more accurate calculation as memory increases could be something around 1-2GB for the OS, plus 1GB for every 4GB up to 16GB, -then 1GB or so for every 8. For 128GB that would end up being 2 (base) + 4 (1 for every four up to 16) + 14 (1 for every 8 between -16 and 128) or 20GB. 10% would be 12% free, 20% would be 24% free. So you can use a calculation like that but I find that 10-20% -range works then watch and tweak if and as needed with data from your environment. So if we go with that 20GB free that means we’d -want to leave 108GB for SQL Server max. That works. It’s divisible by the NUMA nodes. So I’d want to set that number to 108GB, but -the setting is in MB. So I multiple 108 * 1,024 (MB per GB) and get 110,592MB. -*/ - -SELECT @AvailableMemory_MB AS AvailableMemory_MB - ,@MinMemory_MB AS ConfigMinMemory_MB - ,CEILING(@AvailableMemory_GB * 1.0 / 2) * 1024 AS CalcMinMemory_MB - ,@MaxMemory_MB AS ConfigMaxMemory_MB - ,(@AvailableMemory_GB - (2 /*OS*/ - + CASE WHEN @AvailableMemory_GB > 16 THEN 4 - ELSE (@AvailableMemory_GB / 4) - END /*plus 1GB for every 4GB up to 16GB*/ - + CASE WHEN @AvailableMemory_GB > 16 THEN ((@AvailableMemory_GB - 16) / 8) - ELSE 0 - END /*plus 1GB for every 8GB beyond 16GB*/ - ) - ) * 1024 AS CalcMaxMemory_MB; - - -/* -EXEC SP_CONFIGURE 'Min Server Memory' , 110592 -GO -EXEC SP_CONFIGURE 'Max Server Memory' , 17408 -GO -RECONFIGURE -GO +/* +https://straightpathsql.com/archives/2017/02/sql-server-max-memory-best-practices/ +*/ + +DECLARE @AvailableMemory_MB INT + ,@MaxMemory_MB INT + ,@MinMemory_MB INT + ,@AvailableMemory_GB INT; + +SELECT @AvailableMemory_MB = physical_memory_kb / 1024 + ,@AvailableMemory_GB = physical_memory_kb / 1024 / 1024 +FROM master.sys.dm_os_sys_info; + +SELECT @MaxMemory_MB = CAST(value_in_use AS INT) +FROM sys.configurations +WHERE name = 'Max Server Memory (MB)'; + +SELECT @MinMemory_MB = CAST(value_in_use AS INT) +FROM sys.configurations +WHERE name = 'Min Server Memory (MB)'; + +/* +A more accurate calculation as memory increases could be something around 1-2GB for the OS, plus 1GB for every 4GB up to 16GB, +then 1GB or so for every 8. For 128GB that would end up being 2 (base) + 4 (1 for every four up to 16) + 14 (1 for every 8 between +16 and 128) or 20GB. 10% would be 12% free, 20% would be 24% free. So you can use a calculation like that but I find that 10-20% +range works then watch and tweak if and as needed with data from your environment. So if we go with that 20GB free that means we’d +want to leave 108GB for SQL Server max. That works. It’s divisible by the NUMA nodes. So I’d want to set that number to 108GB, but +the setting is in MB. So I multiple 108 * 1,024 (MB per GB) and get 110,592MB. +*/ + +SELECT @AvailableMemory_MB AS AvailableMemory_MB + ,@MinMemory_MB AS ConfigMinMemory_MB + ,CEILING(@AvailableMemory_GB * 1.0 / 2) * 1024 AS CalcMinMemory_MB + ,@MaxMemory_MB AS ConfigMaxMemory_MB + ,(@AvailableMemory_GB - (2 /*OS*/ + + CASE WHEN @AvailableMemory_GB > 16 THEN 4 + ELSE (@AvailableMemory_GB / 4) + END /*plus 1GB for every 4GB up to 16GB*/ + + CASE WHEN @AvailableMemory_GB > 16 THEN ((@AvailableMemory_GB - 16) / 8) + ELSE 0 + END /*plus 1GB for every 8GB beyond 16GB*/ + ) + ) * 1024 AS CalcMaxMemory_MB; + + +/* +EXEC SP_CONFIGURE 'Min Server Memory' , 110592 +GO +EXEC SP_CONFIGURE 'Max Server Memory' , 17408 +GO +RECONFIGURE +GO */ \ No newline at end of file diff --git a/server-config/startup-parameters_set.sql b/server-set-startup-parameters.sql similarity index 97% rename from server-config/startup-parameters_set.sql rename to server-set-startup-parameters.sql index 33a2f76..995f701 100644 --- a/server-config/startup-parameters_set.sql +++ b/server-set-startup-parameters.sql @@ -1,151 +1,151 @@ -/****************************************************************************** -Globally enable / disable the specified trace flags. -Use DBCC TRACEON/TRACEOFF to enable disable globally trace flags, then adjust -the SQL Server instance startup parameters for these trace flags. - -SQL Server startup parameters are stored in the registry at: -HKLM\Software\Microsoft\Microsoft SQL Server\MSSQL12.SQL2014\MSSQLServer\Parameters - -To use the xp_instance_reg... XPs, use: -HKLM\Software\Microsoft\MSSQLSERVER\MSSQLServer\Parameters. - -To use: -1. Add the Trace Flags that you want modified to the @TraceFlags table variable. -2. Set the @DebugLevel variable to 1 to see what will happen on your system first. -3. When satisified what will happen, set @DebugLevel to 0 to actually execute the statements. -******************************************************************************** - MODIFICATION LOG -******************************************************************************** -http://blog.waynesheffield.com/wayne/archive/2017/09/registry-sql-server-startup-parameters/ -2016-08-03 WGS Initial Creation. -*******************************************************************************/ -SET NOCOUNT ON; --- Declare and initialize variables. --- To use with SQL 2005, cannot set the variables in the declare statement. -DECLARE @MaxValue INTEGER, - @SQLCMD VARCHAR(MAX), - @RegHive VARCHAR(50), - @RegKey VARCHAR(100), - @DebugLevel TINYINT; - -SET @RegHive = 'HKEY_LOCAL_MACHINE'; -SET @RegKey = 'Software\Microsoft\MSSQLSERVER\MSSQLServer\Parameters'; -SET @DebugLevel = 0; -- only makes changes if set to zero! - --- Add the trace flags that you want changed here. --- If enable = 1, DBCC TRACEON will be run; if enable = 0 then DBCC TRACEOFF will be run. --- If enable_on_startup = 1, then this TF will be added to start up on service restart; --- If enable_on_startup - 0, then this TF will be removed from starting up service restart -DECLARE @TraceFlags TABLE ( - TF INTEGER, - enable BIT, - enable_on_startup BIT, - TF2 AS '-T' + CONVERT(VARCHAR(15), TF) -); -INSERT INTO @TraceFlags (TF, enable, enable_on_startup) --- To work with SQL 2005, cannot use a table value constructor. --- So, use SELECT statements with UNION ALL for each TF to modify. -SELECT 1117, 1, 1 UNION ALL -SELECT 1118, 1, 1 UNION ALL -SELECT 1222, 0, 0 UNION ALL -SELECT 3226, 1, 1; - - --- Get all of the arguments / parameters when starting up the service. -DECLARE @SQLArgs TABLE ( - Value VARCHAR(50), - Data VARCHAR(500), - ArgNum AS CONVERT(INTEGER, REPLACE(Value, 'SQLArg', ''))); -INSERT INTO @SQLArgs - EXECUTE master.sys.xp_instance_regenumvalues @RegHive, @RegKey; - - --- Get the highest argument number that is currently set -SELECT @MaxValue = MAX(ArgNum) -FROM @SQLArgs; -RAISERROR('MaxValue: %i', 10, 1, @MaxValue) WITH NOWAIT; - --- Disable specified trace flags -SELECT @SQLCMD = 'DBCC TRACEOFF(' + - STUFF((SELECT ',' + CONVERT(VARCHAR(15), TF) - FROM @TraceFlags - WHERE enable = 0 - ORDER BY TF - FOR XML PATH(''), TYPE).value('.','varchar(max)') - ,1,1,'') + ', -1);' - -IF @DebugLevel = 0 EXECUTE (@SQLCMD); -RAISERROR('Disable TFs Command: "%s"', 10, 1, @SQLCMD) WITH NOWAIT; - --- Enable specified trace flags -SELECT @SQLCMD = 'DBCC TRACEON(' + - STUFF((SELECT ',' + CONVERT(VARCHAR(15), TF) - FROM @TraceFlags - WHERE enable = 1 - ORDER BY TF - FOR XML PATH(''), TYPE).value('.','varchar(max)') - ,1,1,'') + ', -1);' - -IF @DebugLevel = 0 EXECUTE (@SQLCMD); -RAISERROR('Enable TFs Command: "%s"', 10, 1, @SQLCMD) WITH NOWAIT; - -DECLARE cSQLParams CURSOR LOCAL FAST_FORWARD FOR -WITH cte AS -( - -- Current arguments, with new TFs added at the end. Get a row number to sort by. - SELECT *, - ROW_NUMBER() OVER (ORDER BY ISNULL(ArgNum, 999999999), TF) - 1 AS RN - FROM @SQLArgs arg - FULL OUTER JOIN @TraceFlags tf ON arg.Data = tf.TF2 -), cte2 AS -( - -- Use the row number to calc the SQLArg# for new TFs. - -- Use the original Value (SQLArg#) and Data for all rows if possible, - -- Otherwise use the calculated SQLArg# and the calculated TF2 column. - -- Only get the original non-TF-matched parameters, and the TFs set to be enabled - -- (existing startup TFs not in @TraceFlags are left alone). - SELECT ca.Value, - ca.Data - -- in case any TFs are removed, calculate new row numbers in order - -- to renumber the SQLArg values - , ROW_NUMBER() OVER (ORDER BY RN) - 1 AS RN2 - FROM cte - -- Again, for SQL 2005, use SELECT statement instead of VALUES. - CROSS APPLY (SELECT ISNULL(Value, 'SQLArg' + CONVERT(VARCHAR(15), RN)), - ISNULL(Data, TF2) ) ca(Value, Data) - WHERE ISNULL(enable_on_startup, 1) = 1 -- ISNULL handles non-TF parameters -) --- The first three parameters are the location of the errorlog directory, --- and the master database file locations. Ignore these. --- This returns the remaining parameters that should be set. --- Also return the highest number of parameters, so can determine if any need to be deleted. -SELECT 'SQLArg' + CONVERT(VARCHAR(15), RN2) AS Value, - Data, - MAX(RN2) OVER () AS MaxRN2 -FROM cte2 -WHERE RN2 > 2 -ORDER BY RN2; - -DECLARE @Value VARCHAR(50), - @Data VARCHAR(500), - @MaxRN2 INTEGER; -OPEN cSQLParams; -FETCH NEXT FROM cSQLParams INTO @Value, @Data, @MaxRN2; -WHILE @@FETCH_STATUS = 0 -BEGIN - IF @DebugLevel = 0 EXECUTE master.sys.xp_instance_regwrite @RegHive, @RegKey, @Value, 'REG_SZ', @Data; - RAISERROR('EXECUTE master.sys.xp_instance_regwrite ''%s'', ''%s'', ''%s'', ''REG_SZ'', ''%s''', 10, 1, @RegHive, @RegKey, @Value, @Data) WITH NOWAIT; - FETCH NEXT FROM cSQLParams INTO @Value, @Data, @MaxRN2; -END; -CLOSE cSQLParams; -DEALLOCATE cSQLParams; - --- In case deleting more TFs than added, there may be extra SQLArg values left behind. --- Need to delete the extras now. -WHILE @MaxValue > @MaxRN2 -BEGIN - SET @Value = 'SQLArg' + CONVERT(VARCHAR(15), @MaxValue); - IF @DebugLevel = 0 EXECUTE master.sys.xp_instance_regdeletevalue @RegHive, @RegKey, @Value; - RAISERROR('EXECUTE master.sys.xp_instance_regdeletevalue ''%s'', ''%s'', ''%s''', 10, 1, @RegHive, @RegKey, @Value) WITH NOWAIT; - SET @MaxValue = @MaxValue - 1; +/****************************************************************************** +Globally enable / disable the specified trace flags. +Use DBCC TRACEON/TRACEOFF to enable disable globally trace flags, then adjust +the SQL Server instance startup parameters for these trace flags. + +SQL Server startup parameters are stored in the registry at: +HKLM\Software\Microsoft\Microsoft SQL Server\MSSQL12.SQL2014\MSSQLServer\Parameters + +To use the xp_instance_reg... XPs, use: +HKLM\Software\Microsoft\MSSQLSERVER\MSSQLServer\Parameters. + +To use: +1. Add the Trace Flags that you want modified to the @TraceFlags table variable. +2. Set the @DebugLevel variable to 1 to see what will happen on your system first. +3. When satisified what will happen, set @DebugLevel to 0 to actually execute the statements. +******************************************************************************** + MODIFICATION LOG +******************************************************************************** +http://blog.waynesheffield.com/wayne/archive/2017/09/registry-sql-server-startup-parameters/ +2016-08-03 WGS Initial Creation. +*******************************************************************************/ +SET NOCOUNT ON; +-- Declare and initialize variables. +-- To use with SQL 2005, cannot set the variables in the declare statement. +DECLARE @MaxValue INTEGER, + @SQLCMD VARCHAR(MAX), + @RegHive VARCHAR(50), + @RegKey VARCHAR(100), + @DebugLevel TINYINT; + +SET @RegHive = 'HKEY_LOCAL_MACHINE'; +SET @RegKey = 'Software\Microsoft\MSSQLSERVER\MSSQLServer\Parameters'; +SET @DebugLevel = 0; -- only makes changes if set to zero! + +-- Add the trace flags that you want changed here. +-- If enable = 1, DBCC TRACEON will be run; if enable = 0 then DBCC TRACEOFF will be run. +-- If enable_on_startup = 1, then this TF will be added to start up on service restart; +-- If enable_on_startup - 0, then this TF will be removed from starting up service restart +DECLARE @TraceFlags TABLE ( + TF INTEGER, + enable BIT, + enable_on_startup BIT, + TF2 AS '-T' + CONVERT(VARCHAR(15), TF) +); +INSERT INTO @TraceFlags (TF, enable, enable_on_startup) +-- To work with SQL 2005, cannot use a table value constructor. +-- So, use SELECT statements with UNION ALL for each TF to modify. +SELECT 1117, 1, 1 UNION ALL +SELECT 1118, 1, 1 UNION ALL +SELECT 1222, 0, 0 UNION ALL +SELECT 3226, 1, 1; + + +-- Get all of the arguments / parameters when starting up the service. +DECLARE @SQLArgs TABLE ( + Value VARCHAR(50), + Data VARCHAR(500), + ArgNum AS CONVERT(INTEGER, REPLACE(Value, 'SQLArg', ''))); +INSERT INTO @SQLArgs + EXECUTE master.sys.xp_instance_regenumvalues @RegHive, @RegKey; + + +-- Get the highest argument number that is currently set +SELECT @MaxValue = MAX(ArgNum) +FROM @SQLArgs; +RAISERROR('MaxValue: %i', 10, 1, @MaxValue) WITH NOWAIT; + +-- Disable specified trace flags +SELECT @SQLCMD = 'DBCC TRACEOFF(' + + STUFF((SELECT ',' + CONVERT(VARCHAR(15), TF) + FROM @TraceFlags + WHERE enable = 0 + ORDER BY TF + FOR XML PATH(''), TYPE).value('.','varchar(max)') + ,1,1,'') + ', -1);' + +IF @DebugLevel = 0 EXECUTE (@SQLCMD); +RAISERROR('Disable TFs Command: "%s"', 10, 1, @SQLCMD) WITH NOWAIT; + +-- Enable specified trace flags +SELECT @SQLCMD = 'DBCC TRACEON(' + + STUFF((SELECT ',' + CONVERT(VARCHAR(15), TF) + FROM @TraceFlags + WHERE enable = 1 + ORDER BY TF + FOR XML PATH(''), TYPE).value('.','varchar(max)') + ,1,1,'') + ', -1);' + +IF @DebugLevel = 0 EXECUTE (@SQLCMD); +RAISERROR('Enable TFs Command: "%s"', 10, 1, @SQLCMD) WITH NOWAIT; + +DECLARE cSQLParams CURSOR LOCAL FAST_FORWARD FOR +WITH cte AS +( + -- Current arguments, with new TFs added at the end. Get a row number to sort by. + SELECT *, + ROW_NUMBER() OVER (ORDER BY ISNULL(ArgNum, 999999999), TF) - 1 AS RN + FROM @SQLArgs arg + FULL OUTER JOIN @TraceFlags tf ON arg.Data = tf.TF2 +), cte2 AS +( + -- Use the row number to calc the SQLArg# for new TFs. + -- Use the original Value (SQLArg#) and Data for all rows if possible, + -- Otherwise use the calculated SQLArg# and the calculated TF2 column. + -- Only get the original non-TF-matched parameters, and the TFs set to be enabled + -- (existing startup TFs not in @TraceFlags are left alone). + SELECT ca.Value, + ca.Data + -- in case any TFs are removed, calculate new row numbers in order + -- to renumber the SQLArg values + , ROW_NUMBER() OVER (ORDER BY RN) - 1 AS RN2 + FROM cte + -- Again, for SQL 2005, use SELECT statement instead of VALUES. + CROSS APPLY (SELECT ISNULL(Value, 'SQLArg' + CONVERT(VARCHAR(15), RN)), + ISNULL(Data, TF2) ) ca(Value, Data) + WHERE ISNULL(enable_on_startup, 1) = 1 -- ISNULL handles non-TF parameters +) +-- The first three parameters are the location of the errorlog directory, +-- and the master database file locations. Ignore these. +-- This returns the remaining parameters that should be set. +-- Also return the highest number of parameters, so can determine if any need to be deleted. +SELECT 'SQLArg' + CONVERT(VARCHAR(15), RN2) AS Value, + Data, + MAX(RN2) OVER () AS MaxRN2 +FROM cte2 +WHERE RN2 > 2 +ORDER BY RN2; + +DECLARE @Value VARCHAR(50), + @Data VARCHAR(500), + @MaxRN2 INTEGER; +OPEN cSQLParams; +FETCH NEXT FROM cSQLParams INTO @Value, @Data, @MaxRN2; +WHILE @@FETCH_STATUS = 0 +BEGIN + IF @DebugLevel = 0 EXECUTE master.sys.xp_instance_regwrite @RegHive, @RegKey, @Value, 'REG_SZ', @Data; + RAISERROR('EXECUTE master.sys.xp_instance_regwrite ''%s'', ''%s'', ''%s'', ''REG_SZ'', ''%s''', 10, 1, @RegHive, @RegKey, @Value, @Data) WITH NOWAIT; + FETCH NEXT FROM cSQLParams INTO @Value, @Data, @MaxRN2; +END; +CLOSE cSQLParams; +DEALLOCATE cSQLParams; + +-- In case deleting more TFs than added, there may be extra SQLArg values left behind. +-- Need to delete the extras now. +WHILE @MaxValue > @MaxRN2 +BEGIN + SET @Value = 'SQLArg' + CONVERT(VARCHAR(15), @MaxValue); + IF @DebugLevel = 0 EXECUTE master.sys.xp_instance_regdeletevalue @RegHive, @RegKey, @Value; + RAISERROR('EXECUTE master.sys.xp_instance_regdeletevalue ''%s'', ''%s'', ''%s''', 10, 1, @RegHive, @RegKey, @Value) WITH NOWAIT; + SET @MaxValue = @MaxValue - 1; END; \ No newline at end of file diff --git a/server-setup-database-mail.sql b/server-setup-database-mail.sql new file mode 100644 index 0000000..f50f418 --- /dev/null +++ b/server-setup-database-mail.sql @@ -0,0 +1,59 @@ +-- pre-req: Service Broker and Database Mail XPs enabled +select is_broker_enabled from sys.databases where name = 'msdb'; +select * from sys.configurations where name = 'database mail xps'; +go + +-- if need to enable Database Mail XPs +-- need Show Advanced Options enabled +select * from sys.configurations where name = 'show advanced options'; +go +-- if not, enabled and remember to disable after +EXEC sys.sp_configure 'show advanced options', N'1'; +RECONFIGURE; +go +-- enable Database Mail XPs +EXEC sys.sp_configure 'database mail xps', N'1'; +RECONFIGURE; +go +-- if you enabled Show Advanced Options, disable it now +EXEC sys.sp_configure 'show advanced options', N'0'; +RECONFIGURE; +go + +-- create Database Mail account +declare @account_id int + ,@profile_id int; + +EXEC msdb.dbo.sysmail_add_account_sp + @account_name = N'SQLAdmin@company.com' + ,@email_address = N'SQLAdmin@company.com' + ,@display_name = N'SQLAdmin@company.com' + ,@mailserver_name = N'smtp.domain.net' + ,@account_id = @account_id OUTPUT; + +-- create Database Mail profile +EXEC msdb.dbo.sysmail_add_profile_sp + @profile_name = N'DBA' + ,@profile_id = @profile_id OUTPUT; + +-- add account to profile +EXEC msdb.dbo.sysmail_add_profileaccount_sp + @profile_id = @profile_id + ,@account_id = @account_id + ,@sequence_number = 1; + +-- grant access to use Database Mail profile +EXEC msdb.dbo.sysmail_add_principalprofile_sp + @principal_id = 0 + ,@profile_id = @profile_id + ,@is_default = 1; +go + +/* +enable on sql server agent +prop > alert system +enale profile +include body... +enable fail-safe...email +restart sql agent +*/ \ No newline at end of file diff --git a/sp_who_is_active-run-as-script.sql b/sp_who_is_active-run-as-script.sql new file mode 100644 index 0000000..7efd75f --- /dev/null +++ b/sp_who_is_active-run-as-script.sql @@ -0,0 +1,5175 @@ +USE master +GO + +--IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'sp_WhoIsActive') +-- EXEC ('CREATE PROC dbo.sp_WhoIsActive AS SELECT ''stub version, to be replaced''') +--GO + +/********************************************************************************************* +Who Is Active? v11.17 (2016-10-18) +(C) 2007-2016, Adam Machanic + +Feedback: mailto:amachanic@gmail.com5 +Updates: http://whoisactive.com +kill 369 +License: + Who is Active? is free to download and use for personal, educational, and internal + corporate purposes, provided that this header is preserved. Redistribution or sale + of Who is Active?, in whole or in part, is prohibited without the author's express + written consent. +*********************************************************************************************/ +--ALTER PROC dbo.sp_WhoIsActive +--( +DECLARE +--~ + --Filters--Both inclusive and exclusive + --Set either filter to '' to disable + --Valid filter types are: session, program, database, login, and host + --Session is a session ID, and either 0 or '' can be used to indicate "all" sessions + --All other filter types support % or _ as wildcards + @filter sysname = '', --kill 320 + @filter_type VARCHAR(10) = 'login', + @not_filter sysname = '', + @not_filter_type VARCHAR(10) = 'session', + + --Retrieve data about the calling session? + @show_own_spid BIT = 0, + + --Retrieve data about system sessions? + @show_system_spids BIT = 0, + + --Controls how sleeping SPIDs are handled, based on the idea of levels of interest + --0 does not pull any sleeping SPIDs + --1 pulls only those sleeping SPIDs that also have an open transaction + --2 pulls all sleeping SPIDs + @show_sleeping_spids TINYINT = 1, + + --If 1, gets the full stored procedure or running batch, when available + --If 0, gets only the actual statement that is currently running in the batch or procedure + @get_full_inner_text BIT = 0, + + --Get associated query plans for running tasks, if available + --If @get_plans = 1, gets the plan based on the request's statement offset + --If @get_plans = 2, gets the entire plan based on the request's plan_handle + @get_plans TINYINT = 0, + + --Get the associated outer ad hoc query or stored procedure call, if available + @get_outer_command BIT = 1, + + --Enables pulling transaction log write info and transaction duration + @get_transaction_info BIT = 0, + + --Get information on active tasks, based on three interest levels + --Level 0 does not pull any task-related information + --Level 1 is a lightweight mode that pulls the top non-CXPACKET wait, giving preference to blockers + --Level 2 pulls all available task-based metrics, including: + --number of active tasks, current wait stats, physical I/O, context switches, and blocker information + @get_task_info TINYINT = 1, + + --Gets associated locks for each request, aggregated in an XML format + @get_locks BIT = 0, + + --Get average time for past runs of an active query + --(based on the combination of plan handle, sql handle, and offset) + @get_avg_time BIT = 0, + + --Get additional non-performance-related information about the session or request + --text_size, language, date_format, date_first, quoted_identifier, arithabort, ansi_null_dflt_on, + --ansi_defaults, ansi_warnings, ansi_padding, ansi_nulls, concat_null_yields_null, + --transaction_isolation_level, lock_timeout, deadlock_priority, row_count, command_type + -- + --If a SQL Agent job is running, an subnode called agent_info will be populated with some or all of + --the following: job_id, job_name, step_id, step_name, msdb_query_error (in the event of an error) + -- + --If @get_task_info is set to 2 and a lock wait is detected, a subnode called block_info will be + --populated with some or all of the following: lock_type, database_name, object_id, file_id, hobt_id, + --applock_hash, metadata_resource, metadata_class_id, object_name, schema_name + @get_additional_info BIT = 0, + + --Walk the blocking chain and count the number of + --total SPIDs blocked all the way down by a given session + --Also enables task_info Level 1, if @get_task_info is set to 0 + @find_block_leaders BIT = 0, + + --Pull deltas on various metrics + --Interval in seconds to wait before doing the second data pull + @delta_interval TINYINT = 0, + + --List of desired output columns, in desired order + --Note that the final output will be the intersection of all enabled features and all + --columns in the list. Therefore, only columns associated with enabled features will + --actually appear in the output. Likewise, removing columns from this list may effectively + --disable features, even if they are turned on + -- + --Each element in this list must be one of the valid output column names. Names must be + --delimited by square brackets. White space, formatting, and additional characters are + --allowed, as long as the list contains exact matches of delimited valid column names. + @output_column_list VARCHAR(8000) = '[dd%][session_id][sql_text][sql_command][login_name][wait_info][tasks][tran_log%][cpu%][temp%][block%][reads%][writes%][context%][physical%][query_plan][locks][%]', + + --Column(s) by which to sort output, optionally with sort directions. + --Valid column choices: + --session_id, physical_io, reads, physical_reads, writes, tempdb_allocations, + --tempdb_current, CPU, context_switches, used_memory, physical_io_delta, + --reads_delta, physical_reads_delta, writes_delta, tempdb_allocations_delta, + --tempdb_current_delta, CPU_delta, context_switches_delta, used_memory_delta, + --tasks, tran_start_time, open_tran_count, blocking_session_id, blocked_session_count, + --percent_complete, host_name, login_name, database_name, start_time, login_time + -- + --Note that column names in the list must be bracket-delimited. Commas and/or white + --space are not required. + @sort_order VARCHAR(500) = '[start_time] ASC', + + --Formats some of the output columns in a more "human readable" form + --0 disables outfput format + --1 formats the output for variable-width fonts + --2 formats the output for fixed-width fonts + @format_output TINYINT = 1, + + --If set to a non-blank value, the script will attempt to insert into the specified + --destination table. Please note that the script will not verify that the table exists, + --or that it has the correct schema, before doing the insert. + --Table can be specified in one, two, or three-part format + @destination_table VARCHAR(4000) = '', + + --If set to 1, no data collection will happen and no result set will be returned; instead, + --a CREATE TABLE statement will be returned via the @schema parameter, which will match + --the schema of the result set that would be returned by using the same collection of the + --rest of the parameters. The CREATE TABLE statement will have a placeholder token of + -- in place of an actual table name. + @return_schema BIT = 0, + --@schema VARCHAR(MAX) = NULL OUTPUT, + @schema VARCHAR(MAX) = NULL, + + --Help! What do I do? + @help BIT = 0 +--~ +--) +/* +OUTPUT COLUMNS +-------------- +Formatted/Non: [session_id] [smallint] NOT NULL + Session ID (a.k.a. SPID) + +Formatted: [dd hh:mm:ss.mss] [varchar](15) NULL +Non-Formatted: + For an active request, time the query has been running + For a sleeping session, time since the last batch completed + +Formatted: [dd hh:mm:ss.mss (avg)] [varchar](15) NULL +Non-Formatted: [avg_elapsed_time] [int] NULL + (Requires @get_avg_time option) + How much time has the active portion of the query taken in the past, on average? + +Formatted: [physical_io] [varchar](30) NULL +Non-Formatted: [physical_io] [bigint] NULL + Shows the number of physical I/Os, for active requests + +Formatted: [reads] [varchar](30) NULL +Non-Formatted: [reads] [bigint] NULL + For an active request, number of reads done for the current query + For a sleeping session, total number of reads done over the lifetime of the session + +Formatted: [physical_reads] [varchar](30) NULL +Non-Formatted: [physical_reads] [bigint] NULL + For an active request, number of physical reads done for the current query + For a sleeping session, total number of physical reads done over the lifetime of the session + +Formatted: [writes] [varchar](30) NULL +Non-Formatted: [writes] [bigint] NULL + For an active request, number of writes done for the current query + For a sleeping session, total number of writes done over the lifetime of the session + +Formatted: [tempdb_allocations] [varchar](30) NULL +Non-Formatted: [tempdb_allocations] [bigint] NULL + For an active request, number of TempDB writes done for the current query + For a sleeping session, total number of TempDB writes done over the lifetime of the session + +Formatted: [tempdb_current] [varchar](30) NULL +Non-Formatted: [tempdb_current] [bigint] NULL + For an active request, number of TempDB pages currently allocated for the query + For a sleeping session, number of TempDB pages currently allocated for the session + +Formatted: [CPU] [varchar](30) NULL +Non-Formatted: [CPU] [int] NULL + For an active request, total CPU time consumed by the current query + For a sleeping session, total CPU time consumed over the lifetime of the session + +Formatted: [context_switches] [varchar](30) NULL +Non-Formatted: [context_switches] [bigint] NULL + Shows the number of context switches, for active requests + +Formatted: [used_memory] [varchar](30) NOT NULL +Non-Formatted: [used_memory] [bigint] NOT NULL + For an active request, total memory consumption for the current query + For a sleeping session, total current memory consumption + +Formatted: [physical_io_delta] [varchar](30) NULL +Non-Formatted: [physical_io_delta] [bigint] NULL + (Requires @delta_interval option) + Difference between the number of physical I/Os reported on the first and second collections. + If the request started after the first collection, the value will be NULL + +Formatted: [reads_delta] [varchar](30) NULL +Non-Formatted: [reads_delta] [bigint] NULL + (Requires @delta_interval option) + Difference between the number of reads reported on the first and second collections. + If the request started after the first collection, the value will be NULL + +Formatted: [physical_reads_delta] [varchar](30) NULL +Non-Formatted: [physical_reads_delta] [bigint] NULL + (Requires @delta_interval option) + Difference between the number of physical reads reported on the first and second collections. + If the request started after the first collection, the value will be NULL + +Formatted: [writes_delta] [varchar](30) NULL +Non-Formatted: [writes_delta] [bigint] NULL + (Requires @delta_interval option) + Difference between the number of writes reported on the first and second collections. + If the request started after the first collection, the value will be NULL + +Formatted: [tempdb_allocations_delta] [varchar](30) NULL +Non-Formatted: [tempdb_allocations_delta] [bigint] NULL + (Requires @delta_interval option) + Difference between the number of TempDB writes reported on the first and second collections. + If the request started after the first collection, the value will be NULL + +Formatted: [tempdb_current_delta] [varchar](30) NULL +Non-Formatted: [tempdb_current_delta] [bigint] NULL + (Requires @delta_interval option) + Difference between the number of allocated TempDB pages reported on the first and second + collections. If the request started after the first collection, the value will be NULL + +Formatted: [CPU_delta] [varchar](30) NULL +Non-Formatted: [CPU_delta] [int] NULL + (Requires @delta_interval option) + Difference between the CPU time reported on the first and second collections. + If the request started after the first collection, the value will be NULL + +Formatted: [context_switches_delta] [varchar](30) NULL +Non-Formatted: [context_switches_delta] [bigint] NULL + (Requires @delta_interval option) + Difference between the context switches count reported on the first and second collections + If the request started after the first collection, the value will be NULL + +Formatted: [used_memory_delta] [varchar](30) NULL +Non-Formatted: [used_memory_delta] [bigint] NULL + Difference between the memory usage reported on the first and second collections + If the request started after the first collection, the value will be NULL + +Formatted: [tasks] [varchar](30) NULL +Non-Formatted: [tasks] [smallint] NULL + Number of worker tasks currently allocated, for active requests + +Formatted/Non: [status] [varchar](30) NOT NULL + Activity status for the session (running, sleeping, etc) + +Formatted/Non: [wait_info] [nvarchar](4000) NULL + Aggregates wait information, in the following format: + (Ax: Bms/Cms/Dms)E + A is the number of waiting tasks currently waiting on resource type E. B/C/D are wait + times, in milliseconds. If only one thread is waiting, its wait time will be shown as B. + If two tasks are waiting, each of their wait times will be shown (B/C). If three or more + tasks are waiting, the minimum, average, and maximum wait times will be shown (B/C/D). + If wait type E is a page latch wait and the page is of a "special" type (e.g. PFS, GAM, SGAM), + the page type will be identified. + If wait type E is CXPACKET, the nodeId from the query plan will be identified + +Formatted/Non: [locks] [xml] NULL + (Requires @get_locks option) + Aggregates lock information, in XML format. + The lock XML includes the lock mode, locked object, and aggregates the number of requests. + Attempts are made to identify locked objects by name + +Formatted/Non: [tran_start_time] [datetime] NULL + (Requires @get_transaction_info option) + Date and time that the first transaction opened by a session caused a transaction log + write to occur. + +Formatted/Non: [tran_log_writes] [nvarchar](4000) NULL + (Requires @get_transaction_info option) + Aggregates transaction log write information, in the following format: + A:wB (C kB) + A is a database that has been touched by an active transaction + B is the number of log writes that have been made in the database as a result of the transaction + C is the number of log kilobytes consumed by the log records + +Formatted: [open_tran_count] [varchar](30) NULL +Non-Formatted: [open_tran_count] [smallint] NULL + Shows the number of open transactions the session has open + +Formatted: [sql_command] [xml] NULL +Non-Formatted: [sql_command] [nvarchar](max) NULL + (Requires @get_outer_command option) + Shows the "outer" SQL command, i.e. the text of the batch or RPC sent to the server, + if available + +Formatted: [sql_text] [xml] NULL +Non-Formatted: [sql_text] [nvarchar](max) NULL + Shows the SQL text for active requests or the last statement executed + for sleeping sessions, if available in either case. + If @get_full_inner_text option is set, shows the full text of the batch. + Otherwise, shows only the active statement within the batch. + If the query text is locked, a special timeout message will be sent, in the following format: + + If an error occurs, an error message will be sent, in the following format: + + +Formatted/Non: [query_plan] [xml] NULL + (Requires @get_plans option) + Shows the query plan for the request, if available. + If the plan is locked, a special timeout message will be sent, in the following format: + + If an error occurs, an error message will be sent, in the following format: + + +Formatted/Non: [blocking_session_id] [smallint] NULL + When applicable, shows the blocking SPID + +Formatted: [blocked_session_count] [varchar](30) NULL +Non-Formatted: [blocked_session_count] [smallint] NULL + (Requires @find_block_leaders option) + The total number of SPIDs blocked by this session, + all the way down the blocking chain. + +Formatted: [percent_complete] [varchar](30) NULL +Non-Formatted: [percent_complete] [real] NULL + When applicable, shows the percent complete (e.g. for backups, restores, and some rollbacks) + +Formatted/Non: [host_name] [sysname] NOT NULL + Shows the host name for the connection + +Formatted/Non: [login_name] [sysname] NOT NULL + Shows the login name for the connection + +Formatted/Non: [database_name] [sysname] NULL + Shows the connected database + +Formatted/Non: [program_name] [sysname] NULL + Shows the reported program/application name + +Formatted/Non: [additional_info] [xml] NULL + (Requires @get_additional_info option) + Returns additional non-performance-related session/request information + If the script finds a SQL Agent job running, the name of the job and job step will be reported + If @get_task_info = 2 and the script finds a lock wait, the locked object will be reported + +Formatted/Non: [start_time] [datetime] NOT NULL + For active requests, shows the time the request started + For sleeping sessions, shows the time the last batch completed + +Formatted/Non: [login_time] [datetime] NOT NULL + Shows the time that the session connected + +Formatted/Non: [request_id] [int] NULL + For active requests, shows the request_id + Should be 0 unless MARS is being used + +Formatted/Non: [collection_time] [datetime] NOT NULL + Time that this script's final SELECT ran +*/ +--AS +BEGIN; + SET NOCOUNT ON; + SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; + SET QUOTED_IDENTIFIER ON; + SET ANSI_PADDING ON; + SET CONCAT_NULL_YIELDS_NULL ON; + SET ANSI_WARNINGS ON; + SET NUMERIC_ROUNDABORT OFF; + SET ARITHABORT ON; + + IF + @filter IS NULL + OR @filter_type IS NULL + OR @not_filter IS NULL + OR @not_filter_type IS NULL + OR @show_own_spid IS NULL + OR @show_system_spids IS NULL + OR @show_sleeping_spids IS NULL + OR @get_full_inner_text IS NULL + OR @get_plans IS NULL + OR @get_outer_command IS NULL + OR @get_transaction_info IS NULL + OR @get_task_info IS NULL + OR @get_locks IS NULL + OR @get_avg_time IS NULL + OR @get_additional_info IS NULL + OR @find_block_leaders IS NULL + OR @delta_interval IS NULL + OR @format_output IS NULL + OR @output_column_list IS NULL + OR @sort_order IS NULL + OR @return_schema IS NULL + OR @destination_table IS NULL + OR @help IS NULL + BEGIN; + RAISERROR('Input parameters cannot be NULL', 16, 1); + RETURN; + END; + + IF @filter_type NOT IN ('session', 'program', 'database', 'login', 'host') + BEGIN; + RAISERROR('Valid filter types are: session, program, database, login, host', 16, 1); + RETURN; + END; + + IF @filter_type = 'session' AND @filter LIKE '%[^0123456789]%' + BEGIN; + RAISERROR('Session filters must be valid integers', 16, 1); + RETURN; + END; + + IF @not_filter_type NOT IN ('session', 'program', 'database', 'login', 'host') + BEGIN; + RAISERROR('Valid filter types are: session, program, database, login, host', 16, 1); + RETURN; + END; + + IF @not_filter_type = 'session' AND @not_filter LIKE '%[^0123456789]%' + BEGIN; + RAISERROR('Session filters must be valid integers', 16, 1); + RETURN; + END; + + IF @show_sleeping_spids NOT IN (0, 1, 2) + BEGIN; + RAISERROR('Valid values for @show_sleeping_spids are: 0, 1, or 2', 16, 1); + RETURN; + END; + + IF @get_plans NOT IN (0, 1, 2) + BEGIN; + RAISERROR('Valid values for @get_plans are: 0, 1, or 2', 16, 1); + RETURN; + END; + + IF @get_task_info NOT IN (0, 1, 2) + BEGIN; + RAISERROR('Valid values for @get_task_info are: 0, 1, or 2', 16, 1); + RETURN; + END; + + IF @format_output NOT IN (0, 1, 2) + BEGIN; + RAISERROR('Valid values for @format_output are: 0, 1, or 2', 16, 1); + RETURN; + END; + + IF @help = 1 + BEGIN; + DECLARE + @header VARCHAR(MAX), + @params VARCHAR(MAX), + @outputs VARCHAR(MAX); + + SELECT + @header = + REPLACE + ( + REPLACE + ( + CONVERT + ( + VARCHAR(MAX), + SUBSTRING + ( + t.text, + CHARINDEX('/' + REPLICATE('*', 93), t.text) + 94, + CHARINDEX(REPLICATE('*', 93) + '/', t.text) - (CHARINDEX('/' + REPLICATE('*', 93), t.text) + 94) + ) + ), + CHAR(13)+CHAR(10), + CHAR(13) + ), + ' ', + '' + ), + @params = + CHAR(13) + + REPLACE + ( + REPLACE + ( + CONVERT + ( + VARCHAR(MAX), + SUBSTRING + ( + t.text, + CHARINDEX('--~', t.text) + 5, + CHARINDEX('--~', t.text, CHARINDEX('--~', t.text) + 5) - (CHARINDEX('--~', t.text) + 5) + ) + ), + CHAR(13)+CHAR(10), + CHAR(13) + ), + ' ', + '' + ), + @outputs = + CHAR(13) + + REPLACE + ( + REPLACE + ( + REPLACE + ( + CONVERT + ( + VARCHAR(MAX), + SUBSTRING + ( + t.text, + CHARINDEX('OUTPUT COLUMNS'+CHAR(13)+CHAR(10)+'--------------', t.text) + 32, + CHARINDEX('*/', t.text, CHARINDEX('OUTPUT COLUMNS'+CHAR(13)+CHAR(10)+'--------------', t.text) + 32) - (CHARINDEX('OUTPUT COLUMNS'+CHAR(13)+CHAR(10)+'--------------', t.text) + 32) + ) + ), + CHAR(9), + CHAR(255) + ), + CHAR(13)+CHAR(10), + CHAR(13) + ), + ' ', + '' + ) + + CHAR(13) + FROM sys.dm_exec_requests AS r + CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t + WHERE + r.session_id = @@SPID; + + WITH + a0 AS + (SELECT 1 AS n UNION ALL SELECT 1), + a1 AS + (SELECT 1 AS n FROM a0 AS a, a0 AS b), + a2 AS + (SELECT 1 AS n FROM a1 AS a, a1 AS b), + a3 AS + (SELECT 1 AS n FROM a2 AS a, a2 AS b), + a4 AS + (SELECT 1 AS n FROM a3 AS a, a3 AS b), + numbers AS + ( + SELECT TOP(LEN(@header) - 1) + ROW_NUMBER() OVER + ( + ORDER BY (SELECT NULL) + ) AS number + FROM a4 + ORDER BY + number + ) + SELECT + RTRIM(LTRIM( + SUBSTRING + ( + @header, + number + 1, + CHARINDEX(CHAR(13), @header, number + 1) - number - 1 + ) + )) AS [------header---------------------------------------------------------------------------------------------------------------] + FROM numbers + WHERE + SUBSTRING(@header, number, 1) = CHAR(13); + + WITH + a0 AS + (SELECT 1 AS n UNION ALL SELECT 1), + a1 AS + (SELECT 1 AS n FROM a0 AS a, a0 AS b), + a2 AS + (SELECT 1 AS n FROM a1 AS a, a1 AS b), + a3 AS + (SELECT 1 AS n FROM a2 AS a, a2 AS b), + a4 AS + (SELECT 1 AS n FROM a3 AS a, a3 AS b), + numbers AS + ( + SELECT TOP(LEN(@params) - 1) + ROW_NUMBER() OVER + ( + ORDER BY (SELECT NULL) + ) AS number + FROM a4 + ORDER BY + number + ), + tokens AS + ( + SELECT + RTRIM(LTRIM( + SUBSTRING + ( + @params, + number + 1, + CHARINDEX(CHAR(13), @params, number + 1) - number - 1 + ) + )) AS token, + number, + CASE + WHEN SUBSTRING(@params, number + 1, 1) = CHAR(13) THEN number + ELSE COALESCE(NULLIF(CHARINDEX(',' + CHAR(13) + CHAR(13), @params, number), 0), LEN(@params)) + END AS param_group, + ROW_NUMBER() OVER + ( + PARTITION BY + CHARINDEX(',' + CHAR(13) + CHAR(13), @params, number), + SUBSTRING(@params, number+1, 1) + ORDER BY + number + ) AS group_order + FROM numbers + WHERE + SUBSTRING(@params, number, 1) = CHAR(13) + ), + parsed_tokens AS + ( + SELECT + MIN + ( + CASE + WHEN token LIKE '@%' THEN token + ELSE NULL + END + ) AS parameter, + MIN + ( + CASE + WHEN token LIKE '--%' THEN RIGHT(token, LEN(token) - 2) + ELSE NULL + END + ) AS description, + param_group, + group_order + FROM tokens + WHERE + NOT + ( + token = '' + AND group_order > 1 + ) + GROUP BY + param_group, + group_order + ) + SELECT + CASE + WHEN description IS NULL AND parameter IS NULL THEN '-------------------------------------------------------------------------' + WHEN param_group = MAX(param_group) OVER() THEN parameter + ELSE COALESCE(LEFT(parameter, LEN(parameter) - 1), '') + END AS [------parameter----------------------------------------------------------], + CASE + WHEN description IS NULL AND parameter IS NULL THEN '----------------------------------------------------------------------------------------------------------------------' + ELSE COALESCE(description, '') + END AS [------description-----------------------------------------------------------------------------------------------------] + FROM parsed_tokens + ORDER BY + param_group, + group_order; + + WITH + a0 AS + (SELECT 1 AS n UNION ALL SELECT 1), + a1 AS + (SELECT 1 AS n FROM a0 AS a, a0 AS b), + a2 AS + (SELECT 1 AS n FROM a1 AS a, a1 AS b), + a3 AS + (SELECT 1 AS n FROM a2 AS a, a2 AS b), + a4 AS + (SELECT 1 AS n FROM a3 AS a, a3 AS b), + numbers AS + ( + SELECT TOP(LEN(@outputs) - 1) + ROW_NUMBER() OVER + ( + ORDER BY (SELECT NULL) + ) AS number + FROM a4 + ORDER BY + number + ), + tokens AS + ( + SELECT + RTRIM(LTRIM( + SUBSTRING + ( + @outputs, + number + 1, + CASE + WHEN + COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) < + COALESCE(NULLIF(CHARINDEX(CHAR(13) + CHAR(255) COLLATE Latin1_General_Bin2, @outputs, number + 1), 0), LEN(@outputs)) + THEN COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) - number - 1 + ELSE + COALESCE(NULLIF(CHARINDEX(CHAR(13) + CHAR(255) COLLATE Latin1_General_Bin2, @outputs, number + 1), 0), LEN(@outputs)) - number - 1 + END + ) + )) AS token, + number, + COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) AS output_group, + ROW_NUMBER() OVER + ( + PARTITION BY + COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) + ORDER BY + number + ) AS output_group_order + FROM numbers + WHERE + SUBSTRING(@outputs, number, 10) = CHAR(13) + 'Formatted' + OR SUBSTRING(@outputs, number, 2) = CHAR(13) + CHAR(255) COLLATE Latin1_General_Bin2 + ), + output_tokens AS + ( + SELECT + *, + CASE output_group_order + WHEN 2 THEN MAX(CASE output_group_order WHEN 1 THEN token ELSE NULL END) OVER (PARTITION BY output_group) + ELSE '' + END COLLATE Latin1_General_Bin2 AS column_info + FROM tokens + ) + SELECT + CASE output_group_order + WHEN 1 THEN '-----------------------------------' + WHEN 2 THEN + CASE + WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN + SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+1, CHARINDEX(']', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+2) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)) + ELSE + SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+2, CHARINDEX(']', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+2) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)-1) + END + ELSE '' + END AS formatted_column_name, + CASE output_group_order + WHEN 1 THEN '-----------------------------------' + WHEN 2 THEN + CASE + WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN + SUBSTRING(column_info, CHARINDEX(']', column_info)+2, LEN(column_info)) + ELSE + SUBSTRING(column_info, CHARINDEX(']', column_info)+2, CHARINDEX('Non-Formatted:', column_info, CHARINDEX(']', column_info)+2) - CHARINDEX(']', column_info)-3) + END + ELSE '' + END AS formatted_column_type, + CASE output_group_order + WHEN 1 THEN '---------------------------------------' + WHEN 2 THEN + CASE + WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN '' + ELSE + CASE + WHEN SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, 1) = '<' THEN + SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, CHARINDEX('>', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))) + ELSE + SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, CHARINDEX(']', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))) + END + END + ELSE '' + END AS unformatted_column_name, + CASE output_group_order + WHEN 1 THEN '---------------------------------------' + WHEN 2 THEN + CASE + WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN '' + ELSE + CASE + WHEN SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, 1) = '<' THEN '' + ELSE + SUBSTRING(column_info, CHARINDEX(']', column_info, CHARINDEX('Non-Formatted:', column_info))+2, CHARINDEX('Non-Formatted:', column_info, CHARINDEX(']', column_info)+2) - CHARINDEX(']', column_info)-3) + END + END + ELSE '' + END AS unformatted_column_type, + CASE output_group_order + WHEN 1 THEN '----------------------------------------------------------------------------------------------------------------------' + ELSE REPLACE(token, CHAR(255) COLLATE Latin1_General_Bin2, '') + END AS [------description-----------------------------------------------------------------------------------------------------] + FROM output_tokens + WHERE + NOT + ( + output_group_order = 1 + AND output_group = LEN(@outputs) + ) + ORDER BY + output_group, + CASE output_group_order + WHEN 1 THEN 99 + ELSE output_group_order + END; + + RETURN; + END; + + WITH + a0 AS + (SELECT 1 AS n UNION ALL SELECT 1), + a1 AS + (SELECT 1 AS n FROM a0 AS a, a0 AS b), + a2 AS + (SELECT 1 AS n FROM a1 AS a, a1 AS b), + a3 AS + (SELECT 1 AS n FROM a2 AS a, a2 AS b), + a4 AS + (SELECT 1 AS n FROM a3 AS a, a3 AS b), + numbers AS + ( + SELECT TOP(LEN(@output_column_list)) + ROW_NUMBER() OVER + ( + ORDER BY (SELECT NULL) + ) AS number + FROM a4 + ORDER BY + number + ), + tokens AS + ( + SELECT + '|[' + + SUBSTRING + ( + @output_column_list, + number + 1, + CHARINDEX(']', @output_column_list, number) - number - 1 + ) + '|]' AS token, + number + FROM numbers + WHERE + SUBSTRING(@output_column_list, number, 1) = '[' + ), + ordered_columns AS + ( + SELECT + x.column_name, + ROW_NUMBER() OVER + ( + PARTITION BY + x.column_name + ORDER BY + tokens.number, + x.default_order + ) AS r, + ROW_NUMBER() OVER + ( + ORDER BY + tokens.number, + x.default_order + ) AS s + FROM tokens + JOIN + ( + SELECT '[session_id]' AS column_name, 1 AS default_order + UNION ALL + SELECT '[dd hh:mm:ss.mss]', 2 + WHERE + @format_output IN (1, 2) + UNION ALL + SELECT '[dd hh:mm:ss.mss (avg)]', 3 + WHERE + @format_output IN (1, 2) + AND @get_avg_time = 1 + UNION ALL + SELECT '[avg_elapsed_time]', 4 + WHERE + @format_output = 0 + AND @get_avg_time = 1 + UNION ALL + SELECT '[physical_io]', 5 + WHERE + @get_task_info = 2 + UNION ALL + SELECT '[reads]', 6 + UNION ALL + SELECT '[physical_reads]', 7 + UNION ALL + SELECT '[writes]', 8 + UNION ALL + SELECT '[tempdb_allocations]', 9 + UNION ALL + SELECT '[tempdb_current]', 10 + UNION ALL + SELECT '[CPU]', 11 + UNION ALL + SELECT '[context_switches]', 12 + WHERE + @get_task_info = 2 + UNION ALL + SELECT '[used_memory]', 13 + UNION ALL + SELECT '[physical_io_delta]', 14 + WHERE + @delta_interval > 0 + AND @get_task_info = 2 + UNION ALL + SELECT '[reads_delta]', 15 + WHERE + @delta_interval > 0 + UNION ALL + SELECT '[physical_reads_delta]', 16 + WHERE + @delta_interval > 0 + UNION ALL + SELECT '[writes_delta]', 17 + WHERE + @delta_interval > 0 + UNION ALL + SELECT '[tempdb_allocations_delta]', 18 + WHERE + @delta_interval > 0 + UNION ALL + SELECT '[tempdb_current_delta]', 19 + WHERE + @delta_interval > 0 + UNION ALL + SELECT '[CPU_delta]', 20 + WHERE + @delta_interval > 0 + UNION ALL + SELECT '[context_switches_delta]', 21 + WHERE + @delta_interval > 0 + AND @get_task_info = 2 + UNION ALL + SELECT '[used_memory_delta]', 22 + WHERE + @delta_interval > 0 + UNION ALL + SELECT '[tasks]', 23 + WHERE + @get_task_info = 2 + UNION ALL + SELECT '[status]', 24 + UNION ALL + SELECT '[wait_info]', 25 + WHERE + @get_task_info > 0 + OR @find_block_leaders = 1 + UNION ALL + SELECT '[locks]', 26 + WHERE + @get_locks = 1 + UNION ALL + SELECT '[tran_start_time]', 27 + WHERE + @get_transaction_info = 1 + UNION ALL + SELECT '[tran_log_writes]', 28 + WHERE + @get_transaction_info = 1 + UNION ALL + SELECT '[open_tran_count]', 29 + UNION ALL + SELECT '[sql_command]', 30 + WHERE + @get_outer_command = 1 + UNION ALL + SELECT '[sql_text]', 31 + UNION ALL + SELECT '[query_plan]', 32 + WHERE + @get_plans >= 1 + UNION ALL + SELECT '[blocking_session_id]', 33 + WHERE + @get_task_info > 0 + OR @find_block_leaders = 1 + UNION ALL + SELECT '[blocked_session_count]', 34 + WHERE + @find_block_leaders = 1 + UNION ALL + SELECT '[percent_complete]', 35 + UNION ALL + SELECT '[host_name]', 36 + UNION ALL + SELECT '[login_name]', 37 + UNION ALL + SELECT '[database_name]', 38 + UNION ALL + SELECT '[program_name]', 39 + UNION ALL + SELECT '[additional_info]', 40 + WHERE + @get_additional_info = 1 + UNION ALL + SELECT '[start_time]', 41 + UNION ALL + SELECT '[login_time]', 42 + UNION ALL + SELECT '[request_id]', 43 + UNION ALL + SELECT '[collection_time]', 44 + ) AS x ON + x.column_name LIKE token ESCAPE '|' + ) + SELECT + @output_column_list = + STUFF + ( + ( + SELECT + ',' + column_name as [text()] + FROM ordered_columns + WHERE + r = 1 + ORDER BY + s + FOR XML + PATH('') + ), + 1, + 1, + '' + ); + + IF COALESCE(RTRIM(@output_column_list), '') = '' + BEGIN; + RAISERROR('No valid column matches found in @output_column_list or no columns remain due to selected options.', 16, 1); + RETURN; + END; + + IF @destination_table <> '' + BEGIN; + SET @destination_table = + --database + COALESCE(QUOTENAME(PARSENAME(@destination_table, 3)) + '.', '') + + --schema + COALESCE(QUOTENAME(PARSENAME(@destination_table, 2)) + '.', '') + + --table + COALESCE(QUOTENAME(PARSENAME(@destination_table, 1)), ''); + + IF COALESCE(RTRIM(@destination_table), '') = '' + BEGIN; + RAISERROR('Destination table not properly formatted.', 16, 1); + RETURN; + END; + END; + + WITH + a0 AS + (SELECT 1 AS n UNION ALL SELECT 1), + a1 AS + (SELECT 1 AS n FROM a0 AS a, a0 AS b), + a2 AS + (SELECT 1 AS n FROM a1 AS a, a1 AS b), + a3 AS + (SELECT 1 AS n FROM a2 AS a, a2 AS b), + a4 AS + (SELECT 1 AS n FROM a3 AS a, a3 AS b), + numbers AS + ( + SELECT TOP(LEN(@sort_order)) + ROW_NUMBER() OVER + ( + ORDER BY (SELECT NULL) + ) AS number + FROM a4 + ORDER BY + number + ), + tokens AS + ( + SELECT + '|[' + + SUBSTRING + ( + @sort_order, + number + 1, + CHARINDEX(']', @sort_order, number) - number - 1 + ) + '|]' AS token, + SUBSTRING + ( + @sort_order, + CHARINDEX(']', @sort_order, number) + 1, + COALESCE(NULLIF(CHARINDEX('[', @sort_order, CHARINDEX(']', @sort_order, number)), 0), LEN(@sort_order)) - CHARINDEX(']', @sort_order, number) + ) AS next_chunk, + number + FROM numbers + WHERE + SUBSTRING(@sort_order, number, 1) = '[' + ), + ordered_columns AS + ( + SELECT + x.column_name + + CASE + WHEN tokens.next_chunk LIKE '%asc%' THEN ' ASC' + WHEN tokens.next_chunk LIKE '%desc%' THEN ' DESC' + ELSE '' + END AS column_name, + ROW_NUMBER() OVER + ( + PARTITION BY + x.column_name + ORDER BY + tokens.number + ) AS r, + tokens.number + FROM tokens + JOIN + ( + SELECT '[session_id]' AS column_name + UNION ALL + SELECT '[physical_io]' + UNION ALL + SELECT '[reads]' + UNION ALL + SELECT '[physical_reads]' + UNION ALL + SELECT '[writes]' + UNION ALL + SELECT '[tempdb_allocations]' + UNION ALL + SELECT '[tempdb_current]' + UNION ALL + SELECT '[CPU]' + UNION ALL + SELECT '[context_switches]' + UNION ALL + SELECT '[used_memory]' + UNION ALL + SELECT '[physical_io_delta]' + UNION ALL + SELECT '[reads_delta]' + UNION ALL + SELECT '[physical_reads_delta]' + UNION ALL + SELECT '[writes_delta]' + UNION ALL + SELECT '[tempdb_allocations_delta]' + UNION ALL + SELECT '[tempdb_current_delta]' + UNION ALL + SELECT '[CPU_delta]' + UNION ALL + SELECT '[context_switches_delta]' + UNION ALL + SELECT '[used_memory_delta]' + UNION ALL + SELECT '[tasks]' + UNION ALL + SELECT '[tran_start_time]' + UNION ALL + SELECT '[open_tran_count]' + UNION ALL + SELECT '[blocking_session_id]' + UNION ALL + SELECT '[blocked_session_count]' + UNION ALL + SELECT '[percent_complete]' + UNION ALL + SELECT '[host_name]' + UNION ALL + SELECT '[login_name]' + UNION ALL + SELECT '[database_name]' + UNION ALL + SELECT '[start_time]' + UNION ALL + SELECT '[login_time]' + ) AS x ON + x.column_name LIKE token ESCAPE '|' + ) + SELECT + @sort_order = COALESCE(z.sort_order, '') + FROM + ( + SELECT + STUFF + ( + ( + SELECT + ',' + column_name as [text()] + FROM ordered_columns + WHERE + r = 1 + ORDER BY + number + FOR XML + PATH('') + ), + 1, + 1, + '' + ) AS sort_order + ) AS z; + + IF OBJECT_ID('tempdb..#sessions','U') IS NOT NULL + DROP TABLE #sessions; + + CREATE TABLE #sessions + ( + recursion SMALLINT NOT NULL, + session_id SMALLINT NOT NULL, + request_id INT NOT NULL, + session_number INT NOT NULL, + elapsed_time INT NOT NULL, + avg_elapsed_time INT NULL, + physical_io BIGINT NULL, + reads BIGINT NULL, + physical_reads BIGINT NULL, + writes BIGINT NULL, + tempdb_allocations BIGINT NULL, + tempdb_current BIGINT NULL, + CPU INT NULL, + thread_CPU_snapshot BIGINT NULL, + context_switches BIGINT NULL, + used_memory BIGINT NOT NULL, + tasks SMALLINT NULL, + status VARCHAR(30) NOT NULL, + wait_info NVARCHAR(4000) NULL, + locks XML NULL, + transaction_id BIGINT NULL, + tran_start_time DATETIME NULL, + tran_log_writes NVARCHAR(4000) NULL, + open_tran_count SMALLINT NULL, + sql_command XML NULL, + sql_handle VARBINARY(64) NULL, + statement_start_offset INT NULL, + statement_end_offset INT NULL, + sql_text XML NULL, + plan_handle VARBINARY(64) NULL, + query_plan XML NULL, + blocking_session_id SMALLINT NULL, + blocked_session_count SMALLINT NULL, + percent_complete REAL NULL, + host_name sysname NULL, + login_name sysname NOT NULL, + database_name sysname NULL, + program_name sysname NULL, + additional_info XML NULL, + start_time DATETIME NOT NULL, + login_time DATETIME NULL, + last_request_start_time DATETIME NULL, + PRIMARY KEY CLUSTERED (session_id, request_id, recursion) WITH (IGNORE_DUP_KEY = ON), + UNIQUE NONCLUSTERED (transaction_id, session_id, request_id, recursion) WITH (IGNORE_DUP_KEY = ON) + ); + + IF @return_schema = 0 + BEGIN; + --Disable unnecessary autostats on the table + CREATE STATISTICS s_session_id ON #sessions (session_id) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_request_id ON #sessions (request_id) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_transaction_id ON #sessions (transaction_id) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_session_number ON #sessions (session_number) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_status ON #sessions (status) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_start_time ON #sessions (start_time) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_last_request_start_time ON #sessions (last_request_start_time) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_recursion ON #sessions (recursion) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + + DECLARE @recursion SMALLINT; + SET @recursion = + CASE @delta_interval + WHEN 0 THEN 1 + ELSE -1 + END; + + DECLARE @first_collection_ms_ticks BIGINT; + DECLARE @last_collection_start DATETIME; + + --Used for the delta pull + REDO:; + + IF + @get_locks = 1 + AND @recursion = 1 + AND @output_column_list LIKE '%|[locks|]%' ESCAPE '|' + BEGIN; + SELECT + y.resource_type, + y.database_name, + y.object_id, + y.file_id, + y.page_type, + y.hobt_id, + y.allocation_unit_id, + y.index_id, + y.schema_id, + y.principal_id, + y.request_mode, + y.request_status, + y.session_id, + y.resource_description, + y.request_count, + s.request_id, + s.start_time, + CONVERT(sysname, NULL) AS object_name, + CONVERT(sysname, NULL) AS index_name, + CONVERT(sysname, NULL) AS schema_name, + CONVERT(sysname, NULL) AS principal_name, + CONVERT(NVARCHAR(2048), NULL) AS query_error + INTO #locks + FROM + ( + SELECT + sp.spid AS session_id, + CASE sp.status + WHEN 'sleeping' THEN CONVERT(INT, 0) + ELSE sp.request_id + END AS request_id, + CASE sp.status + WHEN 'sleeping' THEN sp.last_batch + ELSE COALESCE(req.start_time, sp.last_batch) + END AS start_time, + sp.dbid + FROM sys.sysprocesses AS sp + OUTER APPLY + ( + SELECT TOP(1) + CASE + WHEN + ( + sp.hostprocess > '' + OR r.total_elapsed_time < 0 + ) THEN + r.start_time + ELSE + DATEADD + ( + ms, + 1000 * (DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())) / 500) - DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())), + DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE()) + ) + END AS start_time + FROM sys.dm_exec_requests AS r + WHERE + r.session_id = sp.spid + AND r.request_id = sp.request_id + ) AS req + WHERE + --Process inclusive filter + 1 = + CASE + WHEN @filter <> '' THEN + CASE @filter_type + WHEN 'session' THEN + CASE + WHEN + CONVERT(SMALLINT, @filter) = 0 + OR sp.spid = CONVERT(SMALLINT, @filter) + THEN 1 + ELSE 0 + END + WHEN 'program' THEN + CASE + WHEN sp.program_name LIKE @filter THEN 1 + ELSE 0 + END + WHEN 'login' THEN + CASE + WHEN sp.loginame LIKE @filter THEN 1 + ELSE 0 + END + WHEN 'host' THEN + CASE + WHEN sp.hostname LIKE @filter THEN 1 + ELSE 0 + END + WHEN 'database' THEN + CASE + WHEN DB_NAME(sp.dbid) LIKE @filter THEN 1 + ELSE 0 + END + ELSE 0 + END + ELSE 1 + END + --Process exclusive filter + AND 0 = + CASE + WHEN @not_filter <> '' THEN + CASE @not_filter_type + WHEN 'session' THEN + CASE + WHEN sp.spid = CONVERT(SMALLINT, @not_filter) THEN 1 + ELSE 0 + END + WHEN 'program' THEN + CASE + WHEN sp.program_name LIKE @not_filter THEN 1 + ELSE 0 + END + WHEN 'login' THEN + CASE + WHEN sp.loginame LIKE @not_filter THEN 1 + ELSE 0 + END + WHEN 'host' THEN + CASE + WHEN sp.hostname LIKE @not_filter THEN 1 + ELSE 0 + END + WHEN 'database' THEN + CASE + WHEN DB_NAME(sp.dbid) LIKE @not_filter THEN 1 + ELSE 0 + END + ELSE 0 + END + ELSE 0 + END + AND + ( + @show_own_spid = 1 + OR sp.spid <> @@SPID + ) + AND + ( + @show_system_spids = 1 + OR sp.hostprocess > '' + ) + AND sp.ecid = 0 + ) AS s + INNER HASH JOIN + ( + SELECT + x.resource_type, + x.database_name, + x.object_id, + x.file_id, + CASE + WHEN x.page_no = 1 OR x.page_no % 8088 = 0 THEN 'PFS' + WHEN x.page_no = 2 OR x.page_no % 511232 = 0 THEN 'GAM' + WHEN x.page_no = 3 OR (x.page_no - 1) % 511232 = 0 THEN 'SGAM' + WHEN x.page_no = 6 OR (x.page_no - 6) % 511232 = 0 THEN 'DCM' + WHEN x.page_no = 7 OR (x.page_no - 7) % 511232 = 0 THEN 'BCM' + WHEN x.page_no IS NOT NULL THEN '*' + ELSE NULL + END AS page_type, + x.hobt_id, + x.allocation_unit_id, + x.index_id, + x.schema_id, + x.principal_id, + x.request_mode, + x.request_status, + x.session_id, + x.request_id, + CASE + WHEN COALESCE(x.object_id, x.file_id, x.hobt_id, x.allocation_unit_id, x.index_id, x.schema_id, x.principal_id) IS NULL THEN NULLIF(resource_description, '') + ELSE NULL + END AS resource_description, + COUNT(*) AS request_count + FROM + ( + SELECT + tl.resource_type + + CASE + WHEN tl.resource_subtype = '' THEN '' + ELSE '.' + tl.resource_subtype + END AS resource_type, + COALESCE(DB_NAME(tl.resource_database_id), N'(null)') AS database_name, + CONVERT + ( + INT, + CASE + WHEN tl.resource_type = 'OBJECT' THEN tl.resource_associated_entity_id + WHEN tl.resource_description LIKE '%object_id = %' THEN + ( + SUBSTRING + ( + tl.resource_description, + (CHARINDEX('object_id = ', tl.resource_description) + 12), + COALESCE + ( + NULLIF + ( + CHARINDEX(',', tl.resource_description, CHARINDEX('object_id = ', tl.resource_description) + 12), + 0 + ), + DATALENGTH(tl.resource_description)+1 + ) - (CHARINDEX('object_id = ', tl.resource_description) + 12) + ) + ) + ELSE NULL + END + ) AS object_id, + CONVERT + ( + INT, + CASE + WHEN tl.resource_type = 'FILE' THEN CONVERT(INT, tl.resource_description) + WHEN tl.resource_type IN ('PAGE', 'EXTENT', 'RID') THEN LEFT(tl.resource_description, CHARINDEX(':', tl.resource_description)-1) + ELSE NULL + END + ) AS file_id, + CONVERT + ( + INT, + CASE + WHEN tl.resource_type IN ('PAGE', 'EXTENT', 'RID') THEN + SUBSTRING + ( + tl.resource_description, + CHARINDEX(':', tl.resource_description) + 1, + COALESCE + ( + NULLIF + ( + CHARINDEX(':', tl.resource_description, CHARINDEX(':', tl.resource_description) + 1), + 0 + ), + DATALENGTH(tl.resource_description)+1 + ) - (CHARINDEX(':', tl.resource_description) + 1) + ) + ELSE NULL + END + ) AS page_no, + CASE + WHEN tl.resource_type IN ('PAGE', 'KEY', 'RID', 'HOBT') THEN tl.resource_associated_entity_id + ELSE NULL + END AS hobt_id, + CASE + WHEN tl.resource_type = 'ALLOCATION_UNIT' THEN tl.resource_associated_entity_id + ELSE NULL + END AS allocation_unit_id, + CONVERT + ( + INT, + CASE + WHEN + /*TODO: Deal with server principals*/ + tl.resource_subtype <> 'SERVER_PRINCIPAL' + AND tl.resource_description LIKE '%index_id or stats_id = %' THEN + ( + SUBSTRING + ( + tl.resource_description, + (CHARINDEX('index_id or stats_id = ', tl.resource_description) + 23), + COALESCE + ( + NULLIF + ( + CHARINDEX(',', tl.resource_description, CHARINDEX('index_id or stats_id = ', tl.resource_description) + 23), + 0 + ), + DATALENGTH(tl.resource_description)+1 + ) - (CHARINDEX('index_id or stats_id = ', tl.resource_description) + 23) + ) + ) + ELSE NULL + END + ) AS index_id, + CONVERT + ( + INT, + CASE + WHEN tl.resource_description LIKE '%schema_id = %' THEN + ( + SUBSTRING + ( + tl.resource_description, + (CHARINDEX('schema_id = ', tl.resource_description) + 12), + COALESCE + ( + NULLIF + ( + CHARINDEX(',', tl.resource_description, CHARINDEX('schema_id = ', tl.resource_description) + 12), + 0 + ), + DATALENGTH(tl.resource_description)+1 + ) - (CHARINDEX('schema_id = ', tl.resource_description) + 12) + ) + ) + ELSE NULL + END + ) AS schema_id, + CONVERT + ( + INT, + CASE + WHEN tl.resource_description LIKE '%principal_id = %' THEN + ( + SUBSTRING + ( + tl.resource_description, + (CHARINDEX('principal_id = ', tl.resource_description) + 15), + COALESCE + ( + NULLIF + ( + CHARINDEX(',', tl.resource_description, CHARINDEX('principal_id = ', tl.resource_description) + 15), + 0 + ), + DATALENGTH(tl.resource_description)+1 + ) - (CHARINDEX('principal_id = ', tl.resource_description) + 15) + ) + ) + ELSE NULL + END + ) AS principal_id, + tl.request_mode, + tl.request_status, + tl.request_session_id AS session_id, + tl.request_request_id AS request_id, + + /*TODO: Applocks, other resource_descriptions*/ + RTRIM(tl.resource_description) AS resource_description, + tl.resource_associated_entity_id + /*********************************************/ + FROM + ( + SELECT + request_session_id, + CONVERT(VARCHAR(120), resource_type) COLLATE Latin1_General_Bin2 AS resource_type, + CONVERT(VARCHAR(120), resource_subtype) COLLATE Latin1_General_Bin2 AS resource_subtype, + resource_database_id, + CONVERT(VARCHAR(512), resource_description) COLLATE Latin1_General_Bin2 AS resource_description, + resource_associated_entity_id, + CONVERT(VARCHAR(120), request_mode) COLLATE Latin1_General_Bin2 AS request_mode, + CONVERT(VARCHAR(120), request_status) COLLATE Latin1_General_Bin2 AS request_status, + request_request_id + FROM sys.dm_tran_locks + ) AS tl + ) AS x + GROUP BY + x.resource_type, + x.database_name, + x.object_id, + x.file_id, + CASE + WHEN x.page_no = 1 OR x.page_no % 8088 = 0 THEN 'PFS' + WHEN x.page_no = 2 OR x.page_no % 511232 = 0 THEN 'GAM' + WHEN x.page_no = 3 OR (x.page_no - 1) % 511232 = 0 THEN 'SGAM' + WHEN x.page_no = 6 OR (x.page_no - 6) % 511232 = 0 THEN 'DCM' + WHEN x.page_no = 7 OR (x.page_no - 7) % 511232 = 0 THEN 'BCM' + WHEN x.page_no IS NOT NULL THEN '*' + ELSE NULL + END, + x.hobt_id, + x.allocation_unit_id, + x.index_id, + x.schema_id, + x.principal_id, + x.request_mode, + x.request_status, + x.session_id, + x.request_id, + CASE + WHEN COALESCE(x.object_id, x.file_id, x.hobt_id, x.allocation_unit_id, x.index_id, x.schema_id, x.principal_id) IS NULL THEN NULLIF(resource_description, '') + ELSE NULL + END + ) AS y ON + y.session_id = s.session_id + AND y.request_id = s.request_id + OPTION (HASH GROUP); + + --Disable unnecessary autostats on the table + CREATE STATISTICS s_database_name ON #locks (database_name) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_object_id ON #locks (object_id) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_hobt_id ON #locks (hobt_id) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_allocation_unit_id ON #locks (allocation_unit_id) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_index_id ON #locks (index_id) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_schema_id ON #locks (schema_id) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_principal_id ON #locks (principal_id) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_request_id ON #locks (request_id) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_start_time ON #locks (start_time) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_resource_type ON #locks (resource_type) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_object_name ON #locks (object_name) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_schema_name ON #locks (schema_name) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_page_type ON #locks (page_type) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_request_mode ON #locks (request_mode) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_request_status ON #locks (request_status) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_resource_description ON #locks (resource_description) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_index_name ON #locks (index_name) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_principal_name ON #locks (principal_name) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + END; + + DECLARE + @sql VARCHAR(MAX), + @sql_n NVARCHAR(MAX); + + SET @sql = + CONVERT(VARCHAR(MAX), '') + + 'DECLARE @blocker BIT; + SET @blocker = 0; + DECLARE @i INT; + SET @i = 2147483647; + + DECLARE @sessions TABLE + ( + session_id SMALLINT NOT NULL, + request_id INT NOT NULL, + login_time DATETIME, + last_request_end_time DATETIME, + status VARCHAR(30), + statement_start_offset INT, + statement_end_offset INT, + sql_handle BINARY(20), + host_name NVARCHAR(128), + login_name NVARCHAR(128), + program_name NVARCHAR(128), + database_id SMALLINT, + memory_usage INT, + open_tran_count SMALLINT, + ' + + CASE + WHEN + ( + @get_task_info <> 0 + OR @find_block_leaders = 1 + ) THEN + 'wait_type NVARCHAR(32), + wait_resource NVARCHAR(256), + wait_time BIGINT, + ' + ELSE + '' + END + + 'blocked SMALLINT, + is_user_process BIT, + cmd VARCHAR(32), + PRIMARY KEY CLUSTERED (session_id, request_id) WITH (IGNORE_DUP_KEY = ON) + ); + + DECLARE @blockers TABLE + ( + session_id INT NOT NULL PRIMARY KEY WITH (IGNORE_DUP_KEY = ON) + ); + + BLOCKERS:; + + INSERT @sessions + ( + session_id, + request_id, + login_time, + last_request_end_time, + status, + statement_start_offset, + statement_end_offset, + sql_handle, + host_name, + login_name, + program_name, + database_id, + memory_usage, + open_tran_count, + ' + + CASE + WHEN + ( + @get_task_info <> 0 + OR @find_block_leaders = 1 + ) THEN + 'wait_type, + wait_resource, + wait_time, + ' + ELSE + '' + END + + 'blocked, + is_user_process, + cmd + ) + SELECT TOP(@i) + spy.session_id, + spy.request_id, + spy.login_time, + spy.last_request_end_time, + spy.status, + spy.statement_start_offset, + spy.statement_end_offset, + spy.sql_handle, + spy.host_name, + spy.login_name, + spy.program_name, + spy.database_id, + spy.memory_usage, + spy.open_tran_count, + ' + + CASE + WHEN + ( + @get_task_info <> 0 + OR @find_block_leaders = 1 + ) THEN + 'spy.wait_type, + CASE + WHEN + spy.wait_type LIKE N''PAGE%LATCH_%'' + OR spy.wait_type = N''CXPACKET'' + OR spy.wait_type LIKE N''LATCH[_]%'' + OR spy.wait_type = N''OLEDB'' THEN + spy.wait_resource + ELSE + NULL + END AS wait_resource, + spy.wait_time, + ' + ELSE + '' + END + + 'spy.blocked, + spy.is_user_process, + spy.cmd + FROM + ( + SELECT TOP(@i) + spx.*, + ' + + CASE + WHEN + ( + @get_task_info <> 0 + OR @find_block_leaders = 1 + ) THEN + 'ROW_NUMBER() OVER + ( + PARTITION BY + spx.session_id, + spx.request_id + ORDER BY + CASE + WHEN spx.wait_type LIKE N''LCK[_]%'' THEN + 1 + ELSE + 99 + END, + spx.wait_time DESC, + spx.blocked DESC + ) AS r + ' + ELSE + '1 AS r + ' + END + + 'FROM + ( + SELECT TOP(@i) + sp0.session_id, + sp0.request_id, + sp0.login_time, + sp0.last_request_end_time, + LOWER(sp0.status) AS status, + CASE + WHEN sp0.cmd = ''CREATE INDEX'' THEN + 0 + ELSE + sp0.stmt_start + END AS statement_start_offset, + CASE + WHEN sp0.cmd = N''CREATE INDEX'' THEN + -1 + ELSE + COALESCE(NULLIF(sp0.stmt_end, 0), -1) + END AS statement_end_offset, + sp0.sql_handle, + sp0.host_name, + sp0.login_name, + sp0.program_name, + sp0.database_id, + sp0.memory_usage, + sp0.open_tran_count, + ' + + CASE + WHEN + ( + @get_task_info <> 0 + OR @find_block_leaders = 1 + ) THEN + 'CASE + WHEN sp0.wait_time > 0 AND sp0.wait_type <> N''CXPACKET'' THEN + sp0.wait_type + ELSE + NULL + END AS wait_type, + CASE + WHEN sp0.wait_time > 0 AND sp0.wait_type <> N''CXPACKET'' THEN + sp0.wait_resource + ELSE + NULL + END AS wait_resource, + CASE + WHEN sp0.wait_type <> N''CXPACKET'' THEN + sp0.wait_time + ELSE + 0 + END AS wait_time, + ' + ELSE + '' + END + + 'sp0.blocked, + sp0.is_user_process, + sp0.cmd + FROM + ( + SELECT TOP(@i) + sp1.session_id, + sp1.request_id, + sp1.login_time, + sp1.last_request_end_time, + sp1.status, + sp1.cmd, + sp1.stmt_start, + sp1.stmt_end, + MAX(NULLIF(sp1.sql_handle, 0x00)) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS sql_handle, + sp1.host_name, + MAX(sp1.login_name) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS login_name, + sp1.program_name, + sp1.database_id, + MAX(sp1.memory_usage) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS memory_usage, + MAX(sp1.open_tran_count) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS open_tran_count, + sp1.wait_type, + sp1.wait_resource, + sp1.wait_time, + sp1.blocked, + sp1.hostprocess, + sp1.is_user_process + FROM + ( + SELECT TOP(@i) + sp2.spid AS session_id, + CASE sp2.status + WHEN ''sleeping'' THEN + CONVERT(INT, 0) + ELSE + sp2.request_id + END AS request_id, + MAX(sp2.login_time) AS login_time, + MAX(sp2.last_batch) AS last_request_end_time, + MAX(CONVERT(VARCHAR(30), RTRIM(sp2.status)) COLLATE Latin1_General_Bin2) AS status, + MAX(CONVERT(VARCHAR(32), RTRIM(sp2.cmd)) COLLATE Latin1_General_Bin2) AS cmd, + MAX(sp2.stmt_start) AS stmt_start, + MAX(sp2.stmt_end) AS stmt_end, + MAX(sp2.sql_handle) AS sql_handle, + MAX(CONVERT(sysname, RTRIM(sp2.hostname)) COLLATE SQL_Latin1_General_CP1_CI_AS) AS host_name, + MAX(CONVERT(sysname, RTRIM(sp2.loginame)) COLLATE SQL_Latin1_General_CP1_CI_AS) AS login_name, + MAX + ( + CASE + WHEN blk.queue_id IS NOT NULL THEN + N''Service Broker + database_id: '' + CONVERT(NVARCHAR, blk.database_id) + + N'' queue_id: '' + CONVERT(NVARCHAR, blk.queue_id) + ELSE + CONVERT + ( + sysname, + RTRIM(sp2.program_name) + ) + END COLLATE SQL_Latin1_General_CP1_CI_AS + ) AS program_name, + MAX(sp2.dbid) AS database_id, + MAX(sp2.memusage) AS memory_usage, + MAX(sp2.open_tran) AS open_tran_count, + RTRIM(sp2.lastwaittype) AS wait_type, + RTRIM(sp2.waitresource) AS wait_resource, + MAX(sp2.waittime) AS wait_time, + COALESCE(NULLIF(sp2.blocked, sp2.spid), 0) AS blocked, + MAX + ( + CASE + WHEN blk.session_id = sp2.spid THEN + ''blocker'' + ELSE + RTRIM(sp2.hostprocess) + END + ) AS hostprocess, + CONVERT + ( + BIT, + MAX + ( + CASE + WHEN sp2.hostprocess > '''' THEN + 1 + ELSE + 0 + END + ) + ) AS is_user_process + FROM + ( + SELECT TOP(@i) + session_id, + CONVERT(INT, NULL) AS queue_id, + CONVERT(INT, NULL) AS database_id + FROM @blockers + + UNION ALL + + SELECT TOP(@i) + CONVERT(SMALLINT, 0), + CONVERT(INT, NULL) AS queue_id, + CONVERT(INT, NULL) AS database_id + WHERE + @blocker = 0 + + UNION ALL + + SELECT TOP(@i) + CONVERT(SMALLINT, spid), + queue_id, + database_id + FROM sys.dm_broker_activated_tasks + WHERE + @blocker = 0 + ) AS blk + INNER JOIN sys.sysprocesses AS sp2 ON + sp2.spid = blk.session_id + OR + ( + blk.session_id = 0 + AND @blocker = 0 + ) + ' + + CASE + WHEN + ( + @get_task_info = 0 + AND @find_block_leaders = 0 + ) THEN + 'WHERE + sp2.ecid = 0 + ' + ELSE + '' + END + + 'GROUP BY + sp2.spid, + CASE sp2.status + WHEN ''sleeping'' THEN + CONVERT(INT, 0) + ELSE + sp2.request_id + END, + RTRIM(sp2.lastwaittype), + RTRIM(sp2.waitresource), + COALESCE(NULLIF(sp2.blocked, sp2.spid), 0) + ) AS sp1 + ) AS sp0 + WHERE + @blocker = 1 + OR + (1=1 + ' + + --inclusive filter + CASE + WHEN @filter <> '' THEN + CASE @filter_type + WHEN 'session' THEN + CASE + WHEN CONVERT(SMALLINT, @filter) <> 0 THEN + 'AND sp0.session_id = CONVERT(SMALLINT, @filter) + ' + ELSE + '' + END + WHEN 'program' THEN + 'AND sp0.program_name LIKE @filter + ' + WHEN 'login' THEN + 'AND sp0.login_name LIKE @filter + ' + WHEN 'host' THEN + 'AND sp0.host_name LIKE @filter + ' + WHEN 'database' THEN + 'AND DB_NAME(sp0.database_id) LIKE @filter + ' + ELSE + '' + END + ELSE + '' + END + + --exclusive filter + CASE + WHEN @not_filter <> '' THEN + CASE @not_filter_type + WHEN 'session' THEN + CASE + WHEN CONVERT(SMALLINT, @not_filter) <> 0 THEN + 'AND sp0.session_id <> CONVERT(SMALLINT, @not_filter) + ' + ELSE + '' + END + WHEN 'program' THEN + 'AND sp0.program_name NOT LIKE @not_filter + ' + WHEN 'login' THEN + 'AND sp0.login_name NOT LIKE @not_filter + ' + WHEN 'host' THEN + 'AND sp0.host_name NOT LIKE @not_filter + ' + WHEN 'database' THEN + 'AND DB_NAME(sp0.database_id) NOT LIKE @not_filter + ' + ELSE + '' + END + ELSE + '' + END + + CASE @show_own_spid + WHEN 1 THEN + '' + ELSE + 'AND sp0.session_id <> @@spid + ' + END + + CASE + WHEN @show_system_spids = 0 THEN + 'AND sp0.hostprocess > '''' + ' + ELSE + '' + END + + CASE @show_sleeping_spids + WHEN 0 THEN + 'AND sp0.status <> ''sleeping'' + ' + WHEN 1 THEN + 'AND + ( + sp0.status <> ''sleeping'' + OR sp0.open_tran_count > 0 + ) + ' + ELSE + '' + END + + ') + ) AS spx + ) AS spy + WHERE + spy.r = 1; + ' + + CASE @recursion + WHEN 1 THEN + 'IF @@ROWCOUNT > 0 + BEGIN; + INSERT @blockers + ( + session_id + ) + SELECT TOP(@i) + blocked + FROM @sessions + WHERE + NULLIF(blocked, 0) IS NOT NULL + + EXCEPT + + SELECT TOP(@i) + session_id + FROM @sessions; + ' + + + CASE + WHEN + ( + @get_task_info > 0 + OR @find_block_leaders = 1 + ) THEN + 'IF @@ROWCOUNT > 0 + BEGIN; + SET @blocker = 1; + GOTO BLOCKERS; + END; + ' + ELSE + '' + END + + 'END; + ' + ELSE + '' + END + + 'SELECT TOP(@i) + @recursion AS recursion, + x.session_id, + x.request_id, + DENSE_RANK() OVER + ( + ORDER BY + x.session_id + ) AS session_number, + ' + + CASE + WHEN @output_column_list LIKE '%|[dd hh:mm:ss.mss|]%' ESCAPE '|' THEN + 'x.elapsed_time ' + ELSE + '0 ' + END + + 'AS elapsed_time, + ' + + CASE + WHEN + ( + @output_column_list LIKE '%|[dd hh:mm:ss.mss (avg)|]%' ESCAPE '|' OR + @output_column_list LIKE '%|[avg_elapsed_time|]%' ESCAPE '|' + ) + AND @recursion = 1 + THEN + 'x.avg_elapsed_time / 1000 ' + ELSE + 'NULL ' + END + + 'AS avg_elapsed_time, + ' + + CASE + WHEN + @output_column_list LIKE '%|[physical_io|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[physical_io_delta|]%' ESCAPE '|' + THEN + 'x.physical_io ' + ELSE + 'NULL ' + END + + 'AS physical_io, + ' + + CASE + WHEN + @output_column_list LIKE '%|[reads|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[reads_delta|]%' ESCAPE '|' + THEN + 'x.reads ' + ELSE + '0 ' + END + + 'AS reads, + ' + + CASE + WHEN + @output_column_list LIKE '%|[physical_reads|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[physical_reads_delta|]%' ESCAPE '|' + THEN + 'x.physical_reads ' + ELSE + '0 ' + END + + 'AS physical_reads, + ' + + CASE + WHEN + @output_column_list LIKE '%|[writes|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[writes_delta|]%' ESCAPE '|' + THEN + 'x.writes ' + ELSE + '0 ' + END + + 'AS writes, + ' + + CASE + WHEN + @output_column_list LIKE '%|[tempdb_allocations|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[tempdb_allocations_delta|]%' ESCAPE '|' + THEN + 'x.tempdb_allocations ' + ELSE + '0 ' + END + + 'AS tempdb_allocations, + ' + + CASE + WHEN + @output_column_list LIKE '%|[tempdb_current|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[tempdb_current_delta|]%' ESCAPE '|' + THEN + 'x.tempdb_current ' + ELSE + '0 ' + END + + 'AS tempdb_current, + ' + + CASE + WHEN + @output_column_list LIKE '%|[CPU|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|' + THEN + 'x.CPU ' + ELSE + '0 ' + END + + 'AS CPU, + ' + + CASE + WHEN + @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|' + AND @get_task_info = 2 + THEN + 'x.thread_CPU_snapshot ' + ELSE + '0 ' + END + + 'AS thread_CPU_snapshot, + ' + + CASE + WHEN + @output_column_list LIKE '%|[context_switches|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[context_switches_delta|]%' ESCAPE '|' + THEN + 'x.context_switches ' + ELSE + 'NULL ' + END + + 'AS context_switches, + ' + + CASE + WHEN + @output_column_list LIKE '%|[used_memory|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[used_memory_delta|]%' ESCAPE '|' + THEN + 'x.used_memory ' + ELSE + '0 ' + END + + 'AS used_memory, + ' + + CASE + WHEN + @output_column_list LIKE '%|[tasks|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'x.tasks ' + ELSE + 'NULL ' + END + + 'AS tasks, + ' + + CASE + WHEN + ( + @output_column_list LIKE '%|[status|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[sql_command|]%' ESCAPE '|' + ) + AND @recursion = 1 + THEN + 'x.status ' + ELSE + ''''' ' + END + + 'AS status, + ' + + CASE + WHEN + @output_column_list LIKE '%|[wait_info|]%' ESCAPE '|' + AND @recursion = 1 + THEN + CASE @get_task_info + WHEN 2 THEN + 'COALESCE(x.task_wait_info, x.sys_wait_info) ' + ELSE + 'x.sys_wait_info ' + END + ELSE + 'NULL ' + END + + 'AS wait_info, + ' + + CASE + WHEN + ( + @output_column_list LIKE '%|[tran_start_time|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[tran_log_writes|]%' ESCAPE '|' + ) + AND @recursion = 1 + THEN + 'x.transaction_id ' + ELSE + 'NULL ' + END + + 'AS transaction_id, + ' + + CASE + WHEN + @output_column_list LIKE '%|[open_tran_count|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'x.open_tran_count ' + ELSE + 'NULL ' + END + + 'AS open_tran_count, + ' + + CASE + WHEN + @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'x.sql_handle ' + ELSE + 'NULL ' + END + + 'AS sql_handle, + ' + + CASE + WHEN + ( + @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|' + ) + AND @recursion = 1 + THEN + 'x.statement_start_offset ' + ELSE + 'NULL ' + END + + 'AS statement_start_offset, + ' + + CASE + WHEN + ( + @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|' + ) + AND @recursion = 1 + THEN + 'x.statement_end_offset ' + ELSE + 'NULL ' + END + + 'AS statement_end_offset, + ' + + 'NULL AS sql_text, + ' + + CASE + WHEN + @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'x.plan_handle ' + ELSE + 'NULL ' + END + + 'AS plan_handle, + ' + + CASE + WHEN + @output_column_list LIKE '%|[blocking_session_id|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'NULLIF(x.blocking_session_id, 0) ' + ELSE + 'NULL ' + END + + 'AS blocking_session_id, + ' + + CASE + WHEN + @output_column_list LIKE '%|[percent_complete|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'x.percent_complete ' + ELSE + 'NULL ' + END + + 'AS percent_complete, + ' + + CASE + WHEN + @output_column_list LIKE '%|[host_name|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'x.host_name ' + ELSE + ''''' ' + END + + 'AS host_name, + ' + + CASE + WHEN + @output_column_list LIKE '%|[login_name|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'x.login_name ' + ELSE + ''''' ' + END + + 'AS login_name, + ' + + CASE + WHEN + @output_column_list LIKE '%|[database_name|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'DB_NAME(x.database_id) ' + ELSE + 'NULL ' + END + + 'AS database_name, + ' + + CASE + WHEN + @output_column_list LIKE '%|[program_name|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'x.program_name ' + ELSE + ''''' ' + END + + 'AS program_name, + ' + + CASE + WHEN + @output_column_list LIKE '%|[additional_info|]%' ESCAPE '|' + AND @recursion = 1 + THEN + '( + SELECT TOP(@i) + x.text_size, + x.language, + x.date_format, + x.date_first, + CASE x.quoted_identifier + WHEN 0 THEN ''OFF'' + WHEN 1 THEN ''ON'' + END AS quoted_identifier, + CASE x.arithabort + WHEN 0 THEN ''OFF'' + WHEN 1 THEN ''ON'' + END AS arithabort, + CASE x.ansi_null_dflt_on + WHEN 0 THEN ''OFF'' + WHEN 1 THEN ''ON'' + END AS ansi_null_dflt_on, + CASE x.ansi_defaults + WHEN 0 THEN ''OFF'' + WHEN 1 THEN ''ON'' + END AS ansi_defaults, + CASE x.ansi_warnings + WHEN 0 THEN ''OFF'' + WHEN 1 THEN ''ON'' + END AS ansi_warnings, + CASE x.ansi_padding + WHEN 0 THEN ''OFF'' + WHEN 1 THEN ''ON'' + END AS ansi_padding, + CASE ansi_nulls + WHEN 0 THEN ''OFF'' + WHEN 1 THEN ''ON'' + END AS ansi_nulls, + CASE x.concat_null_yields_null + WHEN 0 THEN ''OFF'' + WHEN 1 THEN ''ON'' + END AS concat_null_yields_null, + CASE x.transaction_isolation_level + WHEN 0 THEN ''Unspecified'' + WHEN 1 THEN ''ReadUncomitted'' + WHEN 2 THEN ''ReadCommitted'' + WHEN 3 THEN ''Repeatable'' + WHEN 4 THEN ''Serializable'' + WHEN 5 THEN ''Snapshot'' + END AS transaction_isolation_level, + x.lock_timeout, + x.deadlock_priority, + x.row_count, + x.command_type, + master.dbo.fn_varbintohexstr(x.sql_handle) AS sql_handle, + master.dbo.fn_varbintohexstr(x.plan_handle) AS plan_handle, + ' + + CASE + WHEN @output_column_list LIKE '%|[program_name|]%' ESCAPE '|' THEN + '( + SELECT TOP(1) + CONVERT(uniqueidentifier, CONVERT(XML, '''').value(''xs:hexBinary( substring(sql:column("agent_info.job_id_string"), 0) )'', ''binary(16)'')) AS job_id, + agent_info.step_id, + ( + SELECT TOP(1) + NULL + FOR XML + PATH(''job_name''), + TYPE + ), + ( + SELECT TOP(1) + NULL + FOR XML + PATH(''step_name''), + TYPE + ) + FROM + ( + SELECT TOP(1) + SUBSTRING(x.program_name, CHARINDEX(''0x'', x.program_name) + 2, 32) AS job_id_string, + SUBSTRING(x.program_name, CHARINDEX('': Step '', x.program_name) + 7, CHARINDEX('')'', x.program_name, CHARINDEX('': Step '', x.program_name)) - (CHARINDEX('': Step '', x.program_name) + 7)) AS step_id + WHERE + x.program_name LIKE N''SQLAgent - TSQL JobStep (Job 0x%'' + ) AS agent_info + FOR XML + PATH(''agent_job_info''), + TYPE + ), + ' + ELSE '' + END + + CASE + WHEN @get_task_info = 2 THEN + 'CONVERT(XML, x.block_info) AS block_info, + ' + ELSE + '' + END + + 'x.host_process_id + FOR XML + PATH(''additional_info''), + TYPE + ) ' + ELSE + 'NULL ' + END + + 'AS additional_info, + x.start_time, + ' + + CASE + WHEN + @output_column_list LIKE '%|[login_time|]%' ESCAPE '|' + AND @recursion = 1 + THEN + 'x.login_time ' + ELSE + 'NULL ' + END + + 'AS login_time, + x.last_request_start_time + FROM + ( + SELECT TOP(@i) + y.*, + CASE + WHEN DATEDIFF(hour, y.start_time, GETDATE()) > 576 THEN + DATEDIFF(second, GETDATE(), y.start_time) + ELSE DATEDIFF(ms, y.start_time, GETDATE()) + END AS elapsed_time, + COALESCE(tempdb_info.tempdb_allocations, 0) AS tempdb_allocations, + COALESCE + ( + CASE + WHEN tempdb_info.tempdb_current < 0 THEN 0 + ELSE tempdb_info.tempdb_current + END, + 0 + ) AS tempdb_current, + ' + + CASE + WHEN + ( + @get_task_info <> 0 + OR @find_block_leaders = 1 + ) THEN + 'N''('' + CONVERT(NVARCHAR, y.wait_duration_ms) + N''ms)'' + + y.wait_type + + CASE + WHEN y.wait_type LIKE N''PAGE%LATCH_%'' THEN + N'':'' + + COALESCE(DB_NAME(CONVERT(INT, LEFT(y.resource_description, CHARINDEX(N'':'', y.resource_description) - 1))), N''(null)'') + + N'':'' + + SUBSTRING(y.resource_description, CHARINDEX(N'':'', y.resource_description) + 1, LEN(y.resource_description) - CHARINDEX(N'':'', REVERSE(y.resource_description)) - CHARINDEX(N'':'', y.resource_description)) + + N''('' + + CASE + WHEN + CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 1 OR + CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) % 8088 = 0 + THEN + N''PFS'' + WHEN + CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 2 OR + CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) % 511232 = 0 + THEN + N''GAM'' + WHEN + CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 3 OR + (CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) - 1) % 511232 = 0 + THEN + N''SGAM'' + WHEN + CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 6 OR + (CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) - 6) % 511232 = 0 + THEN + N''DCM'' + WHEN + CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 7 OR + (CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) - 7) % 511232 = 0 + THEN + N''BCM'' + ELSE + N''*'' + END + + N'')'' + WHEN y.wait_type = N''CXPACKET'' THEN + N'':'' + SUBSTRING(y.resource_description, CHARINDEX(N''nodeId'', y.resource_description) + 7, 4) + WHEN y.wait_type LIKE N''LATCH[_]%'' THEN + N'' ['' + LEFT(y.resource_description, COALESCE(NULLIF(CHARINDEX(N'' '', y.resource_description), 0), LEN(y.resource_description) + 1) - 1) + N'']'' + WHEN + y.wait_type = N''OLEDB'' + AND y.resource_description LIKE N''%(SPID=%)'' THEN + N''['' + LEFT(y.resource_description, CHARINDEX(N''(SPID='', y.resource_description) - 2) + + N'':'' + SUBSTRING(y.resource_description, CHARINDEX(N''(SPID='', y.resource_description) + 6, CHARINDEX(N'')'', y.resource_description, (CHARINDEX(N''(SPID='', y.resource_description) + 6)) - (CHARINDEX(N''(SPID='', y.resource_description) + 6)) + '']'' + ELSE + N'''' + END COLLATE Latin1_General_Bin2 AS sys_wait_info, + ' + ELSE + '' + END + + CASE + WHEN @get_task_info = 2 THEN + 'tasks.physical_io, + tasks.context_switches, + tasks.tasks, + tasks.block_info, + tasks.wait_info AS task_wait_info, + tasks.thread_CPU_snapshot, + ' + ELSE + '' + END + + CASE + WHEN NOT (@get_avg_time = 1 AND @recursion = 1) THEN + 'CONVERT(INT, NULL) ' + ELSE + 'qs.total_elapsed_time / qs.execution_count ' + END + + 'AS avg_elapsed_time + FROM + ( + SELECT TOP(@i) + sp.session_id, + sp.request_id, + COALESCE(r.logical_reads, s.logical_reads) AS reads, + COALESCE(r.reads, s.reads) AS physical_reads, + COALESCE(r.writes, s.writes) AS writes, + COALESCE(r.CPU_time, s.CPU_time) AS CPU, + sp.memory_usage + COALESCE(r.granted_query_memory, 0) AS used_memory, + LOWER(sp.status) AS status, + COALESCE(r.sql_handle, sp.sql_handle) AS sql_handle, + COALESCE(r.statement_start_offset, sp.statement_start_offset) AS statement_start_offset, + COALESCE(r.statement_end_offset, sp.statement_end_offset) AS statement_end_offset, + ' + + CASE + WHEN + ( + @get_task_info <> 0 + OR @find_block_leaders = 1 + ) THEN + 'sp.wait_type COLLATE Latin1_General_Bin2 AS wait_type, + sp.wait_resource COLLATE Latin1_General_Bin2 AS resource_description, + sp.wait_time AS wait_duration_ms, + ' + ELSE + '' + END + + 'NULLIF(sp.blocked, 0) AS blocking_session_id, + r.plan_handle, + NULLIF(r.percent_complete, 0) AS percent_complete, + sp.host_name, + sp.login_name, + sp.program_name, + s.host_process_id, + COALESCE(r.text_size, s.text_size) AS text_size, + COALESCE(r.language, s.language) AS language, + COALESCE(r.date_format, s.date_format) AS date_format, + COALESCE(r.date_first, s.date_first) AS date_first, + COALESCE(r.quoted_identifier, s.quoted_identifier) AS quoted_identifier, + COALESCE(r.arithabort, s.arithabort) AS arithabort, + COALESCE(r.ansi_null_dflt_on, s.ansi_null_dflt_on) AS ansi_null_dflt_on, + COALESCE(r.ansi_defaults, s.ansi_defaults) AS ansi_defaults, + COALESCE(r.ansi_warnings, s.ansi_warnings) AS ansi_warnings, + COALESCE(r.ansi_padding, s.ansi_padding) AS ansi_padding, + COALESCE(r.ansi_nulls, s.ansi_nulls) AS ansi_nulls, + COALESCE(r.concat_null_yields_null, s.concat_null_yields_null) AS concat_null_yields_null, + COALESCE(r.transaction_isolation_level, s.transaction_isolation_level) AS transaction_isolation_level, + COALESCE(r.lock_timeout, s.lock_timeout) AS lock_timeout, + COALESCE(r.deadlock_priority, s.deadlock_priority) AS deadlock_priority, + COALESCE(r.row_count, s.row_count) AS row_count, + COALESCE(r.command, sp.cmd) AS command_type, + COALESCE + ( + CASE + WHEN + ( + s.is_user_process = 0 + AND r.total_elapsed_time >= 0 + ) THEN + DATEADD + ( + ms, + 1000 * (DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())) / 500) - DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())), + DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE()) + ) + END, + NULLIF(COALESCE(r.start_time, sp.last_request_end_time), CONVERT(DATETIME, ''19000101'', 112)), + ( + SELECT TOP(1) + DATEADD(second, -(ms_ticks / 1000), GETDATE()) + FROM sys.dm_os_sys_info + ) + ) AS start_time, + sp.login_time, + CASE + WHEN s.is_user_process = 1 THEN + s.last_request_start_time + ELSE + COALESCE + ( + DATEADD + ( + ms, + 1000 * (DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())) / 500) - DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())), + DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE()) + ), + s.last_request_start_time + ) + END AS last_request_start_time, + r.transaction_id, + sp.database_id, + sp.open_tran_count + FROM @sessions AS sp + LEFT OUTER LOOP JOIN sys.dm_exec_sessions AS s ON + s.session_id = sp.session_id + AND s.login_time = sp.login_time + LEFT OUTER LOOP JOIN sys.dm_exec_requests AS r ON + sp.status <> ''sleeping'' + AND r.session_id = sp.session_id + AND r.request_id = sp.request_id + AND + ( + ( + s.is_user_process = 0 + AND sp.is_user_process = 0 + ) + OR + ( + r.start_time = s.last_request_start_time + AND s.last_request_end_time <= sp.last_request_end_time + ) + ) + ) AS y + ' + + CASE + WHEN @get_task_info = 2 THEN + CONVERT(VARCHAR(MAX), '') + + 'LEFT OUTER HASH JOIN + ( + SELECT TOP(@i) + task_nodes.task_node.value(''(session_id/text())[1]'', ''SMALLINT'') AS session_id, + task_nodes.task_node.value(''(request_id/text())[1]'', ''INT'') AS request_id, + task_nodes.task_node.value(''(physical_io/text())[1]'', ''BIGINT'') AS physical_io, + task_nodes.task_node.value(''(context_switches/text())[1]'', ''BIGINT'') AS context_switches, + task_nodes.task_node.value(''(tasks/text())[1]'', ''INT'') AS tasks, + task_nodes.task_node.value(''(block_info/text())[1]'', ''NVARCHAR(4000)'') AS block_info, + task_nodes.task_node.value(''(waits/text())[1]'', ''NVARCHAR(4000)'') AS wait_info, + task_nodes.task_node.value(''(thread_CPU_snapshot/text())[1]'', ''BIGINT'') AS thread_CPU_snapshot + FROM + ( + SELECT TOP(@i) + CONVERT + ( + XML, + REPLACE + ( + CONVERT(NVARCHAR(MAX), tasks_raw.task_xml_raw) COLLATE Latin1_General_Bin2, + N'''', + N'', '' + ) + ) AS task_xml + FROM + ( + SELECT TOP(@i) + CASE waits.r + WHEN 1 THEN + waits.session_id + ELSE + NULL + END AS [session_id], + CASE waits.r + WHEN 1 THEN + waits.request_id + ELSE + NULL + END AS [request_id], + CASE waits.r + WHEN 1 THEN + waits.physical_io + ELSE + NULL + END AS [physical_io], + CASE waits.r + WHEN 1 THEN + waits.context_switches + ELSE + NULL + END AS [context_switches], + CASE waits.r + WHEN 1 THEN + waits.thread_CPU_snapshot + ELSE + NULL + END AS [thread_CPU_snapshot], + CASE waits.r + WHEN 1 THEN + waits.tasks + ELSE + NULL + END AS [tasks], + CASE waits.r + WHEN 1 THEN + waits.block_info + ELSE + NULL + END AS [block_info], + REPLACE + ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + CONVERT + ( + NVARCHAR(MAX), + N''('' + + CONVERT(NVARCHAR, num_waits) + N''x: '' + + CASE num_waits + WHEN 1 THEN + CONVERT(NVARCHAR, min_wait_time) + N''ms'' + WHEN 2 THEN + CASE + WHEN min_wait_time <> max_wait_time THEN + CONVERT(NVARCHAR, min_wait_time) + N''/'' + CONVERT(NVARCHAR, max_wait_time) + N''ms'' + ELSE + CONVERT(NVARCHAR, max_wait_time) + N''ms'' + END + ELSE + CASE + WHEN min_wait_time <> max_wait_time THEN + CONVERT(NVARCHAR, min_wait_time) + N''/'' + CONVERT(NVARCHAR, avg_wait_time) + N''/'' + CONVERT(NVARCHAR, max_wait_time) + N''ms'' + ELSE + CONVERT(NVARCHAR, max_wait_time) + N''ms'' + END + END + + N'')'' + wait_type COLLATE Latin1_General_Bin2 + ), + NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), + NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), + NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), + NCHAR(0), + N'''' + ) AS [waits] + FROM + ( + SELECT TOP(@i) + w1.*, + ROW_NUMBER() OVER + ( + PARTITION BY + w1.session_id, + w1.request_id + ORDER BY + w1.block_info DESC, + w1.num_waits DESC, + w1.wait_type + ) AS r + FROM + ( + SELECT TOP(@i) + task_info.session_id, + task_info.request_id, + task_info.physical_io, + task_info.context_switches, + task_info.thread_CPU_snapshot, + task_info.num_tasks AS tasks, + CASE + WHEN task_info.runnable_time IS NOT NULL THEN + ''RUNNABLE'' + ELSE + wt2.wait_type + END AS wait_type, + NULLIF(COUNT(COALESCE(task_info.runnable_time, wt2.waiting_task_address)), 0) AS num_waits, + MIN(COALESCE(task_info.runnable_time, wt2.wait_duration_ms)) AS min_wait_time, + AVG(COALESCE(task_info.runnable_time, wt2.wait_duration_ms)) AS avg_wait_time, + MAX(COALESCE(task_info.runnable_time, wt2.wait_duration_ms)) AS max_wait_time, + MAX(wt2.block_info) AS block_info + FROM + ( + SELECT TOP(@i) + t.session_id, + t.request_id, + SUM(CONVERT(BIGINT, t.pending_io_count)) OVER (PARTITION BY t.session_id, t.request_id) AS physical_io, + SUM(CONVERT(BIGINT, t.context_switches_count)) OVER (PARTITION BY t.session_id, t.request_id) AS context_switches, + ' + + CASE + WHEN @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|' + THEN + 'SUM(tr.usermode_time + tr.kernel_time) OVER (PARTITION BY t.session_id, t.request_id) ' + ELSE + 'CONVERT(BIGINT, NULL) ' + END + + ' AS thread_CPU_snapshot, + COUNT(*) OVER (PARTITION BY t.session_id, t.request_id) AS num_tasks, + t.task_address, + t.task_state, + CASE + WHEN + t.task_state = ''RUNNABLE'' + AND w.runnable_time > 0 THEN + w.runnable_time + ELSE + NULL + END AS runnable_time + FROM sys.dm_os_tasks AS t + CROSS APPLY + ( + SELECT TOP(1) + sp2.session_id + FROM @sessions AS sp2 + WHERE + sp2.session_id = t.session_id + AND sp2.request_id = t.request_id + AND sp2.status <> ''sleeping'' + ) AS sp20 + LEFT OUTER HASH JOIN + ( + SELECT TOP(@i) + ( + SELECT TOP(@i) + ms_ticks + FROM sys.dm_os_sys_info + ) - + w0.wait_resumed_ms_ticks AS runnable_time, + w0.worker_address, + w0.thread_address, + w0.task_bound_ms_ticks + FROM sys.dm_os_workers AS w0 + WHERE + w0.state = ''RUNNABLE'' + OR @first_collection_ms_ticks >= w0.task_bound_ms_ticks + ) AS w ON + w.worker_address = t.worker_address + ' + + CASE + WHEN @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|' + THEN + 'LEFT OUTER HASH JOIN sys.dm_os_threads AS tr ON + tr.thread_address = w.thread_address + AND @first_collection_ms_ticks >= w.task_bound_ms_ticks + ' + ELSE + '' + END + + ') AS task_info + LEFT OUTER HASH JOIN + ( + SELECT TOP(@i) + wt1.wait_type, + wt1.waiting_task_address, + MAX(wt1.wait_duration_ms) AS wait_duration_ms, + MAX(wt1.block_info) AS block_info + FROM + ( + SELECT DISTINCT TOP(@i) + wt.wait_type + + CASE + WHEN wt.wait_type LIKE N''PAGE%LATCH_%'' THEN + '':'' + + COALESCE(DB_NAME(CONVERT(INT, LEFT(wt.resource_description, CHARINDEX(N'':'', wt.resource_description) - 1))), N''(null)'') + + N'':'' + + SUBSTRING(wt.resource_description, CHARINDEX(N'':'', wt.resource_description) + 1, LEN(wt.resource_description) - CHARINDEX(N'':'', REVERSE(wt.resource_description)) - CHARINDEX(N'':'', wt.resource_description)) + + N''('' + + CASE + WHEN + CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 1 OR + CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) % 8088 = 0 + THEN + N''PFS'' + WHEN + CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 2 OR + CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) % 511232 = 0 + THEN + N''GAM'' + WHEN + CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 3 OR + (CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) - 1) % 511232 = 0 + THEN + N''SGAM'' + WHEN + CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 6 OR + (CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) - 6) % 511232 = 0 + THEN + N''DCM'' + WHEN + CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 7 OR + (CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) - 7) % 511232 = 0 + THEN + N''BCM'' + ELSE + N''*'' + END + + N'')'' + WHEN wt.wait_type = N''CXPACKET'' THEN + N'':'' + SUBSTRING(wt.resource_description, CHARINDEX(N''nodeId'', wt.resource_description) + 7, 4) + WHEN wt.wait_type LIKE N''LATCH[_]%'' THEN + N'' ['' + LEFT(wt.resource_description, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description), 0), LEN(wt.resource_description) + 1) - 1) + N'']'' + ELSE + N'''' + END COLLATE Latin1_General_Bin2 AS wait_type, + CASE + WHEN + ( + wt.blocking_session_id IS NOT NULL + AND wt.wait_type LIKE N''LCK[_]%'' + ) THEN + ( + SELECT TOP(@i) + x.lock_type, + REPLACE + ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + DB_NAME + ( + CONVERT + ( + INT, + SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''dbid='', wt.resource_description), 0) + 5, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''dbid='', wt.resource_description) + 5), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''dbid='', wt.resource_description) - 5) + ) + ), + NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), + NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), + NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), + NCHAR(0), + N'''' + ) AS database_name, + CASE x.lock_type + WHEN N''objectlock'' THEN + SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''objid='', wt.resource_description), 0) + 6, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''objid='', wt.resource_description) + 6), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''objid='', wt.resource_description) - 6) + ELSE + NULL + END AS object_id, + CASE x.lock_type + WHEN N''filelock'' THEN + SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''fileid='', wt.resource_description), 0) + 7, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''fileid='', wt.resource_description) + 7), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''fileid='', wt.resource_description) - 7) + ELSE + NULL + END AS file_id, + CASE + WHEN x.lock_type in (N''pagelock'', N''extentlock'', N''ridlock'') THEN + SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''associatedObjectId='', wt.resource_description), 0) + 19, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''associatedObjectId='', wt.resource_description) + 19), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''associatedObjectId='', wt.resource_description) - 19) + WHEN x.lock_type in (N''keylock'', N''hobtlock'', N''allocunitlock'') THEN + SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''hobtid='', wt.resource_description), 0) + 7, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''hobtid='', wt.resource_description) + 7), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''hobtid='', wt.resource_description) - 7) + ELSE + NULL + END AS hobt_id, + CASE x.lock_type + WHEN N''applicationlock'' THEN + SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''hash='', wt.resource_description), 0) + 5, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''hash='', wt.resource_description) + 5), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''hash='', wt.resource_description) - 5) + ELSE + NULL + END AS applock_hash, + CASE x.lock_type + WHEN N''metadatalock'' THEN + SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''subresource='', wt.resource_description), 0) + 12, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''subresource='', wt.resource_description) + 12), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''subresource='', wt.resource_description) - 12) + ELSE + NULL + END AS metadata_resource, + CASE x.lock_type + WHEN N''metadatalock'' THEN + SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''classid='', wt.resource_description), 0) + 8, COALESCE(NULLIF(CHARINDEX(N'' dbid='', wt.resource_description) - CHARINDEX(N''classid='', wt.resource_description), 0), LEN(wt.resource_description) + 1) - 8) + ELSE + NULL + END AS metadata_class_id + FROM + ( + SELECT TOP(1) + LEFT(wt.resource_description, CHARINDEX(N'' '', wt.resource_description) - 1) COLLATE Latin1_General_Bin2 AS lock_type + ) AS x + FOR XML + PATH('''') + ) + ELSE NULL + END AS block_info, + wt.wait_duration_ms, + wt.waiting_task_address + FROM + ( + SELECT TOP(@i) + wt0.wait_type COLLATE Latin1_General_Bin2 AS wait_type, + wt0.resource_description COLLATE Latin1_General_Bin2 AS resource_description, + wt0.wait_duration_ms, + wt0.waiting_task_address, + CASE + WHEN wt0.blocking_session_id = p.blocked THEN + wt0.blocking_session_id + ELSE + NULL + END AS blocking_session_id + FROM sys.dm_os_waiting_tasks AS wt0 + CROSS APPLY + ( + SELECT TOP(1) + s0.blocked + FROM @sessions AS s0 + WHERE + s0.session_id = wt0.session_id + AND COALESCE(s0.wait_type, N'''') <> N''OLEDB'' + AND wt0.wait_type <> N''OLEDB'' + ) AS p + ) AS wt + ) AS wt1 + GROUP BY + wt1.wait_type, + wt1.waiting_task_address + ) AS wt2 ON + wt2.waiting_task_address = task_info.task_address + AND wt2.wait_duration_ms > 0 + AND task_info.runnable_time IS NULL + GROUP BY + task_info.session_id, + task_info.request_id, + task_info.physical_io, + task_info.context_switches, + task_info.thread_CPU_snapshot, + task_info.num_tasks, + CASE + WHEN task_info.runnable_time IS NOT NULL THEN + ''RUNNABLE'' + ELSE + wt2.wait_type + END + ) AS w1 + ) AS waits + ORDER BY + waits.session_id, + waits.request_id, + waits.r + FOR XML + PATH(N''tasks''), + TYPE + ) AS tasks_raw (task_xml_raw) + ) AS tasks_final + CROSS APPLY tasks_final.task_xml.nodes(N''/tasks'') AS task_nodes (task_node) + WHERE + task_nodes.task_node.exist(N''session_id'') = 1 + ) AS tasks ON + tasks.session_id = y.session_id + AND tasks.request_id = y.request_id + ' + ELSE + '' + END + + 'LEFT OUTER HASH JOIN + ( + SELECT TOP(@i) + t_info.session_id, + COALESCE(t_info.request_id, -1) AS request_id, + SUM(t_info.tempdb_allocations) AS tempdb_allocations, + SUM(t_info.tempdb_current) AS tempdb_current + FROM + ( + SELECT TOP(@i) + tsu.session_id, + tsu.request_id, + tsu.user_objects_alloc_page_count + + tsu.internal_objects_alloc_page_count AS tempdb_allocations, + tsu.user_objects_alloc_page_count + + tsu.internal_objects_alloc_page_count - + tsu.user_objects_dealloc_page_count - + tsu.internal_objects_dealloc_page_count AS tempdb_current + FROM sys.dm_db_task_space_usage AS tsu + CROSS APPLY + ( + SELECT TOP(1) + s0.session_id + FROM @sessions AS s0 + WHERE + s0.session_id = tsu.session_id + ) AS p + + UNION ALL + + SELECT TOP(@i) + ssu.session_id, + NULL AS request_id, + ssu.user_objects_alloc_page_count + + ssu.internal_objects_alloc_page_count AS tempdb_allocations, + ssu.user_objects_alloc_page_count + + ssu.internal_objects_alloc_page_count - + ssu.user_objects_dealloc_page_count - + ssu.internal_objects_dealloc_page_count AS tempdb_current + FROM sys.dm_db_session_space_usage AS ssu + CROSS APPLY + ( + SELECT TOP(1) + s0.session_id + FROM @sessions AS s0 + WHERE + s0.session_id = ssu.session_id + ) AS p + ) AS t_info + GROUP BY + t_info.session_id, + COALESCE(t_info.request_id, -1) + ) AS tempdb_info ON + tempdb_info.session_id = y.session_id + AND tempdb_info.request_id = + CASE + WHEN y.status = N''sleeping'' THEN + -1 + ELSE + y.request_id + END + ' + + CASE + WHEN + NOT + ( + @get_avg_time = 1 + AND @recursion = 1 + ) THEN + '' + ELSE + 'LEFT OUTER HASH JOIN + ( + SELECT TOP(@i) + * + FROM sys.dm_exec_query_stats + ) AS qs ON + qs.sql_handle = y.sql_handle + AND qs.plan_handle = y.plan_handle + AND qs.statement_start_offset = y.statement_start_offset + AND qs.statement_end_offset = y.statement_end_offset + ' + END + + ') AS x + OPTION (KEEPFIXED PLAN, OPTIMIZE FOR (@i = 1)); '; + + SET @sql_n = CONVERT(NVARCHAR(MAX), @sql); + + SET @last_collection_start = GETDATE(); + + IF @recursion = -1 + BEGIN; + SELECT + @first_collection_ms_ticks = ms_ticks + FROM sys.dm_os_sys_info; + END; + + INSERT #sessions + ( + recursion, + session_id, + request_id, + session_number, + elapsed_time, + avg_elapsed_time, + physical_io, + reads, + physical_reads, + writes, + tempdb_allocations, + tempdb_current, + CPU, + thread_CPU_snapshot, + context_switches, + used_memory, + tasks, + status, + wait_info, + transaction_id, + open_tran_count, + sql_handle, + statement_start_offset, + statement_end_offset, + sql_text, + plan_handle, + blocking_session_id, + percent_complete, + host_name, + login_name, + database_name, + program_name, + additional_info, + start_time, + login_time, + last_request_start_time + ) + EXEC sp_executesql + @sql_n, + N'@recursion SMALLINT, @filter sysname, @not_filter sysname, @first_collection_ms_ticks BIGINT', + @recursion, @filter, @not_filter, @first_collection_ms_ticks; + + --Collect transaction information? + IF + @recursion = 1 + AND + ( + @output_column_list LIKE '%|[tran_start_time|]%' ESCAPE '|' + OR @output_column_list LIKE '%|[tran_log_writes|]%' ESCAPE '|' + ) + BEGIN; + DECLARE @i INT; + SET @i = 2147483647; + + UPDATE s + SET + tran_start_time = + CONVERT + ( + DATETIME, + LEFT + ( + x.trans_info, + NULLIF(CHARINDEX(NCHAR(254) COLLATE Latin1_General_Bin2, x.trans_info) - 1, -1) + ), + 121 + ), + tran_log_writes = + RIGHT + ( + x.trans_info, + LEN(x.trans_info) - CHARINDEX(NCHAR(254) COLLATE Latin1_General_Bin2, x.trans_info) + ) + FROM + ( + SELECT TOP(@i) + trans_nodes.trans_node.value('(session_id/text())[1]', 'SMALLINT') AS session_id, + COALESCE(trans_nodes.trans_node.value('(request_id/text())[1]', 'INT'), 0) AS request_id, + trans_nodes.trans_node.value('(trans_info/text())[1]', 'NVARCHAR(4000)') AS trans_info + FROM + ( + SELECT TOP(@i) + CONVERT + ( + XML, + REPLACE + ( + CONVERT(NVARCHAR(MAX), trans_raw.trans_xml_raw) COLLATE Latin1_General_Bin2, + N'', N'' + ) + ) + FROM + ( + SELECT TOP(@i) + CASE u_trans.r + WHEN 1 THEN u_trans.session_id + ELSE NULL + END AS [session_id], + CASE u_trans.r + WHEN 1 THEN u_trans.request_id + ELSE NULL + END AS [request_id], + CONVERT + ( + NVARCHAR(MAX), + CASE + WHEN u_trans.database_id IS NOT NULL THEN + CASE u_trans.r + WHEN 1 THEN COALESCE(CONVERT(NVARCHAR, u_trans.transaction_start_time, 121) + NCHAR(254), N'') + ELSE N'' + END + + REPLACE + ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + CONVERT(VARCHAR(128), COALESCE(DB_NAME(u_trans.database_id), N'(null)')), + NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), + NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), + NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), + NCHAR(0), + N'?' + ) + + N': ' + + CONVERT(NVARCHAR, u_trans.log_record_count) + N' (' + CONVERT(NVARCHAR, u_trans.log_kb_used) + N' kB)' + + N',' + ELSE + N'N/A,' + END COLLATE Latin1_General_Bin2 + ) AS [trans_info] + FROM + ( + SELECT TOP(@i) + trans.*, + ROW_NUMBER() OVER + ( + PARTITION BY + trans.session_id, + trans.request_id + ORDER BY + trans.transaction_start_time DESC + ) AS r + FROM + ( + SELECT TOP(@i) + session_tran_map.session_id, + session_tran_map.request_id, + s_tran.database_id, + COALESCE(SUM(s_tran.database_transaction_log_record_count), 0) AS log_record_count, + COALESCE(SUM(s_tran.database_transaction_log_bytes_used), 0) / 1024 AS log_kb_used, + MIN(s_tran.database_transaction_begin_time) AS transaction_start_time + FROM + ( + SELECT TOP(@i) + * + FROM sys.dm_tran_active_transactions + WHERE + transaction_begin_time <= @last_collection_start + ) AS a_tran + INNER HASH JOIN + ( + SELECT TOP(@i) + * + FROM sys.dm_tran_database_transactions + WHERE + database_id < 32767 + ) AS s_tran ON + s_tran.transaction_id = a_tran.transaction_id + LEFT OUTER HASH JOIN + ( + SELECT TOP(@i) + * + FROM sys.dm_tran_session_transactions + ) AS tst ON + s_tran.transaction_id = tst.transaction_id + CROSS APPLY + ( + SELECT TOP(1) + s3.session_id, + s3.request_id + FROM + ( + SELECT TOP(1) + s1.session_id, + s1.request_id + FROM #sessions AS s1 + WHERE + s1.transaction_id = s_tran.transaction_id + AND s1.recursion = 1 + + UNION ALL + + SELECT TOP(1) + s2.session_id, + s2.request_id + FROM #sessions AS s2 + WHERE + s2.session_id = tst.session_id + AND s2.recursion = 1 + ) AS s3 + ORDER BY + s3.request_id + ) AS session_tran_map + GROUP BY + session_tran_map.session_id, + session_tran_map.request_id, + s_tran.database_id + ) AS trans + ) AS u_trans + FOR XML + PATH('trans'), + TYPE + ) AS trans_raw (trans_xml_raw) + ) AS trans_final (trans_xml) + CROSS APPLY trans_final.trans_xml.nodes('/trans') AS trans_nodes (trans_node) + ) AS x + INNER HASH JOIN #sessions AS s ON + s.session_id = x.session_id + AND s.request_id = x.request_id + OPTION (OPTIMIZE FOR (@i = 1)); + END; + + --Variables for text and plan collection + DECLARE + @session_id SMALLINT, + @request_id INT, + @sql_handle VARBINARY(64), + @plan_handle VARBINARY(64), + @statement_start_offset INT, + @statement_end_offset INT, + @start_time DATETIME, + @database_name sysname; + + IF + @recursion = 1 + AND @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|' + BEGIN; + DECLARE sql_cursor + CURSOR LOCAL FAST_FORWARD + FOR + SELECT + session_id, + request_id, + sql_handle, + statement_start_offset, + statement_end_offset + FROM #sessions + WHERE + recursion = 1 + AND sql_handle IS NOT NULL + OPTION (KEEPFIXED PLAN); + + OPEN sql_cursor; + + FETCH NEXT FROM sql_cursor + INTO + @session_id, + @request_id, + @sql_handle, + @statement_start_offset, + @statement_end_offset; + + --Wait up to 5 ms for the SQL text, then give up + SET LOCK_TIMEOUT 5; + + WHILE @@FETCH_STATUS = 0 + BEGIN; + BEGIN TRY; + UPDATE s + SET + s.sql_text = + ( + SELECT + REPLACE + ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + N'--' + NCHAR(13) + NCHAR(10) + + CASE + WHEN @get_full_inner_text = 1 THEN est.text + WHEN LEN(est.text) < (@statement_end_offset / 2) + 1 THEN est.text + WHEN SUBSTRING(est.text, (@statement_start_offset/2), 2) LIKE N'[a-zA-Z0-9][a-zA-Z0-9]' THEN est.text + ELSE + CASE + WHEN @statement_start_offset > 0 THEN + SUBSTRING + ( + est.text, + ((@statement_start_offset/2) + 1), + ( + CASE + WHEN @statement_end_offset = -1 THEN 2147483647 + ELSE ((@statement_end_offset - @statement_start_offset)/2) + 1 + END + ) + ) + ELSE RTRIM(LTRIM(est.text)) + END + END + + NCHAR(13) + NCHAR(10) + N'--' COLLATE Latin1_General_Bin2, + NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), + NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), + NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), + NCHAR(0), + N'' + ) AS [processing-instruction(query)] + FOR XML + PATH(''), + TYPE + ), + s.statement_start_offset = + CASE + WHEN LEN(est.text) < (@statement_end_offset / 2) + 1 THEN 0 + WHEN SUBSTRING(CONVERT(VARCHAR(MAX), est.text), (@statement_start_offset/2), 2) LIKE '[a-zA-Z0-9][a-zA-Z0-9]' THEN 0 + ELSE @statement_start_offset + END, + s.statement_end_offset = + CASE + WHEN LEN(est.text) < (@statement_end_offset / 2) + 1 THEN -1 + WHEN SUBSTRING(CONVERT(VARCHAR(MAX), est.text), (@statement_start_offset/2), 2) LIKE '[a-zA-Z0-9][a-zA-Z0-9]' THEN -1 + ELSE @statement_end_offset + END + FROM + #sessions AS s, + ( + SELECT TOP(1) + text + FROM + ( + SELECT + text, + 0 AS row_num + FROM sys.dm_exec_sql_text(@sql_handle) + + UNION ALL + + SELECT + NULL, + 1 AS row_num + ) AS est0 + ORDER BY + row_num + ) AS est + WHERE + s.session_id = @session_id + AND s.request_id = @request_id + AND s.recursion = 1 + OPTION (KEEPFIXED PLAN); + END TRY + BEGIN CATCH; + UPDATE s + SET + s.sql_text = + CASE ERROR_NUMBER() + WHEN 1222 THEN '' + ELSE '' + END + FROM #sessions AS s + WHERE + s.session_id = @session_id + AND s.request_id = @request_id + AND s.recursion = 1 + OPTION (KEEPFIXED PLAN); + END CATCH; + + FETCH NEXT FROM sql_cursor + INTO + @session_id, + @request_id, + @sql_handle, + @statement_start_offset, + @statement_end_offset; + END; + + --Return this to the default + SET LOCK_TIMEOUT -1; + + CLOSE sql_cursor; + DEALLOCATE sql_cursor; + END; + + IF + @get_outer_command = 1 + AND @recursion = 1 + AND @output_column_list LIKE '%|[sql_command|]%' ESCAPE '|' + BEGIN; + DECLARE @buffer_results TABLE + ( + EventType VARCHAR(30), + Parameters INT, + EventInfo NVARCHAR(4000), + start_time DATETIME, + session_number INT IDENTITY(1,1) NOT NULL PRIMARY KEY + ); + + DECLARE buffer_cursor + CURSOR LOCAL FAST_FORWARD + FOR + SELECT + session_id, + MAX(start_time) AS start_time + FROM #sessions + WHERE + recursion = 1 + GROUP BY + session_id + ORDER BY + session_id + OPTION (KEEPFIXED PLAN); + + OPEN buffer_cursor; + + FETCH NEXT FROM buffer_cursor + INTO + @session_id, + @start_time; + + WHILE @@FETCH_STATUS = 0 + BEGIN; + BEGIN TRY; + --In SQL Server 2008, DBCC INPUTBUFFER will throw + --an exception if the session no longer exists + INSERT @buffer_results + ( + EventType, + Parameters, + EventInfo + ) + EXEC sp_executesql + N'DBCC INPUTBUFFER(@session_id) WITH NO_INFOMSGS;', + N'@session_id SMALLINT', + @session_id; + + UPDATE br + SET + br.start_time = @start_time + FROM @buffer_results AS br + WHERE + br.session_number = + ( + SELECT MAX(br2.session_number) + FROM @buffer_results br2 + ); + END TRY + BEGIN CATCH + END CATCH; + + FETCH NEXT FROM buffer_cursor + INTO + @session_id, + @start_time; + END; + + UPDATE s + SET + sql_command = + ( + SELECT + REPLACE + ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + CONVERT + ( + NVARCHAR(MAX), + N'--' + NCHAR(13) + NCHAR(10) + br.EventInfo + NCHAR(13) + NCHAR(10) + N'--' COLLATE Latin1_General_Bin2 + ), + NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), + NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), + NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), + NCHAR(0), + N'' + ) AS [processing-instruction(query)] + FROM @buffer_results AS br + WHERE + br.session_number = s.session_number + AND br.start_time = s.start_time + AND + ( + ( + s.start_time = s.last_request_start_time + AND EXISTS + ( + SELECT * + FROM sys.dm_exec_requests r2 + WHERE + r2.session_id = s.session_id + AND r2.request_id = s.request_id + AND r2.start_time = s.start_time + ) + ) + OR + ( + s.request_id = 0 + AND EXISTS + ( + SELECT * + FROM sys.dm_exec_sessions s2 + WHERE + s2.session_id = s.session_id + AND s2.last_request_start_time = s.last_request_start_time + ) + ) + ) + FOR XML + PATH(''), + TYPE + ) + FROM #sessions AS s + WHERE + recursion = 1 + OPTION (KEEPFIXED PLAN); + + CLOSE buffer_cursor; + DEALLOCATE buffer_cursor; + END; + + IF + @get_plans >= 1 + AND @recursion = 1 + AND @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|' + BEGIN; + DECLARE plan_cursor + CURSOR LOCAL FAST_FORWARD + FOR + SELECT + session_id, + request_id, + plan_handle, + statement_start_offset, + statement_end_offset + FROM #sessions + WHERE + recursion = 1 + AND plan_handle IS NOT NULL + OPTION (KEEPFIXED PLAN); + + OPEN plan_cursor; + + FETCH NEXT FROM plan_cursor + INTO + @session_id, + @request_id, + @plan_handle, + @statement_start_offset, + @statement_end_offset; + + --Wait up to 5 ms for a query plan, then give up + SET LOCK_TIMEOUT 5; + + WHILE @@FETCH_STATUS = 0 + BEGIN; + BEGIN TRY; + UPDATE s + SET + s.query_plan = + ( + SELECT + CONVERT(xml, query_plan) + FROM sys.dm_exec_text_query_plan + ( + @plan_handle, + CASE @get_plans + WHEN 1 THEN + @statement_start_offset + ELSE + 0 + END, + CASE @get_plans + WHEN 1 THEN + @statement_end_offset + ELSE + -1 + END + ) + ) + FROM #sessions AS s + WHERE + s.session_id = @session_id + AND s.request_id = @request_id + AND s.recursion = 1 + OPTION (KEEPFIXED PLAN); + END TRY + BEGIN CATCH; + IF ERROR_NUMBER() = 6335 + BEGIN; + UPDATE s + SET + s.query_plan = + ( + SELECT + N'--' + NCHAR(13) + NCHAR(10) + + N'-- Could not render showplan due to XML data type limitations. ' + NCHAR(13) + NCHAR(10) + + N'-- To see the graphical plan save the XML below as a .SQLPLAN file and re-open in SSMS.' + NCHAR(13) + NCHAR(10) + + N'--' + NCHAR(13) + NCHAR(10) + + REPLACE(qp.query_plan, N'' + ELSE '' + END + FROM #sessions AS s + WHERE + s.session_id = @session_id + AND s.request_id = @request_id + AND s.recursion = 1 + OPTION (KEEPFIXED PLAN); + END; + END CATCH; + + FETCH NEXT FROM plan_cursor + INTO + @session_id, + @request_id, + @plan_handle, + @statement_start_offset, + @statement_end_offset; + END; + + --Return this to the default + SET LOCK_TIMEOUT -1; + + CLOSE plan_cursor; + DEALLOCATE plan_cursor; + END; + + IF + @get_locks = 1 + AND @recursion = 1 + AND @output_column_list LIKE '%|[locks|]%' ESCAPE '|' + BEGIN; + DECLARE locks_cursor + CURSOR LOCAL FAST_FORWARD + FOR + SELECT DISTINCT + database_name + FROM #locks + WHERE + EXISTS + ( + SELECT * + FROM #sessions AS s + WHERE + s.session_id = #locks.session_id + AND recursion = 1 + ) + AND database_name <> '(null)' + OPTION (KEEPFIXED PLAN); + + OPEN locks_cursor; + + FETCH NEXT FROM locks_cursor + INTO + @database_name; + + WHILE @@FETCH_STATUS = 0 + BEGIN; + BEGIN TRY; + SET @sql_n = CONVERT(NVARCHAR(MAX), '') + + 'UPDATE l ' + + 'SET ' + + 'object_name = ' + + 'REPLACE ' + + '( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'o.name COLLATE Latin1_General_Bin2, ' + + 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + + 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + + 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + + 'NCHAR(0), ' + + N''''' ' + + '), ' + + 'index_name = ' + + 'REPLACE ' + + '( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'i.name COLLATE Latin1_General_Bin2, ' + + 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + + 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + + 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + + 'NCHAR(0), ' + + N''''' ' + + '), ' + + 'schema_name = ' + + 'REPLACE ' + + '( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 's.name COLLATE Latin1_General_Bin2, ' + + 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + + 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + + 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + + 'NCHAR(0), ' + + N''''' ' + + '), ' + + 'principal_name = ' + + 'REPLACE ' + + '( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'dp.name COLLATE Latin1_General_Bin2, ' + + 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + + 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + + 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + + 'NCHAR(0), ' + + N''''' ' + + ') ' + + 'FROM #locks AS l ' + + 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.allocation_units AS au ON ' + + 'au.allocation_unit_id = l.allocation_unit_id ' + + 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.partitions AS p ON ' + + 'p.hobt_id = ' + + 'COALESCE ' + + '( ' + + 'l.hobt_id, ' + + 'CASE ' + + 'WHEN au.type IN (1, 3) THEN au.container_id ' + + 'ELSE NULL ' + + 'END ' + + ') ' + + 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.partitions AS p1 ON ' + + 'l.hobt_id IS NULL ' + + 'AND au.type = 2 ' + + 'AND p1.partition_id = au.container_id ' + + 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.objects AS o ON ' + + 'o.object_id = COALESCE(l.object_id, p.object_id, p1.object_id) ' + + 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.indexes AS i ON ' + + 'i.object_id = COALESCE(l.object_id, p.object_id, p1.object_id) ' + + 'AND i.index_id = COALESCE(l.index_id, p.index_id, p1.index_id) ' + + 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.schemas AS s ON ' + + 's.schema_id = COALESCE(l.schema_id, o.schema_id) ' + + 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.database_principals AS dp ON ' + + 'dp.principal_id = l.principal_id ' + + 'WHERE ' + + 'l.database_name = @database_name ' + + 'OPTION (KEEPFIXED PLAN); '; + + EXEC sp_executesql + @sql_n, + N'@database_name sysname', + @database_name; + END TRY + BEGIN CATCH; + UPDATE #locks + SET + query_error = + REPLACE + ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + CONVERT + ( + NVARCHAR(MAX), + ERROR_MESSAGE() COLLATE Latin1_General_Bin2 + ), + NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), + NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), + NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), + NCHAR(0), + N'' + ) + WHERE + database_name = @database_name + OPTION (KEEPFIXED PLAN); + END CATCH; + + FETCH NEXT FROM locks_cursor + INTO + @database_name; + END; + + CLOSE locks_cursor; + DEALLOCATE locks_cursor; + + CREATE CLUSTERED INDEX IX_SRD ON #locks (session_id, request_id, database_name); + + UPDATE s + SET + s.locks = + ( + SELECT + REPLACE + ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + CONVERT + ( + NVARCHAR(MAX), + l1.database_name COLLATE Latin1_General_Bin2 + ), + NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), + NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), + NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), + NCHAR(0), + N'' + ) AS [Database/@name], + MIN(l1.query_error) AS [Database/@query_error], + ( + SELECT + l2.request_mode AS [Lock/@request_mode], + l2.request_status AS [Lock/@request_status], + COUNT(*) AS [Lock/@request_count] + FROM #locks AS l2 + WHERE + l1.session_id = l2.session_id + AND l1.request_id = l2.request_id + AND l2.database_name = l1.database_name + AND l2.resource_type = 'DATABASE' + GROUP BY + l2.request_mode, + l2.request_status + FOR XML + PATH(''), + TYPE + ) AS [Database/Locks], + ( + SELECT + COALESCE(l3.object_name, '(null)') AS [Object/@name], + l3.schema_name AS [Object/@schema_name], + ( + SELECT + l4.resource_type AS [Lock/@resource_type], + l4.page_type AS [Lock/@page_type], + l4.index_name AS [Lock/@index_name], + CASE + WHEN l4.object_name IS NULL THEN l4.schema_name + ELSE NULL + END AS [Lock/@schema_name], + l4.principal_name AS [Lock/@principal_name], + l4.resource_description AS [Lock/@resource_description], + l4.request_mode AS [Lock/@request_mode], + l4.request_status AS [Lock/@request_status], + SUM(l4.request_count) AS [Lock/@request_count] + FROM #locks AS l4 + WHERE + l4.session_id = l3.session_id + AND l4.request_id = l3.request_id + AND l3.database_name = l4.database_name + AND COALESCE(l3.object_name, '(null)') = COALESCE(l4.object_name, '(null)') + AND COALESCE(l3.schema_name, '') = COALESCE(l4.schema_name, '') + AND l4.resource_type <> 'DATABASE' + GROUP BY + l4.resource_type, + l4.page_type, + l4.index_name, + CASE + WHEN l4.object_name IS NULL THEN l4.schema_name + ELSE NULL + END, + l4.principal_name, + l4.resource_description, + l4.request_mode, + l4.request_status + FOR XML + PATH(''), + TYPE + ) AS [Object/Locks] + FROM #locks AS l3 + WHERE + l3.session_id = l1.session_id + AND l3.request_id = l1.request_id + AND l3.database_name = l1.database_name + AND l3.resource_type <> 'DATABASE' + GROUP BY + l3.session_id, + l3.request_id, + l3.database_name, + COALESCE(l3.object_name, '(null)'), + l3.schema_name + FOR XML + PATH(''), + TYPE + ) AS [Database/Objects] + FROM #locks AS l1 + WHERE + l1.session_id = s.session_id + AND l1.request_id = s.request_id + AND l1.start_time IN (s.start_time, s.last_request_start_time) + AND s.recursion = 1 + GROUP BY + l1.session_id, + l1.request_id, + l1.database_name + FOR XML + PATH(''), + TYPE + ) + FROM #sessions s + OPTION (KEEPFIXED PLAN); + END; + + IF + @find_block_leaders = 1 + AND @recursion = 1 + AND @output_column_list LIKE '%|[blocked_session_count|]%' ESCAPE '|' + BEGIN; + WITH + blockers AS + ( + SELECT + session_id, + session_id AS top_level_session_id, + CONVERT(VARCHAR(8000), '.' + CONVERT(VARCHAR(8000), session_id) + '.') AS the_path + FROM #sessions + WHERE + recursion = 1 + + UNION ALL + + SELECT + s.session_id, + b.top_level_session_id, + CONVERT(VARCHAR(8000), b.the_path + CONVERT(VARCHAR(8000), s.session_id) + '.') AS the_path + FROM blockers AS b + JOIN #sessions AS s ON + s.blocking_session_id = b.session_id + AND s.recursion = 1 + AND b.the_path NOT LIKE '%.' + CONVERT(VARCHAR(8000), s.session_id) + '.%' COLLATE Latin1_General_Bin2 + ) + UPDATE s + SET + s.blocked_session_count = x.blocked_session_count + FROM #sessions AS s + JOIN + ( + SELECT + b.top_level_session_id AS session_id, + COUNT(*) - 1 AS blocked_session_count + FROM blockers AS b + GROUP BY + b.top_level_session_id + ) x ON + s.session_id = x.session_id + WHERE + s.recursion = 1; + END; + + IF + @get_task_info = 2 + AND @output_column_list LIKE '%|[additional_info|]%' ESCAPE '|' + AND @recursion = 1 + BEGIN; + CREATE TABLE #blocked_requests + ( + session_id SMALLINT NOT NULL, + request_id INT NOT NULL, + database_name sysname NOT NULL, + object_id INT, + hobt_id BIGINT, + schema_id INT, + schema_name sysname NULL, + object_name sysname NULL, + query_error NVARCHAR(2048), + PRIMARY KEY (database_name, session_id, request_id) + ); + + CREATE STATISTICS s_database_name ON #blocked_requests (database_name) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_schema_name ON #blocked_requests (schema_name) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_object_name ON #blocked_requests (object_name) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + CREATE STATISTICS s_query_error ON #blocked_requests (query_error) + WITH SAMPLE 0 ROWS, NORECOMPUTE; + + INSERT #blocked_requests + ( + session_id, + request_id, + database_name, + object_id, + hobt_id, + schema_id + ) + SELECT + session_id, + request_id, + database_name, + object_id, + hobt_id, + CONVERT(INT, SUBSTRING(schema_node, CHARINDEX(' = ', schema_node) + 3, LEN(schema_node))) AS schema_id + FROM + ( + SELECT + session_id, + request_id, + agent_nodes.agent_node.value('(database_name/text())[1]', 'sysname') AS database_name, + agent_nodes.agent_node.value('(object_id/text())[1]', 'int') AS object_id, + agent_nodes.agent_node.value('(hobt_id/text())[1]', 'bigint') AS hobt_id, + agent_nodes.agent_node.value('(metadata_resource/text()[.="SCHEMA"]/../../metadata_class_id/text())[1]', 'varchar(100)') AS schema_node + FROM #sessions AS s + CROSS APPLY s.additional_info.nodes('//block_info') AS agent_nodes (agent_node) + WHERE + s.recursion = 1 + ) AS t + WHERE + t.database_name IS NOT NULL + AND + ( + t.object_id IS NOT NULL + OR t.hobt_id IS NOT NULL + OR t.schema_node IS NOT NULL + ); + + DECLARE blocks_cursor + CURSOR LOCAL FAST_FORWARD + FOR + SELECT DISTINCT + database_name + FROM #blocked_requests; + + OPEN blocks_cursor; + + FETCH NEXT FROM blocks_cursor + INTO + @database_name; + + WHILE @@FETCH_STATUS = 0 + BEGIN; + BEGIN TRY; + SET @sql_n = + CONVERT(NVARCHAR(MAX), '') + + 'UPDATE b ' + + 'SET ' + + 'b.schema_name = ' + + 'REPLACE ' + + '( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 's.name COLLATE Latin1_General_Bin2, ' + + 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + + 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + + 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + + 'NCHAR(0), ' + + N''''' ' + + '), ' + + 'b.object_name = ' + + 'REPLACE ' + + '( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + + 'o.name COLLATE Latin1_General_Bin2, ' + + 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + + 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + + 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + + 'NCHAR(0), ' + + N''''' ' + + ') ' + + 'FROM #blocked_requests AS b ' + + 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.partitions AS p ON ' + + 'p.hobt_id = b.hobt_id ' + + 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.objects AS o ON ' + + 'o.object_id = COALESCE(p.object_id, b.object_id) ' + + 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.schemas AS s ON ' + + 's.schema_id = COALESCE(o.schema_id, b.schema_id) ' + + 'WHERE ' + + 'b.database_name = @database_name; '; + + EXEC sp_executesql + @sql_n, + N'@database_name sysname', + @database_name; + END TRY + BEGIN CATCH; + UPDATE #blocked_requests + SET + query_error = + REPLACE + ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + CONVERT + ( + NVARCHAR(MAX), + ERROR_MESSAGE() COLLATE Latin1_General_Bin2 + ), + NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), + NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), + NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), + NCHAR(0), + N'' + ) + WHERE + database_name = @database_name; + END CATCH; + + FETCH NEXT FROM blocks_cursor + INTO + @database_name; + END; + + CLOSE blocks_cursor; + DEALLOCATE blocks_cursor; + + UPDATE s + SET + additional_info.modify + (' + insert {sql:column("b.schema_name")} + as last + into (/additional_info/block_info)[1] + ') + FROM #sessions AS s + INNER JOIN #blocked_requests AS b ON + b.session_id = s.session_id + AND b.request_id = s.request_id + AND s.recursion = 1 + WHERE + b.schema_name IS NOT NULL; + + UPDATE s + SET + additional_info.modify + (' + insert {sql:column("b.object_name")} + as last + into (/additional_info/block_info)[1] + ') + FROM #sessions AS s + INNER JOIN #blocked_requests AS b ON + b.session_id = s.session_id + AND b.request_id = s.request_id + AND s.recursion = 1 + WHERE + b.object_name IS NOT NULL; + + UPDATE s + SET + additional_info.modify + (' + insert {sql:column("b.query_error")} + as last + into (/additional_info/block_info)[1] + ') + FROM #sessions AS s + INNER JOIN #blocked_requests AS b ON + b.session_id = s.session_id + AND b.request_id = s.request_id + AND s.recursion = 1 + WHERE + b.query_error IS NOT NULL; + END; + + IF + @output_column_list LIKE '%|[program_name|]%' ESCAPE '|' + AND @output_column_list LIKE '%|[additional_info|]%' ESCAPE '|' + AND @recursion = 1 + BEGIN; + DECLARE @job_id UNIQUEIDENTIFIER; + DECLARE @step_id INT; + + DECLARE agent_cursor + CURSOR LOCAL FAST_FORWARD + FOR + SELECT + s.session_id, + agent_nodes.agent_node.value('(job_id/text())[1]', 'uniqueidentifier') AS job_id, + agent_nodes.agent_node.value('(step_id/text())[1]', 'int') AS step_id + FROM #sessions AS s + CROSS APPLY s.additional_info.nodes('//agent_job_info') AS agent_nodes (agent_node) + WHERE + s.recursion = 1 + OPTION (KEEPFIXED PLAN); + + OPEN agent_cursor; + + FETCH NEXT FROM agent_cursor + INTO + @session_id, + @job_id, + @step_id; + + WHILE @@FETCH_STATUS = 0 + BEGIN; + BEGIN TRY; + DECLARE @job_name sysname; + SET @job_name = NULL; + DECLARE @step_name sysname; + SET @step_name = NULL; + + SELECT + @job_name = + REPLACE + ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + j.name, + NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), + NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), + NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), + NCHAR(0), + N'?' + ), + @step_name = + REPLACE + ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + s.step_name, + NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), + NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), + NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), + NCHAR(0), + N'?' + ) + FROM msdb.dbo.sysjobs AS j + INNER JOIN msdb..sysjobsteps AS s ON + j.job_id = s.job_id + WHERE + j.job_id = @job_id + AND s.step_id = @step_id; + + IF @job_name IS NOT NULL + BEGIN; + UPDATE s + SET + additional_info.modify + (' + insert text{sql:variable("@job_name")} + into (/additional_info/agent_job_info/job_name)[1] + ') + FROM #sessions AS s + WHERE + s.session_id = @session_id + OPTION (KEEPFIXED PLAN); + + UPDATE s + SET + additional_info.modify + (' + insert text{sql:variable("@step_name")} + into (/additional_info/agent_job_info/step_name)[1] + ') + FROM #sessions AS s + WHERE + s.session_id = @session_id + OPTION (KEEPFIXED PLAN); + END; + END TRY + BEGIN CATCH; + DECLARE @msdb_error_message NVARCHAR(256); + SET @msdb_error_message = ERROR_MESSAGE(); + + UPDATE s + SET + additional_info.modify + (' + insert {sql:variable("@msdb_error_message")} + as last + into (/additional_info/agent_job_info)[1] + ') + FROM #sessions AS s + WHERE + s.session_id = @session_id + AND s.recursion = 1 + OPTION (KEEPFIXED PLAN); + END CATCH; + + FETCH NEXT FROM agent_cursor + INTO + @session_id, + @job_id, + @step_id; + END; + + CLOSE agent_cursor; + DEALLOCATE agent_cursor; + END; + + IF + @delta_interval > 0 + AND @recursion <> 1 + BEGIN; + SET @recursion = 1; + + DECLARE @delay_time CHAR(12); + SET @delay_time = CONVERT(VARCHAR, DATEADD(second, @delta_interval, 0), 114); + WAITFOR DELAY @delay_time; + + GOTO REDO; + END; + END; + + SET @sql = + --Outer column list + CONVERT + ( + VARCHAR(MAX), + CASE + WHEN + @destination_table <> '' + AND @return_schema = 0 + THEN 'INSERT ' + @destination_table + ' ' + ELSE '' + END + + 'SELECT ' + + @output_column_list + ' ' + + CASE @return_schema + WHEN 1 THEN 'INTO #session_schema ' + ELSE '' + END + --End outer column list + ) + + --Inner column list + CONVERT + ( + VARCHAR(MAX), + 'FROM ' + + '( ' + + 'SELECT ' + + 'session_id, ' + + --[dd hh:mm:ss.mss] + CASE + WHEN @format_output IN (1, 2) THEN + 'CASE ' + + 'WHEN elapsed_time < 0 THEN ' + + 'RIGHT ' + + '( ' + + 'REPLICATE(''0'', max_elapsed_length) + CONVERT(VARCHAR, (-1 * elapsed_time) / 86400), ' + + 'max_elapsed_length ' + + ') + ' + + 'RIGHT ' + + '( ' + + 'CONVERT(VARCHAR, DATEADD(second, (-1 * elapsed_time), 0), 120), ' + + '9 ' + + ') + ' + + '''.000'' ' + + 'ELSE ' + + 'RIGHT ' + + '( ' + + 'REPLICATE(''0'', max_elapsed_length) + CONVERT(VARCHAR, elapsed_time / 86400000), ' + + 'max_elapsed_length ' + + ') + ' + + 'RIGHT ' + + '( ' + + 'CONVERT(VARCHAR, DATEADD(second, elapsed_time / 1000, 0), 120), ' + + '9 ' + + ') + ' + + '''.'' + ' + + 'RIGHT(''000'' + CONVERT(VARCHAR, elapsed_time % 1000), 3) ' + + 'END AS [dd hh:mm:ss.mss], ' + ELSE + '' + END + + --[dd hh:mm:ss.mss (avg)] / avg_elapsed_time + CASE + WHEN @format_output IN (1, 2) THEN + 'RIGHT ' + + '( ' + + '''00'' + CONVERT(VARCHAR, avg_elapsed_time / 86400000), ' + + '2 ' + + ') + ' + + 'RIGHT ' + + '( ' + + 'CONVERT(VARCHAR, DATEADD(second, avg_elapsed_time / 1000, 0), 120), ' + + '9 ' + + ') + ' + + '''.'' + ' + + 'RIGHT(''000'' + CONVERT(VARCHAR, avg_elapsed_time % 1000), 3) AS [dd hh:mm:ss.mss (avg)], ' + ELSE + 'avg_elapsed_time, ' + END + + --physical_io + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_io))) OVER() - LEN(CONVERT(VARCHAR, physical_io))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io), 1), 19)) AS ' + ELSE '' + END + 'physical_io, ' + + --reads + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, reads))) OVER() - LEN(CONVERT(VARCHAR, reads))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads), 1), 19)) AS ' + ELSE '' + END + 'reads, ' + + --physical_reads + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_reads))) OVER() - LEN(CONVERT(VARCHAR, physical_reads))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads), 1), 19)) AS ' + ELSE '' + END + 'physical_reads, ' + + --writes + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, writes))) OVER() - LEN(CONVERT(VARCHAR, writes))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes), 1), 19)) AS ' + ELSE '' + END + 'writes, ' + + --tempdb_allocations + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_allocations))) OVER() - LEN(CONVERT(VARCHAR, tempdb_allocations))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations), 1), 19)) AS ' + ELSE '' + END + 'tempdb_allocations, ' + + --tempdb_current + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_current))) OVER() - LEN(CONVERT(VARCHAR, tempdb_current))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current), 1), 19)) AS ' + ELSE '' + END + 'tempdb_current, ' + + --CPU + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, CPU))) OVER() - LEN(CONVERT(VARCHAR, CPU))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU), 1), 19)) AS ' + ELSE '' + END + 'CPU, ' + + --context_switches + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, context_switches))) OVER() - LEN(CONVERT(VARCHAR, context_switches))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches), 1), 19)) AS ' + ELSE '' + END + 'context_switches, ' + + --used_memory + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, used_memory))) OVER() - LEN(CONVERT(VARCHAR, used_memory))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory), 1), 19)) AS ' + ELSE '' + END + 'used_memory, ' + + CASE + WHEN @output_column_list LIKE '%|_delta|]%' ESCAPE '|' THEN + --physical_io_delta + 'CASE ' + + 'WHEN ' + + 'first_request_start_time = last_request_start_time ' + + 'AND num_events = 2 ' + + 'AND physical_io_delta >= 0 ' + + 'THEN ' + + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_io_delta))) OVER() - LEN(CONVERT(VARCHAR, physical_io_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io_delta), 1), 19)) ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io_delta), 1), 19)) ' + ELSE 'physical_io_delta ' + END + + 'ELSE NULL ' + + 'END AS physical_io_delta, ' + + --reads_delta + 'CASE ' + + 'WHEN ' + + 'first_request_start_time = last_request_start_time ' + + 'AND num_events = 2 ' + + 'AND reads_delta >= 0 ' + + 'THEN ' + + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, reads_delta))) OVER() - LEN(CONVERT(VARCHAR, reads_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads_delta), 1), 19)) ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads_delta), 1), 19)) ' + ELSE 'reads_delta ' + END + + 'ELSE NULL ' + + 'END AS reads_delta, ' + + --physical_reads_delta + 'CASE ' + + 'WHEN ' + + 'first_request_start_time = last_request_start_time ' + + 'AND num_events = 2 ' + + 'AND physical_reads_delta >= 0 ' + + 'THEN ' + + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_reads_delta))) OVER() - LEN(CONVERT(VARCHAR, physical_reads_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads_delta), 1), 19)) ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads_delta), 1), 19)) ' + ELSE 'physical_reads_delta ' + END + + 'ELSE NULL ' + + 'END AS physical_reads_delta, ' + + --writes_delta + 'CASE ' + + 'WHEN ' + + 'first_request_start_time = last_request_start_time ' + + 'AND num_events = 2 ' + + 'AND writes_delta >= 0 ' + + 'THEN ' + + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, writes_delta))) OVER() - LEN(CONVERT(VARCHAR, writes_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes_delta), 1), 19)) ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes_delta), 1), 19)) ' + ELSE 'writes_delta ' + END + + 'ELSE NULL ' + + 'END AS writes_delta, ' + + --tempdb_allocations_delta + 'CASE ' + + 'WHEN ' + + 'first_request_start_time = last_request_start_time ' + + 'AND num_events = 2 ' + + 'AND tempdb_allocations_delta >= 0 ' + + 'THEN ' + + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_allocations_delta))) OVER() - LEN(CONVERT(VARCHAR, tempdb_allocations_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations_delta), 1), 19)) ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations_delta), 1), 19)) ' + ELSE 'tempdb_allocations_delta ' + END + + 'ELSE NULL ' + + 'END AS tempdb_allocations_delta, ' + + --tempdb_current_delta + --this is the only one that can (legitimately) go negative + 'CASE ' + + 'WHEN ' + + 'first_request_start_time = last_request_start_time ' + + 'AND num_events = 2 ' + + 'THEN ' + + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_current_delta))) OVER() - LEN(CONVERT(VARCHAR, tempdb_current_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current_delta), 1), 19)) ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current_delta), 1), 19)) ' + ELSE 'tempdb_current_delta ' + END + + 'ELSE NULL ' + + 'END AS tempdb_current_delta, ' + + --CPU_delta + 'CASE ' + + 'WHEN ' + + 'first_request_start_time = last_request_start_time ' + + 'AND num_events = 2 ' + + 'THEN ' + + 'CASE ' + + 'WHEN ' + + 'thread_CPU_delta > CPU_delta ' + + 'AND thread_CPU_delta > 0 ' + + 'THEN ' + + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, thread_CPU_delta + CPU_delta))) OVER() - LEN(CONVERT(VARCHAR, thread_CPU_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, thread_CPU_delta), 1), 19)) ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, thread_CPU_delta), 1), 19)) ' + ELSE 'thread_CPU_delta ' + END + + 'WHEN CPU_delta >= 0 THEN ' + + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, thread_CPU_delta + CPU_delta))) OVER() - LEN(CONVERT(VARCHAR, CPU_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU_delta), 1), 19)) ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU_delta), 1), 19)) ' + ELSE 'CPU_delta ' + END + + 'ELSE NULL ' + + 'END ' + + 'ELSE ' + + 'NULL ' + + 'END AS CPU_delta, ' + + --context_switches_delta + 'CASE ' + + 'WHEN ' + + 'first_request_start_time = last_request_start_time ' + + 'AND num_events = 2 ' + + 'AND context_switches_delta >= 0 ' + + 'THEN ' + + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, context_switches_delta))) OVER() - LEN(CONVERT(VARCHAR, context_switches_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches_delta), 1), 19)) ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches_delta), 1), 19)) ' + ELSE 'context_switches_delta ' + END + + 'ELSE NULL ' + + 'END AS context_switches_delta, ' + + --used_memory_delta + 'CASE ' + + 'WHEN ' + + 'first_request_start_time = last_request_start_time ' + + 'AND num_events = 2 ' + + 'AND used_memory_delta >= 0 ' + + 'THEN ' + + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, used_memory_delta))) OVER() - LEN(CONVERT(VARCHAR, used_memory_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory_delta), 1), 19)) ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory_delta), 1), 19)) ' + ELSE 'used_memory_delta ' + END + + 'ELSE NULL ' + + 'END AS used_memory_delta, ' + ELSE '' + END + + --tasks + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tasks))) OVER() - LEN(CONVERT(VARCHAR, tasks))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tasks), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tasks), 1), 19)) ' + ELSE '' + END + 'tasks, ' + + 'status, ' + + 'wait_info, ' + + 'locks, ' + + 'tran_start_time, ' + + 'LEFT(tran_log_writes, LEN(tran_log_writes) - 1) AS tran_log_writes, ' + + --open_tran_count + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, open_tran_count))) OVER() - LEN(CONVERT(VARCHAR, open_tran_count))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, open_tran_count), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, open_tran_count), 1), 19)) AS ' + ELSE '' + END + 'open_tran_count, ' + + --sql_command + CASE @format_output + WHEN 0 THEN 'REPLACE(REPLACE(CONVERT(NVARCHAR(MAX), sql_command), '''', '''') AS ' + ELSE '' + END + 'sql_command, ' + + --sql_text + CASE @format_output + WHEN 0 THEN 'REPLACE(REPLACE(CONVERT(NVARCHAR(MAX), sql_text), '''', '''') AS ' + ELSE '' + END + 'sql_text, ' + + 'query_plan, ' + + 'blocking_session_id, ' + + --blocked_session_count + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, blocked_session_count))) OVER() - LEN(CONVERT(VARCHAR, blocked_session_count))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, blocked_session_count), 1), 19)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, blocked_session_count), 1), 19)) AS ' + ELSE '' + END + 'blocked_session_count, ' + + --percent_complete + CASE @format_output + WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, CONVERT(MONEY, percent_complete), 2))) OVER() - LEN(CONVERT(VARCHAR, CONVERT(MONEY, percent_complete), 2))) + CONVERT(CHAR(22), CONVERT(MONEY, percent_complete), 2)) AS ' + WHEN 2 THEN 'CONVERT(VARCHAR, CONVERT(CHAR(22), CONVERT(MONEY, blocked_session_count), 1)) AS ' + ELSE '' + END + 'percent_complete, ' + + 'host_name, ' + + 'login_name, ' + + 'database_name, ' + + 'program_name, ' + + 'additional_info, ' + + 'start_time, ' + + 'login_time, ' + + 'CASE ' + + 'WHEN status = N''sleeping'' THEN NULL ' + + 'ELSE request_id ' + + 'END AS request_id, ' + + 'GETDATE() AS collection_time ' + --End inner column list + ) + + --Derived table and INSERT specification + CONVERT + ( + VARCHAR(MAX), + 'FROM ' + + '( ' + + 'SELECT TOP(2147483647) ' + + '*, ' + + 'CASE ' + + 'MAX ' + + '( ' + + 'LEN ' + + '( ' + + 'CONVERT ' + + '( ' + + 'VARCHAR, ' + + 'CASE ' + + 'WHEN elapsed_time < 0 THEN ' + + '(-1 * elapsed_time) / 86400 ' + + 'ELSE ' + + 'elapsed_time / 86400000 ' + + 'END ' + + ') ' + + ') ' + + ') OVER () ' + + 'WHEN 1 THEN 2 ' + + 'ELSE ' + + 'MAX ' + + '( ' + + 'LEN ' + + '( ' + + 'CONVERT ' + + '( ' + + 'VARCHAR, ' + + 'CASE ' + + 'WHEN elapsed_time < 0 THEN ' + + '(-1 * elapsed_time) / 86400 ' + + 'ELSE ' + + 'elapsed_time / 86400000 ' + + 'END ' + + ') ' + + ') ' + + ') OVER () ' + + 'END AS max_elapsed_length, ' + + CASE + WHEN @output_column_list LIKE '%|_delta|]%' ESCAPE '|' THEN + 'MAX(physical_io * recursion) OVER (PARTITION BY session_id, request_id) + ' + + 'MIN(physical_io * recursion) OVER (PARTITION BY session_id, request_id) AS physical_io_delta, ' + + 'MAX(reads * recursion) OVER (PARTITION BY session_id, request_id) + ' + + 'MIN(reads * recursion) OVER (PARTITION BY session_id, request_id) AS reads_delta, ' + + 'MAX(physical_reads * recursion) OVER (PARTITION BY session_id, request_id) + ' + + 'MIN(physical_reads * recursion) OVER (PARTITION BY session_id, request_id) AS physical_reads_delta, ' + + 'MAX(writes * recursion) OVER (PARTITION BY session_id, request_id) + ' + + 'MIN(writes * recursion) OVER (PARTITION BY session_id, request_id) AS writes_delta, ' + + 'MAX(tempdb_allocations * recursion) OVER (PARTITION BY session_id, request_id) + ' + + 'MIN(tempdb_allocations * recursion) OVER (PARTITION BY session_id, request_id) AS tempdb_allocations_delta, ' + + 'MAX(tempdb_current * recursion) OVER (PARTITION BY session_id, request_id) + ' + + 'MIN(tempdb_current * recursion) OVER (PARTITION BY session_id, request_id) AS tempdb_current_delta, ' + + 'MAX(CPU * recursion) OVER (PARTITION BY session_id, request_id) + ' + + 'MIN(CPU * recursion) OVER (PARTITION BY session_id, request_id) AS CPU_delta, ' + + 'MAX(thread_CPU_snapshot * recursion) OVER (PARTITION BY session_id, request_id) + ' + + 'MIN(thread_CPU_snapshot * recursion) OVER (PARTITION BY session_id, request_id) AS thread_CPU_delta, ' + + 'MAX(context_switches * recursion) OVER (PARTITION BY session_id, request_id) + ' + + 'MIN(context_switches * recursion) OVER (PARTITION BY session_id, request_id) AS context_switches_delta, ' + + 'MAX(used_memory * recursion) OVER (PARTITION BY session_id, request_id) + ' + + 'MIN(used_memory * recursion) OVER (PARTITION BY session_id, request_id) AS used_memory_delta, ' + + 'MIN(last_request_start_time) OVER (PARTITION BY session_id, request_id) AS first_request_start_time, ' + ELSE '' + END + + 'COUNT(*) OVER (PARTITION BY session_id, request_id) AS num_events ' + + 'FROM #sessions AS s1 ' + + CASE + WHEN @sort_order = '' THEN '' + ELSE + 'ORDER BY ' + + @sort_order + END + + ') AS s ' + + 'WHERE ' + + 's.recursion = 1 ' + + ') x ' + + 'OPTION (KEEPFIXED PLAN); ' + + '' + + CASE @return_schema + WHEN 1 THEN + 'SET @schema = ' + + '''CREATE TABLE ( '' + ' + + 'STUFF ' + + '( ' + + '( ' + + 'SELECT ' + + ''','' + ' + + 'QUOTENAME(COLUMN_NAME) + '' '' + ' + + 'DATA_TYPE + ' + + 'CASE ' + + 'WHEN DATA_TYPE LIKE ''%char'' THEN ''('' + COALESCE(NULLIF(CONVERT(VARCHAR, CHARACTER_MAXIMUM_LENGTH), ''-1''), ''max'') + '') '' ' + + 'ELSE '' '' ' + + 'END + ' + + 'CASE IS_NULLABLE ' + + 'WHEN ''NO'' THEN ''NOT '' ' + + 'ELSE '''' ' + + 'END + ''NULL'' AS [text()] ' + + 'FROM tempdb.INFORMATION_SCHEMA.COLUMNS ' + + 'WHERE ' + + 'TABLE_NAME = (SELECT name FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(''tempdb..#session_schema'')) ' + + 'ORDER BY ' + + 'ORDINAL_POSITION ' + + 'FOR XML ' + + 'PATH('''') ' + + '), + ' + + '1, ' + + '1, ' + + ''''' ' + + ') + ' + + ''')''; ' + ELSE '' + END + --End derived table and INSERT specification + ); + + SET @sql_n = CONVERT(NVARCHAR(MAX), @sql); + + EXEC sp_executesql + @sql_n, + N'@schema VARCHAR(MAX) OUTPUT', + @schema OUTPUT; +END; +GO diff --git a/sql-agent-get-alerts.sql b/sql-agent-get-alerts.sql new file mode 100644 index 0000000..d1c6b62 --- /dev/null +++ b/sql-agent-get-alerts.sql @@ -0,0 +1,10 @@ + +SELECT @@SERVERNAME AS servername + ,name + ,message_id + ,severity + ,enabled + ,delay_between_responses + ,include_event_description + ,has_notification +FROM msdb.dbo.sysalerts; diff --git a/sql-agent-get-failed-jobs.sql b/sql-agent-get-failed-jobs.sql new file mode 100644 index 0000000..b1383ae --- /dev/null +++ b/sql-agent-get-failed-jobs.sql @@ -0,0 +1,35 @@ + +DECLARE @ClusterName VARCHAR(128); + +SELECT @ClusterName = cluster_name +FROM master.sys.dm_hadr_cluster +WHERE LEFT(cluster_name, 1) LIKE '[a-z]'; + +SELECT @ClusterName AS clustername + ,@@SERVERNAME AS servername + ,DEFAULT_DOMAIN() as domain + ,j.name AS jobname + ,s.last_run_outcome + ,h.step_id + ,h.step_name + ,h.run_status + ,h.message AS err_msg + ,((SUBSTRING(CAST(h.run_date AS VARCHAR(8)), 5, 2) + '/' + + SUBSTRING(CAST(h.run_date AS VARCHAR(8)), 7, 2) + '/' + + SUBSTRING(CAST(h.run_date AS VARCHAR(8)), 1, 4) + ' ' + + SUBSTRING((REPLICATE('0',6-LEN(CAST(h.run_time AS varchar))) + + CAST(h.run_time AS VARCHAR)), 1, 2) + ':' + + SUBSTRING((REPLICATE('0',6-LEN(CAST(h.run_time AS VARCHAR))) + + CAST(h.run_time AS VARCHAR)), 3, 2) + ':' + + SUBSTRING((REPLICATE('0',6-LEN(CAST(h.run_time as varchar))) + + CAST(h.run_time AS VARCHAR)), 5, 2))) AS exec_date + ,h.run_duration + ,s.retry_attempts AS step_retry_attempts + ,h.retries_attempted + ,s.output_file_name + ,s.on_fail_action AS step_on_fail_action +FROM msdb..sysjobs j + JOIN msdb..sysjobsteps s ON j.job_id = s.job_id + JOIN msdb..sysjobhistory h ON s.job_id = h.job_id AND s.step_id = h.step_id +WHERE h.run_status = 0; + diff --git a/sql-agent-get-job-schedules.sql b/sql-agent-get-job-schedules.sql new file mode 100644 index 0000000..bde8f6c --- /dev/null +++ b/sql-agent-get-job-schedules.sql @@ -0,0 +1,17 @@ + +SELECT @@SERVERNAME AS servername + ,j.name AS jobname + ,s.name AS schedulename + ,s.enabled + ,s.freq_type + ,s.freq_interval + ,s.freq_subday_type + ,s.freq_subday_interval + ,s.freq_relative_interval + ,s.freq_recurrence_factor + ,s.active_start_date + ,s.active_start_time + ,s.active_end_time +FROM msdb..sysjobs j + INNER JOIN msdb..sysjobschedules js ON j.job_id = js.job_id + INNER JOIN msdb..sysschedules s ON js.schedule_id = s.schedule_id; diff --git a/sql-agent-get-job-steps.sql b/sql-agent-get-job-steps.sql new file mode 100644 index 0000000..b745ef2 --- /dev/null +++ b/sql-agent-get-job-steps.sql @@ -0,0 +1,20 @@ + +SELECT @@SERVERNAME AS servername + ,j.name AS jobname + ,js.step_id + ,js.step_name + ,js.subsystem + ,js.command + ,js.on_success_action + ,js.on_success_step_id + ,js.on_fail_action + ,js.on_fail_step_id + ,js.database_name + ,js.database_user_name + ,js.retry_attempts + ,js.retry_interval + ,js.output_file_name + ,CASE WHEN j.start_step_id = js.step_id THEN 1 ELSE 0 END AS start_step_id +FROM msdb..sysjobs j + INNER JOIN msdb..sysjobsteps js ON j.job_id = js.job_id; + diff --git a/server-info/sql-agent-job-hist.sql b/sql-agent-job-get-hist.sql similarity index 98% rename from server-info/sql-agent-job-hist.sql rename to sql-agent-job-get-hist.sql index 3471d76..7568d28 100644 --- a/server-info/sql-agent-job-hist.sql +++ b/sql-agent-job-get-hist.sql @@ -1,211 +1,211 @@ -DECLARE @ShowDisabledJobs BIT = 0 - ,@ShowLastNumHours INT = NULL - ,@ExecDateCutOff DATETIME; - ---SET @ShowLastNumHours = 24; /* Pull just the last 24 hours */ - -IF @ShowLastNumHours IS NOT NULL - SET @ExecDateCutOff = DATEADD(HOUR, -1 * @ShowLastNumHours, GETDATE()); - -DECLARE @jobHistory TABLE ( - job_id UNIQUEIDENTIFIER - ,executions INT - ,success INT - ,cancel INT - ,fail INT - ,retry INT - ,last_execution_id INT - ,last_duration CHAR(8) - ,last_execution_start DATETIME - ,avg_duration CHAR(8) -); - -WITH lastExecution AS ( - SELECT job_id - ,MAX(instance_id) AS last_instance_id - FROM msdb.dbo.sysjobhistory - WHERE step_id = 0 - GROUP BY job_id -) - -INSERT INTO @jobHistory ( - job_id - ,executions - ,success - ,cancel - ,fail - ,retry - ,last_execution_id - ,last_duration - ,last_execution_start - ,avg_duration -) -SELECT sjh.job_id - ,SUM(CASE WHEN sjh.step_id = 0 THEN 1 ELSE 0 END) AS executions - ,SUM(CASE WHEN sjh.run_status = 1 AND sjh.step_id = 0 THEN 1 ELSE 0 END) AS success - ,SUM(CASE WHEN sjh.run_status = 3 AND sjh.step_id = 0 THEN 1 ELSE 0 END) AS cancel - ,SUM(CASE WHEN sjh.run_status = 0 AND sjh.step_id = 0 THEN 1 ELSE 0 END) AS fail - ,SUM(CASE WHEN sjh.run_status = 2 THEN 1 ELSE 0 END) AS retry - ,MAX(CASE WHEN sjh.step_id = 0 THEN sjh.instance_id ELSE NULL END) AS last_execution_id - ,SUBSTRING( - CAST(MAX(CASE WHEN le.job_id IS NOT NULL THEN sjh.run_duration ELSE NULL END) + 1000000 AS VARCHAR(7)) - ,2, 2 - ) + ':' - + SUBSTRING( - CAST(MAX(CASE WHEN le.job_id IS NOT NULL THEN sjh.run_duration ELSE NULL END) + 1000000 AS VARCHAR(7)) - ,4, 2 - ) + ':' - + SUBSTRING( - CAST(MAX(CASE WHEN le.job_id IS NOT NULL THEN sjh.run_duration ELSE NULL END) + 1000000 AS VARCHAR(7)) - ,6, 2 - ) AS last_duration - ,MAX( CASE WHEN le.last_instance_id IS NOT NULL THEN - CONVERT(DATETIME, RTRIM(sjh.run_date)) - + ((sjh.run_time / 10000 * 3600) + ((sjh.run_time % 10000) / 100 * 60) + (sjh.run_time % 10000) - % 100 - ) / (86399.9964) - ELSE '1900-01-01' - END - ) AS last_execution_start - ,SUBSTRING(CAST(AVG(sjh.run_duration) + 1000000 AS VARCHAR(7)), 2, 2) + ':' - + SUBSTRING(CAST(AVG(sjh.run_duration) + 1000000 AS VARCHAR(7)), 4, 2) + ':' - + SUBSTRING(CAST(AVG(sjh.run_duration) + 1000000 AS VARCHAR(7)), 6, 2) AS avg_duration -FROM msdb.dbo.sysjobhistory AS sjh - LEFT JOIN lastExecution AS le - ON sjh.job_id = le.job_id - AND sjh.instance_id = le.last_instance_id -GROUP BY sjh.job_id; - -/* We need to parse the schedule into something we can understand */ -DECLARE @weekDay TABLE (mask INT, maskValue VARCHAR(32)); - -INSERT INTO @weekDay -SELECT 1,'Su' -UNION ALL -SELECT 2,'M' -UNION ALL -SELECT 4,'Tu' -UNION ALL -SELECT 8,'W' -UNION ALL -SELECT 16,'Th' -UNION ALL -SELECT 32,'F' -UNION ALL -SELECT 64,'Sa'; - - -/* Now let's get our schedule information */ -WITH myCTE AS ( - SELECT sched.name AS scheduleName - ,sched.schedule_id - ,jobsched.job_id - ,CASE WHEN sched.freq_type = 1 THEN 'Once' - WHEN sched.freq_type = 4 - AND sched.freq_interval = 1 THEN 'Daily' - WHEN sched.freq_type = 4 THEN 'Every ' + CAST(sched.freq_interval AS VARCHAR(5)) + ' days' - WHEN sched.freq_type = 8 THEN - REPLACE( - REPLACE(REPLACE(( - SELECT x.maskValue - FROM @weekDay AS x - WHERE sched.freq_interval & x.mask <> 0 - ORDER BY mask - FOR XML RAW - ), '"/>', '' - ) - + CASE WHEN sched.freq_recurrence_factor <> 0 - AND sched.freq_recurrence_factor = 1 THEN '; wkly' - WHEN sched.freq_recurrence_factor <> 0 THEN - '; every ' + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' wks' - END - WHEN sched.freq_type = 16 THEN - 'On day ' + CAST(sched.freq_interval AS VARCHAR(10)) + ' of every ' - + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' months' - WHEN sched.freq_type = 32 THEN - CASE WHEN sched.freq_relative_interval = 1 THEN '1st' - WHEN sched.freq_relative_interval = 2 THEN '2nd' - WHEN sched.freq_relative_interval = 4 THEN '3rd' - WHEN sched.freq_relative_interval = 8 THEN '4th' - WHEN sched.freq_relative_interval = 16 THEN 'Last' - END + CASE WHEN sched.freq_interval = 1 THEN ' Su' - WHEN sched.freq_interval = 2 THEN ' M' - WHEN sched.freq_interval = 3 THEN ' Tu' - WHEN sched.freq_interval = 4 THEN ' W' - WHEN sched.freq_interval = 5 THEN ' Th' - WHEN sched.freq_interval = 6 THEN ' F' - WHEN sched.freq_interval = 7 THEN ' Sa' - WHEN sched.freq_interval = 8 THEN ' Day' - WHEN sched.freq_interval = 9 THEN ' Wkday' - WHEN sched.freq_interval = 10 THEN ' Wkend' - END - + CASE WHEN sched.freq_recurrence_factor <> 0 - AND sched.freq_recurrence_factor = 1 THEN '; monthly' - WHEN sched.freq_recurrence_factor <> 0 THEN - '; every ' + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' months' - END - WHEN sched.freq_type = 64 THEN 'StartUp' - WHEN sched.freq_type = 128 THEN 'Idle' - END AS frequency - ,ISNULL( - 'Every ' + CAST(sched.freq_subday_interval AS VARCHAR(10)) - + CASE WHEN sched.freq_subday_type = 2 THEN ' secs' - WHEN sched.freq_subday_type = 4 THEN ' mins' - WHEN sched.freq_subday_type = 8 THEN ' hrs' - END, 'Once' - ) AS subFrequency - ,REPLICATE('0', 6 - LEN(sched.active_start_time)) + CAST(sched.active_start_time AS VARCHAR(6)) AS startTime - ,REPLICATE('0', 6 - LEN(sched.active_end_time)) + CAST(sched.active_end_time AS VARCHAR(6)) AS endTime - ,REPLICATE('0', 6 - LEN(jobsched.next_run_time)) + CAST(jobsched.next_run_time AS VARCHAR(6)) AS nextRunTime - ,CAST(jobsched.next_run_date AS CHAR(8)) AS nextRunDate - FROM msdb.dbo.sysschedules AS sched - JOIN msdb.dbo.sysjobschedules AS jobsched - ON sched.schedule_id = jobsched.schedule_id - WHERE sched.enabled = 1 -) - -/* Finally, let's look at our actual jobs and tie it all together */ -SELECT CONVERT(NVARCHAR(128), SERVERPROPERTY('Servername')) AS serverName - ,job.job_id AS jobID - ,job.name AS jobName - ,CASE WHEN job.enabled = 1 THEN 'Enabled' - ELSE 'Disabled' - END AS jobStatus - ,COALESCE(sched.scheduleName, '(unscheduled)') AS scheduleName - ,COALESCE(sched.frequency, '') AS frequency - ,COALESCE(sched.subFrequency, '') AS subFrequency - ,COALESCE( - SUBSTRING(sched.startTime, 1, 2) + ':' + SUBSTRING(sched.startTime, 3, 2) + ' - ' - + SUBSTRING(sched.endTime, 1, 2) + ':' + SUBSTRING(sched.endTime, 3, 2), '' - ) AS scheduleTime -- HH:MM - ,COALESCE( - SUBSTRING(sched.nextRunDate, 1, 4) + '/' + SUBSTRING(sched.nextRunDate, 5, 2) + '/' - + SUBSTRING(sched.nextRunDate, 7, 2) + ' ' + SUBSTRING(sched.nextRunTime, 1, 2) + ':' - + SUBSTRING(sched.nextRunTime, 3, 2), '' - ) AS nextRunDate - /* Note: the sysjobschedules table refreshes every 20 min, so nextRunDate may be out of date */ - ,COALESCE(jh.executions, 0) AS executions - ,COALESCE(jh.success, 0) AS success - ,COALESCE(jh.cancel, 0) AS cancel - ,COALESCE(jh.fail, 0) AS fail - ,COALESCE(jh.retry, 0) AS retry - ,COALESCE(jh.last_execution_id, 0) AS lastExecutionID - ,jh.last_execution_start AS lastExecutionStart - ,COALESCE(jh.last_duration, '00:00:01') AS lastDuration - ,COALESCE(jh.avg_duration, '00:00:01') AS avgDuration - ,'EXECUTE msdb.dbo.sp_update_job @job_id = ''' + CAST(job.job_id AS CHAR(36)) + ''', @enabled = 0;' AS disableSQLScript -FROM msdb.dbo.sysjobs AS job - LEFT JOIN myCTE AS sched - ON job.job_id = sched.job_id - LEFT JOIN @jobHistory AS jh - ON job.job_id = jh.job_id -WHERE ( - CASE WHEN @ShowDisabledJobs = 0 THEN 1 - END = job.enabled - OR @ShowDisabledJobs = 1 - ) -AND (jh.last_execution_start >= @ExecDateCutOff OR @ExecDateCutOff IS NULL) -ORDER BY job.name +DECLARE @ShowDisabledJobs BIT = 0 + ,@ShowLastNumHours INT = NULL + ,@ExecDateCutOff DATETIME; + +--SET @ShowLastNumHours = 24; /* Pull just the last 24 hours */ + +IF @ShowLastNumHours IS NOT NULL + SET @ExecDateCutOff = DATEADD(HOUR, -1 * @ShowLastNumHours, GETDATE()); + +DECLARE @jobHistory TABLE ( + job_id UNIQUEIDENTIFIER + ,executions INT + ,success INT + ,cancel INT + ,fail INT + ,retry INT + ,last_execution_id INT + ,last_duration CHAR(8) + ,last_execution_start DATETIME + ,avg_duration CHAR(8) +); + +WITH lastExecution AS ( + SELECT job_id + ,MAX(instance_id) AS last_instance_id + FROM msdb.dbo.sysjobhistory + WHERE step_id = 0 + GROUP BY job_id +) + +INSERT INTO @jobHistory ( + job_id + ,executions + ,success + ,cancel + ,fail + ,retry + ,last_execution_id + ,last_duration + ,last_execution_start + ,avg_duration +) +SELECT sjh.job_id + ,SUM(CASE WHEN sjh.step_id = 0 THEN 1 ELSE 0 END) AS executions + ,SUM(CASE WHEN sjh.run_status = 1 AND sjh.step_id = 0 THEN 1 ELSE 0 END) AS success + ,SUM(CASE WHEN sjh.run_status = 3 AND sjh.step_id = 0 THEN 1 ELSE 0 END) AS cancel + ,SUM(CASE WHEN sjh.run_status = 0 AND sjh.step_id = 0 THEN 1 ELSE 0 END) AS fail + ,SUM(CASE WHEN sjh.run_status = 2 THEN 1 ELSE 0 END) AS retry + ,MAX(CASE WHEN sjh.step_id = 0 THEN sjh.instance_id ELSE NULL END) AS last_execution_id + ,SUBSTRING( + CAST(MAX(CASE WHEN le.job_id IS NOT NULL THEN sjh.run_duration ELSE NULL END) + 1000000 AS VARCHAR(7)) + ,2, 2 + ) + ':' + + SUBSTRING( + CAST(MAX(CASE WHEN le.job_id IS NOT NULL THEN sjh.run_duration ELSE NULL END) + 1000000 AS VARCHAR(7)) + ,4, 2 + ) + ':' + + SUBSTRING( + CAST(MAX(CASE WHEN le.job_id IS NOT NULL THEN sjh.run_duration ELSE NULL END) + 1000000 AS VARCHAR(7)) + ,6, 2 + ) AS last_duration + ,MAX( CASE WHEN le.last_instance_id IS NOT NULL THEN + CONVERT(DATETIME, RTRIM(sjh.run_date)) + + ((sjh.run_time / 10000 * 3600) + ((sjh.run_time % 10000) / 100 * 60) + (sjh.run_time % 10000) + % 100 + ) / (86399.9964) + ELSE '1900-01-01' + END + ) AS last_execution_start + ,SUBSTRING(CAST(AVG(sjh.run_duration) + 1000000 AS VARCHAR(7)), 2, 2) + ':' + + SUBSTRING(CAST(AVG(sjh.run_duration) + 1000000 AS VARCHAR(7)), 4, 2) + ':' + + SUBSTRING(CAST(AVG(sjh.run_duration) + 1000000 AS VARCHAR(7)), 6, 2) AS avg_duration +FROM msdb.dbo.sysjobhistory AS sjh + LEFT JOIN lastExecution AS le + ON sjh.job_id = le.job_id + AND sjh.instance_id = le.last_instance_id +GROUP BY sjh.job_id; + +/* We need to parse the schedule into something we can understand */ +DECLARE @weekDay TABLE (mask INT, maskValue VARCHAR(32)); + +INSERT INTO @weekDay +SELECT 1,'Su' +UNION ALL +SELECT 2,'M' +UNION ALL +SELECT 4,'Tu' +UNION ALL +SELECT 8,'W' +UNION ALL +SELECT 16,'Th' +UNION ALL +SELECT 32,'F' +UNION ALL +SELECT 64,'Sa'; + + +/* Now let's get our schedule information */ +WITH myCTE AS ( + SELECT sched.name AS scheduleName + ,sched.schedule_id + ,jobsched.job_id + ,CASE WHEN sched.freq_type = 1 THEN 'Once' + WHEN sched.freq_type = 4 + AND sched.freq_interval = 1 THEN 'Daily' + WHEN sched.freq_type = 4 THEN 'Every ' + CAST(sched.freq_interval AS VARCHAR(5)) + ' days' + WHEN sched.freq_type = 8 THEN + REPLACE( + REPLACE(REPLACE(( + SELECT x.maskValue + FROM @weekDay AS x + WHERE sched.freq_interval & x.mask <> 0 + ORDER BY mask + FOR XML RAW + ), '"/>', '' + ) + + CASE WHEN sched.freq_recurrence_factor <> 0 + AND sched.freq_recurrence_factor = 1 THEN '; wkly' + WHEN sched.freq_recurrence_factor <> 0 THEN + '; every ' + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' wks' + END + WHEN sched.freq_type = 16 THEN + 'On day ' + CAST(sched.freq_interval AS VARCHAR(10)) + ' of every ' + + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' months' + WHEN sched.freq_type = 32 THEN + CASE WHEN sched.freq_relative_interval = 1 THEN '1st' + WHEN sched.freq_relative_interval = 2 THEN '2nd' + WHEN sched.freq_relative_interval = 4 THEN '3rd' + WHEN sched.freq_relative_interval = 8 THEN '4th' + WHEN sched.freq_relative_interval = 16 THEN 'Last' + END + CASE WHEN sched.freq_interval = 1 THEN ' Su' + WHEN sched.freq_interval = 2 THEN ' M' + WHEN sched.freq_interval = 3 THEN ' Tu' + WHEN sched.freq_interval = 4 THEN ' W' + WHEN sched.freq_interval = 5 THEN ' Th' + WHEN sched.freq_interval = 6 THEN ' F' + WHEN sched.freq_interval = 7 THEN ' Sa' + WHEN sched.freq_interval = 8 THEN ' Day' + WHEN sched.freq_interval = 9 THEN ' Wkday' + WHEN sched.freq_interval = 10 THEN ' Wkend' + END + + CASE WHEN sched.freq_recurrence_factor <> 0 + AND sched.freq_recurrence_factor = 1 THEN '; monthly' + WHEN sched.freq_recurrence_factor <> 0 THEN + '; every ' + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' months' + END + WHEN sched.freq_type = 64 THEN 'StartUp' + WHEN sched.freq_type = 128 THEN 'Idle' + END AS frequency + ,ISNULL( + 'Every ' + CAST(sched.freq_subday_interval AS VARCHAR(10)) + + CASE WHEN sched.freq_subday_type = 2 THEN ' secs' + WHEN sched.freq_subday_type = 4 THEN ' mins' + WHEN sched.freq_subday_type = 8 THEN ' hrs' + END, 'Once' + ) AS subFrequency + ,REPLICATE('0', 6 - LEN(sched.active_start_time)) + CAST(sched.active_start_time AS VARCHAR(6)) AS startTime + ,REPLICATE('0', 6 - LEN(sched.active_end_time)) + CAST(sched.active_end_time AS VARCHAR(6)) AS endTime + ,REPLICATE('0', 6 - LEN(jobsched.next_run_time)) + CAST(jobsched.next_run_time AS VARCHAR(6)) AS nextRunTime + ,CAST(jobsched.next_run_date AS CHAR(8)) AS nextRunDate + FROM msdb.dbo.sysschedules AS sched + JOIN msdb.dbo.sysjobschedules AS jobsched + ON sched.schedule_id = jobsched.schedule_id + WHERE sched.enabled = 1 +) + +/* Finally, let's look at our actual jobs and tie it all together */ +SELECT CONVERT(NVARCHAR(128), SERVERPROPERTY('Servername')) AS serverName + ,job.job_id AS jobID + ,job.name AS jobName + ,CASE WHEN job.enabled = 1 THEN 'Enabled' + ELSE 'Disabled' + END AS jobStatus + ,COALESCE(sched.scheduleName, '(unscheduled)') AS scheduleName + ,COALESCE(sched.frequency, '') AS frequency + ,COALESCE(sched.subFrequency, '') AS subFrequency + ,COALESCE( + SUBSTRING(sched.startTime, 1, 2) + ':' + SUBSTRING(sched.startTime, 3, 2) + ' - ' + + SUBSTRING(sched.endTime, 1, 2) + ':' + SUBSTRING(sched.endTime, 3, 2), '' + ) AS scheduleTime -- HH:MM + ,COALESCE( + SUBSTRING(sched.nextRunDate, 1, 4) + '/' + SUBSTRING(sched.nextRunDate, 5, 2) + '/' + + SUBSTRING(sched.nextRunDate, 7, 2) + ' ' + SUBSTRING(sched.nextRunTime, 1, 2) + ':' + + SUBSTRING(sched.nextRunTime, 3, 2), '' + ) AS nextRunDate + /* Note: the sysjobschedules table refreshes every 20 min, so nextRunDate may be out of date */ + ,COALESCE(jh.executions, 0) AS executions + ,COALESCE(jh.success, 0) AS success + ,COALESCE(jh.cancel, 0) AS cancel + ,COALESCE(jh.fail, 0) AS fail + ,COALESCE(jh.retry, 0) AS retry + ,COALESCE(jh.last_execution_id, 0) AS lastExecutionID + ,jh.last_execution_start AS lastExecutionStart + ,COALESCE(jh.last_duration, '00:00:01') AS lastDuration + ,COALESCE(jh.avg_duration, '00:00:01') AS avgDuration + ,'EXECUTE msdb.dbo.sp_update_job @job_id = ''' + CAST(job.job_id AS CHAR(36)) + ''', @enabled = 0;' AS disableSQLScript +FROM msdb.dbo.sysjobs AS job + LEFT JOIN myCTE AS sched + ON job.job_id = sched.job_id + LEFT JOIN @jobHistory AS jh + ON job.job_id = jh.job_id +WHERE ( + CASE WHEN @ShowDisabledJobs = 0 THEN 1 + END = job.enabled + OR @ShowDisabledJobs = 1 + ) +AND (jh.last_execution_start >= @ExecDateCutOff OR @ExecDateCutOff IS NULL) +ORDER BY job.name ,jh.last_execution_start; \ No newline at end of file diff --git a/server-info/sql-agent-job-list.sql b/sql-agent-job-get-list.sql similarity index 91% rename from server-info/sql-agent-job-list.sql rename to sql-agent-job-get-list.sql index 9c05b9b..da844d5 100644 --- a/server-info/sql-agent-job-list.sql +++ b/sql-agent-job-get-list.sql @@ -1,258 +1,258 @@ - --- Query to display schedules of jobs. --- copied from http://www.sqlservercentral.com/scripts/Maintenance+and+Management/62222/ --- posted there by "Cowboy DBA" --- ---------- --- Revised 3/21/08 John Arnott --- added default "ELSE" to case that would put plural "S" in schedule description. (find comment " -- Added default 3/21/08; John Arnott" --- Revised 6/19/08 John Arnott --- re-coded the time parsing routines. Old code didn't handle first hour of the day (00:04, for instance). --- new code uses division by power of 10 to isolate hour, then minute portion of time, --- then a little trick with REPLICATE to left-fill the minutes with a zero if needed. --- Revised 11022012 - neh - replaced @@servername with SERVERPROPERTY('ServerName') --- - added [JobEnabled] --- - added criteria to eliminate disabled schedules --- - modified column aliases --- - modified ORDER BY --- - modified Schedule logic --- Revised 09132016 - neh - modified JOIN syntax to scheduling tables - -DECLARE @LastModDate DATETIME --= '11/1/2016' - , @Enabled BIT --= 1; -- NULL returns both Enabled & Disabled jobs - -SELECT SERVERPROPERTY ('ServerName') as [Server] - , msdb.dbo.sysjobs.name as [Job] - , [JobSteps] = stepcount - , [Enabled] = CASE msdb.dbo.sysjobs.[enabled] - WHEN 1 THEN 'x' - ELSE '' - END - , [Schedule] = - CASE WHEN msdb.dbo.sysjobs.[enabled] = 0 - THEN 'Disabled' - WHEN msdb.dbo.sysjobs.job_id IS NULL - THEN 'Unscheduled' - WHEN msdb.dbo.sysschedules.freq_type = 0x1 -- OneTime - THEN 'Once on ' + CONVERT(CHAR(10), CAST(CAST(msdb.dbo.sysschedules.active_start_date AS VARCHAR)AS DATETIME), 101) - WHEN msdb.dbo.sysschedules.freq_type = 0x4 -- Daily - THEN 'Daily' - WHEN msdb.dbo.sysschedules.freq_type = 0x8 -- weekly - THEN CASE WHEN msdb.dbo.sysschedules.freq_recurrence_factor = 1 - THEN 'Wkly on ' - WHEN msdb.dbo.sysschedules.freq_recurrence_factor > 1 - THEN 'Every ' + CAST(msdb.dbo.sysschedules.freq_recurrence_factor AS VARCHAR) + ' wks on ' - END - + LEFT( - CASE WHEN msdb.dbo.sysschedules.freq_interval & 1 = 1 THEN 'Su, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 2 = 2 THEN 'M, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 4 = 4 THEN 'Tu, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 8 = 8 THEN 'W, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 16 = 16 THEN 'Th, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 32 = 32 THEN 'F, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 64 = 64 THEN 'Sa, ' ELSE '' END - , LEN( - CASE WHEN msdb.dbo.sysschedules.freq_interval & 1 = 1 THEN 'Su, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 2 = 2 THEN 'M, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 4 = 4 THEN 'Tu, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 8 = 8 THEN 'W, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 16 = 16 THEN 'Th, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 32 = 32 THEN 'F, ' ELSE '' END - + CASE WHEN msdb.dbo.sysschedules.freq_interval & 64 = 64 THEN 'Sa, ' ELSE '' END - ) - 1 -- LEN() ignores trailing spaces - ) - WHEN msdb.dbo.sysschedules.freq_type = 0x10 -- monthly - THEN CASE WHEN msdb.dbo.sysschedules.freq_recurrence_factor = 1 - THEN 'Mthly on the ' - WHEN msdb.dbo.sysschedules.freq_recurrence_factor > 1 - THEN 'Every ' + CAST(msdb.dbo.sysschedules.freq_recurrence_factor AS VARCHAR) + ' mo on the ' - END - + CAST(msdb.dbo.sysschedules.freq_interval AS VARCHAR) - + CASE WHEN msdb.dbo.sysschedules.freq_interval IN (1, 21, 31) - THEN 'st' - WHEN msdb.dbo.sysschedules.freq_interval IN (2, 22) - THEN 'nd' - WHEN msdb.dbo.sysschedules.freq_interval IN (3, 23) - THEN 'rd' - ELSE 'th' - END - WHEN msdb.dbo.sysschedules.freq_type = 0x20 -- monthly relative - THEN CASE WHEN msdb.dbo.sysschedules.freq_recurrence_factor = 1 - THEN 'Mthly on the ' - WHEN msdb.dbo.sysschedules.freq_recurrence_factor > 1 - THEN 'Every '+ CAST( msdb.dbo.sysschedules.freq_recurrence_factor AS VARCHAR )+ ' mths on the ' - END - + CASE msdb.dbo.sysschedules.freq_relative_interval - WHEN 0x01 THEN 'first ' - WHEN 0x02 THEN 'second ' - WHEN 0x04 THEN 'third ' - WHEN 0x08 THEN 'fourth ' - WHEN 0x10 THEN 'last ' - END - + CASE msdb.dbo.sysschedules.freq_interval - WHEN 1 THEN 'Su' - WHEN 2 THEN 'M' - WHEN 3 THEN 'Tu' - WHEN 4 THEN 'W' - WHEN 5 THEN 'Th' - WHEN 6 THEN 'F' - WHEN 7 THEN 'Sa' - WHEN 8 THEN 'day' - WHEN 9 THEN 'wk day' - WHEN 10 THEN 'wknd day' - END - WHEN msdb.dbo.sysschedules.freq_type = 0x40 - THEN 'Auto start when SQLServerAgent starts' - WHEN msdb.dbo.sysschedules.freq_type = 0x80 - THEN 'Starts whenever CPUs become idle' - ELSE '' - END - + CASE WHEN msdb.dbo.sysjobs.[enabled] = 0 - THEN '' - WHEN msdb.dbo.sysjobs.job_id IS NULL - THEN '' - WHEN msdb.dbo.sysschedules.freq_subday_type = 0x1 - OR msdb.dbo.sysschedules.freq_type = 0x1 - THEN ' at ' - + CASE -- Depends on time being integer to drop right-side digits - WHEN(msdb.dbo.sysschedules.active_start_time % 1000000)/10000 = 0 - THEN '12' - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) - + CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100) - + ' AM' - WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000< 10 - THEN CONVERT(CHAR(1),(msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) - + CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100) - + ' AM' - WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000 < 12 - THEN CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) - + CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100) - + ' AM' - WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000< 22 - THEN CONVERT(CHAR(1),((msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - 12) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) - + CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100) - + ' PM' - ELSE CONVERT(CHAR(2),((msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - 12) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) - + CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100) - + ' PM' - END - WHEN msdb.dbo.sysschedules.freq_subday_type IN (0x2, 0x4, 0x8) - THEN ' every ' - + CAST(msdb.dbo.sysschedules.freq_subday_interval AS VARCHAR) - + CASE freq_subday_type - WHEN 0x2 - THEN ' sec' - WHEN 0x4 - THEN ' min' - WHEN 0x8 - THEN ' hr' - END - + CASE - WHEN msdb.dbo.sysschedules.freq_subday_interval > 1 - THEN 's' - ELSE '' -- Added default 3/21/08; John Arnott - END - ELSE '' - END - + CASE WHEN msdb.dbo.sysjobs.[enabled] = 0 - THEN '' - WHEN msdb.dbo.sysjobs.job_id IS NULL - THEN '' - WHEN msdb.dbo.sysschedules.freq_subday_type IN (0x2, 0x4, 0x8) - THEN ' btw ' - + CASE -- Depends on time being integer to drop right-side digits - WHEN(msdb.dbo.sysschedules.active_start_time % 1000000)/10000 = 0 - THEN '12' - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) - + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100)) - + ' AM' - WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000< 10 - THEN CONVERT(CHAR(1),(msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) - + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100)) - + ' AM' - WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000 < 12 - THEN CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) - + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100)) - + ' AM' - WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000< 22 - THEN CONVERT(CHAR(1),((msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - 12) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) - + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100)) - + ' PM' - ELSE CONVERT(CHAR(2),((msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - 12) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) - + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100)) - + ' PM' - END - + ' and ' - + CASE -- Depends on time being integer to drop right-side digits - WHEN (msdb.dbo.sysschedules.active_end_time % 1000000)/10000 = 0 - THEN '12' - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100))) - + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100)) - + ' AM' - WHEN (msdb.dbo.sysschedules.active_end_time % 1000000)/10000< 10 - THEN CONVERT(CHAR(1),(msdb.dbo.sysschedules.active_end_time % 1000000)/10000) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100))) - + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100)) - + ' AM' - WHEN (msdb.dbo.sysschedules.active_end_time % 1000000)/10000 < 12 - THEN CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 1000000)/10000) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100))) - + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100)) - + ' AM' - WHEN (msdb.dbo.sysschedules.active_end_time % 1000000)/10000< 22 - THEN CONVERT(CHAR(1),((msdb.dbo.sysschedules.active_end_time % 1000000)/10000) - 12) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100))) - + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100)) - + ' PM' - ELSE CONVERT(CHAR(2),((msdb.dbo.sysschedules.active_end_time % 1000000)/10000) - 12) - + ':' - + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100))) - + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100)) - + ' PM' - END - ELSE '' - END - , [OnFailureNotify] = CASE WHEN msdb.dbo.sysjobs.notify_level_email = 2 THEN msdb.dbo.sysoperators.name ELSE '' END - , [Description] = msdb.dbo.sysjobs.[description] - , [OutputFile] = CASE WHEN l.LogCount != 1 THEN 'Check Logs' - ELSE l.LogPath - END -FROM msdb.dbo.sysjobs - LEFT OUTER JOIN msdb.dbo.sysjobschedules ON msdb.dbo.sysjobs.job_id = msdb.dbo.sysjobschedules.job_id - LEFT OUTER JOIN msdb.dbo.sysschedules - ON msdb.dbo.sysjobschedules.schedule_id = msdb.dbo.sysschedules.schedule_id - AND msdb.dbo.sysschedules.[enabled] = ISNULL(@Enabled,msdb.dbo.sysschedules.[enabled]) - LEFT OUTER JOIN msdb.dbo.sysoperators ON msdb.dbo.sysjobs.notify_email_operator_id = msdb.dbo.sysoperators.id - LEFT OUTER JOIN ( - SELECT job_id - ,StepCount = COUNT(*) - ,LogCount = COUNT(DISTINCT output_file_name) - ,LogPath = MAX(output_file_name) - FROM msdb.dbo.sysjobsteps - --WHERE subsystem = 'TSQL' - GROUP BY job_id - ) l ON l.job_id = sysjobs.job_id -WHERE msdb.dbo.sysjobs.date_modified >= ISNULL(@LastModDate,msdb.dbo.sysjobs.date_modified) -ORDER BY msdb.dbo.sysjobs.name - , msdb.dbo.sysschedules.freq_type + +-- Query to display schedules of jobs. +-- copied from http://www.sqlservercentral.com/scripts/Maintenance+and+Management/62222/ +-- posted there by "Cowboy DBA" +-- ---------- + +DECLARE @LastModDate DATETIME --= '11/1/2016' + , @Enabled BIT --= 1; -- NULL returns both Enabled & Disabled jobs + +SELECT SERVERPROPERTY ('ServerName') as [Server] + , msdb.dbo.sysjobs.name as [Job] + , [JobSteps] = stepcount + , [Enabled] = CASE msdb.dbo.sysjobs.[enabled] WHEN 1 THEN 'Y' ELSE 'N' END + , [StartStepId] = msdb.dbo.sysjobs.start_step_id + , [Schedule] = + CASE WHEN msdb.dbo.sysjobs.[enabled] = 0 + THEN 'Disabled' + WHEN msdb.dbo.sysjobs.job_id IS NULL + THEN 'Unscheduled' + WHEN msdb.dbo.sysschedules.freq_type = 0x1 -- OneTime + THEN 'Once on ' + CONVERT(CHAR(10), CAST(CAST(msdb.dbo.sysschedules.active_start_date AS VARCHAR)AS DATETIME), 101) + WHEN msdb.dbo.sysschedules.freq_type = 0x4 -- Daily + THEN 'Daily' + WHEN msdb.dbo.sysschedules.freq_type = 0x8 -- weekly + THEN CASE WHEN msdb.dbo.sysschedules.freq_recurrence_factor = 1 + THEN 'Wkly on ' + WHEN msdb.dbo.sysschedules.freq_recurrence_factor > 1 + THEN 'Every ' + CAST(msdb.dbo.sysschedules.freq_recurrence_factor AS VARCHAR) + ' wks on ' + END + + LEFT( + CASE WHEN msdb.dbo.sysschedules.freq_interval & 1 = 1 THEN 'Su, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 2 = 2 THEN 'M, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 4 = 4 THEN 'Tu, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 8 = 8 THEN 'W, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 16 = 16 THEN 'Th, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 32 = 32 THEN 'F, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 64 = 64 THEN 'Sa, ' ELSE '' END + , LEN( + CASE WHEN msdb.dbo.sysschedules.freq_interval & 1 = 1 THEN 'Su, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 2 = 2 THEN 'M, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 4 = 4 THEN 'Tu, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 8 = 8 THEN 'W, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 16 = 16 THEN 'Th, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 32 = 32 THEN 'F, ' ELSE '' END + + CASE WHEN msdb.dbo.sysschedules.freq_interval & 64 = 64 THEN 'Sa, ' ELSE '' END + ) - 1 -- LEN() ignores trailing spaces + ) + WHEN msdb.dbo.sysschedules.freq_type = 0x10 -- monthly + THEN CASE WHEN msdb.dbo.sysschedules.freq_recurrence_factor = 1 + THEN 'Mthly on the ' + WHEN msdb.dbo.sysschedules.freq_recurrence_factor > 1 + THEN 'Every ' + CAST(msdb.dbo.sysschedules.freq_recurrence_factor AS VARCHAR) + ' mo on the ' + END + + CAST(msdb.dbo.sysschedules.freq_interval AS VARCHAR) + + CASE WHEN msdb.dbo.sysschedules.freq_interval IN (1, 21, 31) + THEN 'st' + WHEN msdb.dbo.sysschedules.freq_interval IN (2, 22) + THEN 'nd' + WHEN msdb.dbo.sysschedules.freq_interval IN (3, 23) + THEN 'rd' + ELSE 'th' + END + WHEN msdb.dbo.sysschedules.freq_type = 0x20 -- monthly relative + THEN CASE WHEN msdb.dbo.sysschedules.freq_recurrence_factor = 1 + THEN 'Mthly on the ' + WHEN msdb.dbo.sysschedules.freq_recurrence_factor > 1 + THEN 'Every '+ CAST( msdb.dbo.sysschedules.freq_recurrence_factor AS VARCHAR )+ ' mths on the ' + END + + CASE msdb.dbo.sysschedules.freq_relative_interval + WHEN 0x01 THEN 'first ' + WHEN 0x02 THEN 'second ' + WHEN 0x04 THEN 'third ' + WHEN 0x08 THEN 'fourth ' + WHEN 0x10 THEN 'last ' + END + + CASE msdb.dbo.sysschedules.freq_interval + WHEN 1 THEN 'Su' + WHEN 2 THEN 'M' + WHEN 3 THEN 'Tu' + WHEN 4 THEN 'W' + WHEN 5 THEN 'Th' + WHEN 6 THEN 'F' + WHEN 7 THEN 'Sa' + WHEN 8 THEN 'day' + WHEN 9 THEN 'wk day' + WHEN 10 THEN 'wknd day' + END + WHEN msdb.dbo.sysschedules.freq_type = 0x40 + THEN 'Auto start when SQLServerAgent starts' + WHEN msdb.dbo.sysschedules.freq_type = 0x80 + THEN 'Starts whenever CPUs become idle' + ELSE '' + END + + CASE WHEN msdb.dbo.sysjobs.[enabled] = 0 + THEN '' + WHEN msdb.dbo.sysjobs.job_id IS NULL + THEN '' + WHEN msdb.dbo.sysschedules.freq_subday_type = 0x1 + OR msdb.dbo.sysschedules.freq_type = 0x1 + THEN ' at ' + + CASE -- Depends on time being integer to drop right-side digits + WHEN(msdb.dbo.sysschedules.active_start_time % 1000000)/10000 = 0 + THEN '12' + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) + + CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100) + + ' AM' + WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000< 10 + THEN CONVERT(CHAR(1),(msdb.dbo.sysschedules.active_start_time % 1000000)/10000) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) + + CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100) + + ' AM' + WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000 < 12 + THEN CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 1000000)/10000) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) + + CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100) + + ' AM' + WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000< 22 + THEN CONVERT(CHAR(1),((msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - 12) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) + + CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100) + + ' PM' + ELSE CONVERT(CHAR(2),((msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - 12) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) + + CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100) + + ' PM' + END + WHEN msdb.dbo.sysschedules.freq_subday_type IN (0x2, 0x4, 0x8) + THEN ' every ' + + CAST(msdb.dbo.sysschedules.freq_subday_interval AS VARCHAR) + + CASE freq_subday_type + WHEN 0x2 + THEN ' sec' + WHEN 0x4 + THEN ' min' + WHEN 0x8 + THEN ' hr' + END + + CASE + WHEN msdb.dbo.sysschedules.freq_subday_interval > 1 + THEN 's' + ELSE '' -- Added default 3/21/08; John Arnott + END + ELSE '' + END + + CASE WHEN msdb.dbo.sysjobs.[enabled] = 0 + THEN '' + WHEN msdb.dbo.sysjobs.job_id IS NULL + THEN '' + WHEN msdb.dbo.sysschedules.freq_subday_type IN (0x2, 0x4, 0x8) + THEN ' btw ' + + CASE -- Depends on time being integer to drop right-side digits + WHEN(msdb.dbo.sysschedules.active_start_time % 1000000)/10000 = 0 + THEN '12' + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) + + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100)) + + ' AM' + WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000< 10 + THEN CONVERT(CHAR(1),(msdb.dbo.sysschedules.active_start_time % 1000000)/10000) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) + + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100)) + + ' AM' + WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000 < 12 + THEN CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 1000000)/10000) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) + + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100)) + + ' AM' + WHEN (msdb.dbo.sysschedules.active_start_time % 1000000)/10000< 22 + THEN CONVERT(CHAR(1),((msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - 12) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) + + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100)) + + ' PM' + ELSE CONVERT(CHAR(2),((msdb.dbo.sysschedules.active_start_time % 1000000)/10000) - 12) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100))) + + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_start_time % 10000)/100)) + + ' PM' + END + + ' and ' + + CASE -- Depends on time being integer to drop right-side digits + WHEN (msdb.dbo.sysschedules.active_end_time % 1000000)/10000 = 0 + THEN '12' + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100))) + + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100)) + + ' AM' + WHEN (msdb.dbo.sysschedules.active_end_time % 1000000)/10000< 10 + THEN CONVERT(CHAR(1),(msdb.dbo.sysschedules.active_end_time % 1000000)/10000) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100))) + + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100)) + + ' AM' + WHEN (msdb.dbo.sysschedules.active_end_time % 1000000)/10000 < 12 + THEN CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 1000000)/10000) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100))) + + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100)) + + ' AM' + WHEN (msdb.dbo.sysschedules.active_end_time % 1000000)/10000< 22 + THEN CONVERT(CHAR(1),((msdb.dbo.sysschedules.active_end_time % 1000000)/10000) - 12) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100))) + + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100)) + + ' PM' + ELSE CONVERT(CHAR(2),((msdb.dbo.sysschedules.active_end_time % 1000000)/10000) - 12) + + ':' + + REPLICATE('0',2 - LEN(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100))) + + RTRIM(CONVERT(CHAR(2),(msdb.dbo.sysschedules.active_end_time % 10000)/100)) + + ' PM' + END + ELSE '' + END + , [Notify_Level_Eventlog] = + CASE msdb.dbo.sysjobs.notify_level_eventlog + WHEN 0 THEN 'Never' + WHEN 1 THEN 'When the job succeeds' + WHEN 2 THEN 'When the job fails' + WHEN 3 THEN 'When the job completes' + END + , [Notify_Level_Email] = + CASE msdb.dbo.sysjobs.notify_level_email + WHEN 0 THEN 'Never' + WHEN 1 THEN 'When the job succeeds' + WHEN 2 THEN 'When the job fails' + WHEN 3 THEN 'When the job completes' + END + , [OnFailureNotify] = CASE WHEN msdb.dbo.sysjobs.notify_level_email = 2 THEN msdb.dbo.sysoperators.name ELSE '' END + , [OperatorEmail] = msdb.dbo.sysoperators.email_address + , [Description] = msdb.dbo.sysjobs.[description] + , [OutputFile] = CASE WHEN l.LogCount != 1 THEN 'Check Logs' + ELSE l.LogPath + END +FROM msdb.dbo.sysjobs + LEFT OUTER JOIN msdb.dbo.sysjobschedules ON msdb.dbo.sysjobs.job_id = msdb.dbo.sysjobschedules.job_id + LEFT OUTER JOIN msdb.dbo.sysschedules + ON msdb.dbo.sysjobschedules.schedule_id = msdb.dbo.sysschedules.schedule_id + AND msdb.dbo.sysschedules.[enabled] = ISNULL(@Enabled,msdb.dbo.sysschedules.[enabled]) + LEFT OUTER JOIN msdb.dbo.sysoperators ON msdb.dbo.sysjobs.notify_email_operator_id = msdb.dbo.sysoperators.id + LEFT OUTER JOIN ( + SELECT job_id + ,StepCount = COUNT(*) + ,LogCount = COUNT(DISTINCT output_file_name) + ,LogPath = MAX(output_file_name) + FROM msdb.dbo.sysjobsteps + --WHERE subsystem = 'TSQL' + GROUP BY job_id + ) l ON l.job_id = sysjobs.job_id +WHERE msdb.dbo.sysjobs.date_modified >= ISNULL(@LastModDate,msdb.dbo.sysjobs.date_modified) +ORDER BY msdb.dbo.sysjobs.name + , msdb.dbo.sysschedules.freq_type diff --git a/server-config/sql-agent-syspolicy_purge_history-powershell-subsystem-failed-to-load.sql b/sql-agent-syspolicy_purge_history-powershell-subsystem-failed-to-load.sql similarity index 97% rename from server-config/sql-agent-syspolicy_purge_history-powershell-subsystem-failed-to-load.sql rename to sql-agent-syspolicy_purge_history-powershell-subsystem-failed-to-load.sql index 0905545..720fddc 100644 --- a/server-config/sql-agent-syspolicy_purge_history-powershell-subsystem-failed-to-load.sql +++ b/sql-agent-syspolicy_purge_history-powershell-subsystem-failed-to-load.sql @@ -1,37 +1,37 @@ ---SOURCE: http://www.sqlservercentral.com/Forums/Topic772839-146-1.aspx ---SUBJECT: "syspolicy_purge_history" "PowerShell subsystem failed to load" - ---Procedure to trouble shoot the job ‘syspolicy_purge_history’ on SQL server - ---Sometimes job syspolicy_purge_history will fail with the below error message --- Unable to start execution of step 3 (reason: The PowerShell subsystem failed to load [see the SQLAGENT.OUT file for details]; ---The job has been suspended). The step failed. - ---Cause of the failure : invalid location of SQLPS.exe file - ---To troubleshoot the issue please follow the below steps. - ---1. Using the below script check the location of SQLPS.exe file. -SELECT * FROM msdb.dbo.syssubsystems WHERE start_entry_point ='PowerShellStart' - ---2. Go to the server and check whether the file ‘SQLPS.exe’ is located in the path as per step 1. ---3. In this case normally the two paths will be different. ---4. Enable updates using the below script -Use msdb -go -sp_configure 'allow updates', 1 -RECONFIGURE WITH OVERRIDE - ---5. Update the correct path ---Execute the following script after necessary modification (if required) in msdb database. -UPDATE msdb.dbo.syssubsystems SET agent_exe='E:\Server_apps\x86\MSSQL\100\Tools\Binn\SQLPS.exe' WHERE start_entry_point ='PowerShellStart' - ---6. Disable updates using the below script -sp_configure 'allow updates', 0 -RECONFIGURE WITH OVERRIDE - ---7. Confirm that SQLPS.exe file path has changed by running the below script once again -SELECT * FROM msdb.dbo.syssubsystems WHERE start_entry_point ='PowerShellStart' - ---8. Restart the respective SQL agent ( if it is clustered then restart it from the clusadmin ) ---9. Re run the job. +--SOURCE: http://www.sqlservercentral.com/Forums/Topic772839-146-1.aspx +--SUBJECT: "syspolicy_purge_history" "PowerShell subsystem failed to load" + +--Procedure to trouble shoot the job ‘syspolicy_purge_history’ on SQL server + +--Sometimes job syspolicy_purge_history will fail with the below error message +-- Unable to start execution of step 3 (reason: The PowerShell subsystem failed to load [see the SQLAGENT.OUT file for details]; +--The job has been suspended). The step failed. + +--Cause of the failure : invalid location of SQLPS.exe file + +--To troubleshoot the issue please follow the below steps. + +--1. Using the below script check the location of SQLPS.exe file. +SELECT * FROM msdb.dbo.syssubsystems WHERE start_entry_point ='PowerShellStart' + +--2. Go to the server and check whether the file ‘SQLPS.exe’ is located in the path as per step 1. +--3. In this case normally the two paths will be different. +--4. Enable updates using the below script +Use msdb +go +sp_configure 'allow updates', 1 +RECONFIGURE WITH OVERRIDE + +--5. Update the correct path +--Execute the following script after necessary modification (if required) in msdb database. +UPDATE msdb.dbo.syssubsystems SET agent_exe='E:\Server_apps\x86\MSSQL\100\Tools\Binn\SQLPS.exe' WHERE start_entry_point ='PowerShellStart' + +--6. Disable updates using the below script +sp_configure 'allow updates', 0 +RECONFIGURE WITH OVERRIDE + +--7. Confirm that SQLPS.exe file path has changed by running the below script once again +SELECT * FROM msdb.dbo.syssubsystems WHERE start_entry_point ='PowerShellStart' + +--8. Restart the respective SQL agent ( if it is clustered then restart it from the clusadmin ) +--9. Re run the job. diff --git a/server-config/system-database-file-move.sql b/system-database-move-files.sql similarity index 96% rename from server-config/system-database-file-move.sql rename to system-database-move-files.sql index bbe0d43..1d2155f 100644 --- a/server-config/system-database-file-move.sql +++ b/system-database-move-files.sql @@ -1,54 +1,54 @@ -USE [master] -GO - --- move master -/* --dF:\SQL_DATA\master.mdf --lF:\SQL_LOG\mastlog.ldf -*/ - -/* -SELECT name, physical_name AS CurrentLocation -FROM sys.master_files -WHERE database_id = DB_ID(N'model'); -*/ - --- move msdb -ALTER DATABASE msdb -MODIFY FILE (NAME = MSDBData, FILENAME = 'F:\SQL_DATA\MSDBData.mdf'); -GO -ALTER DATABASE msdb -MODIFY FILE (NAME = MSDBLog, FILENAME = 'F:\SQL_LOG\MSDBLog.ldf'); -GO - --- move model -ALTER DATABASE model -MODIFY FILE (NAME = modeldev, FILENAME = 'F:\SQL_DATA\model.mdf'); -GO -ALTER DATABASE model -MODIFY FILE (NAME = modellog, FILENAME = 'F:\SQL_LOG\modellog.ldf'); -GO - --- move TempDB -ALTER DATABASE tempdb -MODIFY FILE (NAME = tempdev, FILENAME = 'T:\TempDb\tempdb.mdf'); -GO -ALTER DATABASE tempdb -MODIFY FILE (NAME = templog, FILENAME = 'T:\TempDb\templog.ldf'); -GO - --- move ReportServer -ALTER DATABASE ReportServer -MODIFY FILE (NAME = ReportServer, FILENAME = 'F:\SQL_DATA\ReportServer.mdf'); -GO -ALTER DATABASE ReportServer -MODIFY FILE (NAME = ReportServer_log, FILENAME = 'F:\SQL_LOG\ReportServer_log.ldf'); -GO - --- move ReportServerTempDB -ALTER DATABASE ReportServerTempDB -MODIFY FILE (NAME = ReportServerTempDB, FILENAME = 'F:\SQL_DATA\ReportServerTempDB.mdf'); -GO -ALTER DATABASE ReportServerTempDB -MODIFY FILE (NAME = ReportServerTempDB_log, FILENAME = 'F:\SQL_LOG\ReportServerTempDB_log.ldf'); +USE [master] +GO + +-- move master +/* +-dF:\SQL_DATA\master.mdf +-lF:\SQL_LOG\mastlog.ldf +*/ + +/* +SELECT name, physical_name AS CurrentLocation +FROM sys.master_files +WHERE database_id = DB_ID(N'model'); +*/ + +-- move msdb +ALTER DATABASE msdb +MODIFY FILE (NAME = MSDBData, FILENAME = 'F:\SQL_DATA\MSDBData.mdf'); +GO +ALTER DATABASE msdb +MODIFY FILE (NAME = MSDBLog, FILENAME = 'F:\SQL_LOG\MSDBLog.ldf'); +GO + +-- move model +ALTER DATABASE model +MODIFY FILE (NAME = modeldev, FILENAME = 'F:\SQL_DATA\model.mdf'); +GO +ALTER DATABASE model +MODIFY FILE (NAME = modellog, FILENAME = 'F:\SQL_LOG\modellog.ldf'); +GO + +-- move TempDB +ALTER DATABASE tempdb +MODIFY FILE (NAME = tempdev, FILENAME = 'T:\TempDb\tempdb.mdf'); +GO +ALTER DATABASE tempdb +MODIFY FILE (NAME = templog, FILENAME = 'T:\TempDb\templog.ldf'); +GO + +-- move ReportServer +ALTER DATABASE ReportServer +MODIFY FILE (NAME = ReportServer, FILENAME = 'F:\SQL_DATA\ReportServer.mdf'); +GO +ALTER DATABASE ReportServer +MODIFY FILE (NAME = ReportServer_log, FILENAME = 'F:\SQL_LOG\ReportServer_log.ldf'); +GO + +-- move ReportServerTempDB +ALTER DATABASE ReportServerTempDB +MODIFY FILE (NAME = ReportServerTempDB, FILENAME = 'F:\SQL_DATA\ReportServerTempDB.mdf'); +GO +ALTER DATABASE ReportServerTempDB +MODIFY FILE (NAME = ReportServerTempDB_log, FILENAME = 'F:\SQL_LOG\ReportServerTempDB_log.ldf'); GO \ No newline at end of file diff --git a/tempdb-add-alter-files.sql b/tempdb-add-alter-files.sql new file mode 100644 index 0000000000000000000000000000000000000000..88f56e7903747918deaee154043f325fa9dee24a GIT binary patch literal 1242 zcmc(fUrPc(6vfZ0LEmBDwn!?Yhah^;Rx5B7RFVo=G`AEiMXjh0U;Spb(Jf3!A7UAH z=KkBc=bp14@0;3CT}72yr)nspN452!SjLm#$!esYUNuo)xA+E%W-*@fWP4;jY0MMj znNn+LBd25xvCJ!(8gE2-+GFK(pd;Q%4d;s#s*uXLr|wWM)a@EHWq$^G(b_N+wTdI&1+WiUVihTQc+Tr9dOHPR= zi@i?%^(-f+eL6k_(Rt-FZdO&3d!1u7m0gslZ5{Ishff~l&27h2O;DWU`rmyzoL1?k zL^lKaO3!hf&hpGJNFi)yXXf?y>A9|!F#Ut6RY+n3NSh~YU>g= fWp!+P%pa$ZEzw7Sej{`hSWWuh6zp5g7%V;k#{Z`k literal 0 HcmV?d00001 diff --git a/database-info/tempdb-what-session-created-that-object.sql b/tempdb-get-session-created-that-object.sql similarity index 97% rename from database-info/tempdb-what-session-created-that-object.sql rename to tempdb-get-session-created-that-object.sql index a6be9fc..d70bd9f 100644 --- a/database-info/tempdb-what-session-created-that-object.sql +++ b/tempdb-get-session-created-that-object.sql @@ -1,23 +1,23 @@ --- https://dba.stackexchange.com/questions/61703/find-which-session-is-holding-which-temporary-table - -DECLARE @FileName VARCHAR(MAX); - -SELECT @FileName = SUBSTRING(path, 0, LEN(path) - CHARINDEX('\', REVERSE(path)) + 1) + '\Log.trc' -FROM sys.traces -WHERE is_default = 1; - -SELECT o.name - ,o.object_id - ,o.create_date - ,gt.NTUserName - ,gt.HostName - ,gt.SPID - ,gt.DatabaseName - ,gt.TextData -FROM sys.fn_trace_gettable(@FileName, DEFAULT) AS gt - JOIN tempdb.sys.objects AS o - ON gt.ObjectID = o.object_id -WHERE gt.DatabaseID = 2 -AND gt.EventClass = 46 -- (Object:Created Event from sys.trace_events) -AND o.create_date >= DATEADD(ms, -100, gt.StartTime) +-- https://dba.stackexchange.com/questions/61703/find-which-session-is-holding-which-temporary-table + +DECLARE @FileName VARCHAR(MAX); + +SELECT @FileName = SUBSTRING(path, 0, LEN(path) - CHARINDEX('\', REVERSE(path)) + 1) + '\Log.trc' +FROM sys.traces +WHERE is_default = 1; + +SELECT o.name + ,o.object_id + ,o.create_date + ,gt.NTUserName + ,gt.HostName + ,gt.SPID + ,gt.DatabaseName + ,gt.TextData +FROM sys.fn_trace_gettable(@FileName, DEFAULT) AS gt + JOIN tempdb.sys.objects AS o + ON gt.ObjectID = o.object_id +WHERE gt.DatabaseID = 2 +AND gt.EventClass = 46 -- (Object:Created Event from sys.trace_events) +AND o.create_date >= DATEADD(ms, -100, gt.StartTime) AND o.create_date <= DATEADD(ms, 100, gt.StartTime); \ No newline at end of file diff --git a/trace-flag-enable-disable.sql b/trace-flag-enable-disable.sql new file mode 100644 index 0000000..d6c76f6 --- /dev/null +++ b/trace-flag-enable-disable.sql @@ -0,0 +1,150 @@ +/****************************************************************************** +Globally enable / disable the specified trace flags. +Use DBCC TRACEON/TRACEOFF to enable disable globally trace flags, then adjust +the SQL Server instance startup parameters for these trace flags. + +SQL Server startup parameters are stored in the registry at: +HKLM\Software\Microsoft\Microsoft SQL Server\MSSQL12.SQL2014\MSSQLServer\Parameters + +To use the xp_instance_reg... XPs, use: +HKLM\Software\Microsoft\MSSQLSERVER\MSSQLServer\Parameters. + +To use: +1. Add the Trace Flags that you want modified to the @TraceFlags table variable. +2. Set the @DebugLevel variable to 1 to see what will happen on your system first. +3. When satisified what will happen, set @DebugLevel to 0 to actually execute the statements. +******************************************************************************** + MODIFICATION LOG +******************************************************************************** +2016-08-03 WGS Initial Creation. +*******************************************************************************/ +SET NOCOUNT ON; +-- Declare and initialize variables. +-- To use with SQL 2005, cannot set the variables in the declare statement. +DECLARE @MaxValue INTEGER, + @SQLCMD VARCHAR(MAX), + @RegHive VARCHAR(50), + @RegKey VARCHAR(100), + @DebugLevel TINYINT; + +SET @RegHive = 'HKEY_LOCAL_MACHINE'; +SET @RegKey = 'Software\Microsoft\MSSQLSERVER\MSSQLServer\Parameters'; +SET @DebugLevel = 0; -- only makes changes if set to zero! + +-- Add the trace flags that you want changed here. +-- If enable = 1, DBCC TRACEON will be run; if enable = 0 then DBCC TRACEOFF will be run. +-- If enable_on_startup = 1, then this TF will be added to start up on service restart; +-- If enable_on_startup - 0, then this TF will be removed from starting up service restart +DECLARE @TraceFlags TABLE ( + TF INTEGER, + enable BIT, + enable_on_startup BIT, + TF2 AS '-T' + CONVERT(VARCHAR(15), TF) +); +INSERT INTO @TraceFlags (TF, enable, enable_on_startup) +-- To work with SQL 2005, cannot use a table value constructor. +-- So, use SELECT statements with UNION ALL for each TF to modify. +SELECT 1117, 1, 1 UNION ALL +SELECT 1118, 1, 1 UNION ALL +SELECT 1204, 0, 0 UNION ALL +SELECT 1222, 0, 0; + + +-- Get all of the arguments / parameters when starting up the service. +DECLARE @SQLArgs TABLE ( + Value VARCHAR(50), + Data VARCHAR(500), + ArgNum AS CONVERT(INTEGER, REPLACE(Value, 'SQLArg', ''))); +INSERT INTO @SQLArgs + EXECUTE master.sys.xp_instance_regenumvalues @RegHive, @RegKey; + + +-- Get the highest argument number that is currently set +SELECT @MaxValue = MAX(ArgNum) +FROM @SQLArgs; +RAISERROR('MaxValue: %i', 10, 1, @MaxValue) WITH NOWAIT; + +-- Disable specified trace flags +SELECT @SQLCMD = 'DBCC TRACEOFF(' + + STUFF((SELECT ',' + CONVERT(VARCHAR(15), TF) + FROM @TraceFlags + WHERE enable = 0 + ORDER BY TF + FOR XML PATH(''), TYPE).value('.','varchar(max)') + ,1,1,'') + ', -1);' + +IF @DebugLevel = 0 EXECUTE (@SQLCMD); +RAISERROR('Disable TFs Command: "%s"', 10, 1, @SQLCMD) WITH NOWAIT; + +-- Enable specified trace flags +SELECT @SQLCMD = 'DBCC TRACEON(' + + STUFF((SELECT ',' + CONVERT(VARCHAR(15), TF) + FROM @TraceFlags + WHERE enable = 1 + ORDER BY TF + FOR XML PATH(''), TYPE).value('.','varchar(max)') + ,1,1,'') + ', -1);' + +IF @DebugLevel = 0 EXECUTE (@SQLCMD); +RAISERROR('Enable TFs Command: "%s"', 10, 1, @SQLCMD) WITH NOWAIT; + +DECLARE cSQLParams CURSOR LOCAL FAST_FORWARD FOR +WITH cte AS +( + -- Current arguments, with new TFs added at the end. Get a row number to sort by. + SELECT *, + ROW_NUMBER() OVER (ORDER BY ISNULL(ArgNum, 999999999), TF) - 1 AS RN + FROM @SQLArgs arg + FULL OUTER JOIN @TraceFlags tf ON arg.Data = tf.TF2 +), cte2 AS +( + -- Use the row number to calc the SQLArg# for new TFs. + -- Use the original Value (SQLArg#) and Data for all rows if possible, + -- Otherwise use the calculated SQLArg# and the calculated TF2 column. + -- Only get the original non-TF-matched parameters, and the TFs set to be enabled + -- (existing startup TFs not in @TraceFlags are left alone). + SELECT ca.Value, + ca.Data + -- in case any TFs are removed, calculate new row numbers in order + -- to renumber the SQLArg values + , ROW_NUMBER() OVER (ORDER BY RN) - 1 AS RN2 + FROM cte + -- Again, for SQL 2005, use SELECT statement instead of VALUES. + CROSS APPLY (SELECT ISNULL(Value, 'SQLArg' + CONVERT(VARCHAR(15), RN)), + ISNULL(Data, TF2) ) ca(Value, Data) + WHERE ISNULL(enable_on_startup, 1) = 1 -- ISNULL handles non-TF parameters +) +-- The first three parameters are the location of the errorlog directory, +-- and the master database file locations. Ignore these. +-- This returns the remaining parameters that should be set. +-- Also return the highest number of parameters, so can determine if any need to be deleted. +SELECT 'SQLArg' + CONVERT(VARCHAR(15), RN2) AS Value, + Data, + MAX(RN2) OVER () AS MaxRN2 +FROM cte2 +WHERE RN2 > 2 +ORDER BY RN2; + +DECLARE @Value VARCHAR(50), + @Data VARCHAR(500), + @MaxRN2 INTEGER; +OPEN cSQLParams; +FETCH NEXT FROM cSQLParams INTO @Value, @Data, @MaxRN2; +WHILE @@FETCH_STATUS = 0 +BEGIN + IF @DebugLevel = 0 EXECUTE master.sys.xp_instance_regwrite @RegHive, @RegKey, @Value, 'REG_SZ', @Data; + RAISERROR('EXECUTE master.sys.xp_instance_regwrite ''%s'', ''%s'', ''%s'', ''REG_SZ'', ''%s''', 10, 1, @RegHive, @RegKey, @Value, @Data) WITH NOWAIT; + FETCH NEXT FROM cSQLParams INTO @Value, @Data, @MaxRN2; +END; +CLOSE cSQLParams; +DEALLOCATE cSQLParams; + +-- In case deleting more TFs than added, there may be extra SQLArg values left behind. +-- Need to delete the extras now. +WHILE @MaxValue > @MaxRN2 +BEGIN + SET @Value = 'SQLArg' + CONVERT(VARCHAR(15), @MaxValue); + IF @DebugLevel = 0 EXECUTE master.sys.xp_instance_regdeletevalue @RegHive, @RegKey, @Value; + RAISERROR('EXECUTE master.sys.xp_instance_regdeletevalue ''%s'', ''%s'', ''%s''', 10, 1, @RegHive, @RegKey, @Value) WITH NOWAIT; + SET @MaxValue = @MaxValue - 1; +END; \ No newline at end of file diff --git a/udf_XML2Table.sql b/udf_XML2Table.sql new file mode 100644 index 0000000000000000000000000000000000000000..8ccada888e67ac794abe474ac1e6936ea4f5fb09 GIT binary patch literal 6608 zcmd5>*-qO~5S`al>Oc66ghFVden7)kkRU-2HX&32O;seevb0p{x3@j#4wJEc?GQo| zRmie)ms!s&_wx78uI$K)ByuG8(vwTMkuP#8$MRO*$S3K9_mXU5O-s6A<*MvTTbA%^ z9rNw5mwT?Us}4F3pzu{b%YkglhBUG61hW^Qek@h_D392ob2WUCau*c0L1_oSyWq2k zeJg=;3uBaoPkN<|?L&sHtYP0-kUzn0-BAHAuBrt6NRJZhNJSdh!IcT*`hjPzKl2D3 zen8?2=+Og>8GK!XI!ET^3h&D>UY8o?=J2#-545&He=WSL(7OccDb zQdUjtHUnP}4YVVrnt_GPCV5LXSE!({`g|5Q~>R;7#+C zXA$cAJ>;%i!~^qJ9Zy*VxkWXWh~9I=@F04#FQVs^9HIW@Sw|y(5&66wvgjdX|B%68 z(F)77v3{!04)V|~EM6pq^L|;z)7rI;_|a%wMJ#m?X%?HTaCKxh%}RH{2MeNBOW?68 z=4(%@br0*Q)zVhT{2bRgR_A>6x&eKyTSkJ%8n?b# zYmQ#aw?e*TH|`y|*7V6q{QCaEEzBx7itp9C?lbr6Fg=G^fBM!N)^^31&W>7^DeHbb zws(-#TEP1X>Q58)p2b7VTOFClZ}xodm*0Kl^W?RKDzqNrg{MHCQD$%+V*jH1%%1;C zZcxj_U71^iXU2Th8?8fo9=%CH2c{Ah^>CDHlpfBop_JoZE~YzNFPEq5k>=JUmaN;# zo=14LFqCmdQAYeVaJp-v%gbV?8v3d6onXkR8IWxj=V|?Qou*PUeT(ezoX#3&lhV~Z z#<$9`jC)?**mwO7IpY^-kTEG8R z{>q10h_dO}pxYWnkLjfPEaNP7lRIr&*QhIXo%KC7=e`=;5vFI$J2#^qcU9$GM^VKp z=U^Eut&@%I;jGq^pMC3AaK4XEgq8==6!Z+U9PTSlQu|{>KX=+uUs?p~d-U^+duQC| zcBf3_#%SPZxfeXovF^2iyL+4~&vCE$fUjPtl!mvmJFKh(d3<=?UBDfw^_-Knf+KO- z+#4Cpjkhx??n~?(GY#9uUaN;r>AAaNM~K}3`$)RJW=B0j)r*aO_O|@)x8t7K%ksKq zi+pD14F-{E89sZDQR(OU;`{btI`X(L_H1PTG2pF>-%7gXZjp4}_9#yf+kOuo$9cM% w@LpB#ZnFE!dTd+mH6V#j(d?2v+W0HZ;YlWYo5q%-HM5#WE#F!t 0 +UNION +SELECT +-- Diff of waits in both snapshots + [ts2].[wait_type], + [ts2].[wait_time_ms] - [ts1].[wait_time_ms] AS [wait_time_ms], + [ts2].[signal_wait_time_ms] - [ts1].[signal_wait_time_ms] AS [signal_wait_time_ms], + [ts2].[waiting_tasks_count] - [ts1].[waiting_tasks_count] AS [waiting_tasks_count] + FROM [##SQLskillsStats2] AS [ts2] + LEFT OUTER JOIN [##SQLskillsStats1] AS [ts1] + ON [ts2].[wait_type] = [ts1].[wait_type] + WHERE [ts1].[wait_type] IS NOT NULL + AND [ts2].[waiting_tasks_count] - [ts1].[waiting_tasks_count] > 0 + AND [ts2].[wait_time_ms] - [ts1].[wait_time_ms] > 0), +[Waits] AS + (SELECT + [wait_type], + [wait_time_ms] / 1000.0 AS [WaitS], + ([wait_time_ms] - [signal_wait_time_ms]) / 1000.0 AS [ResourceS], + [signal_wait_time_ms] / 1000.0 AS [SignalS], + [waiting_tasks_count] AS [WaitCount], + 100.0 * [wait_time_ms] / SUM ([wait_time_ms]) OVER() AS [Percentage], + ROW_NUMBER() OVER(ORDER BY [wait_time_ms] DESC) AS [RowNum] + FROM [DiffWaits] + WHERE [wait_type] NOT IN ( + -- These wait types are almost 100% never a problem and so they are + -- filtered out to avoid them skewing the results. Click on the URL + -- for more information. + N'BROKER_EVENTHANDLER', -- https://www.sqlskills.com/help/waits/BROKER_EVENTHANDLER + N'BROKER_RECEIVE_WAITFOR', -- https://www.sqlskills.com/help/waits/BROKER_RECEIVE_WAITFOR + N'BROKER_TASK_STOP', -- https://www.sqlskills.com/help/waits/BROKER_TASK_STOP + N'BROKER_TO_FLUSH', -- https://www.sqlskills.com/help/waits/BROKER_TO_FLUSH + N'BROKER_TRANSMITTER', -- https://www.sqlskills.com/help/waits/BROKER_TRANSMITTER + N'CHECKPOINT_QUEUE', -- https://www.sqlskills.com/help/waits/CHECKPOINT_QUEUE + N'CHKPT', -- https://www.sqlskills.com/help/waits/CHKPT + N'CLR_AUTO_EVENT', -- https://www.sqlskills.com/help/waits/CLR_AUTO_EVENT + N'CLR_MANUAL_EVENT', -- https://www.sqlskills.com/help/waits/CLR_MANUAL_EVENT + N'CLR_SEMAPHORE', -- https://www.sqlskills.com/help/waits/CLR_SEMAPHORE + N'CXCONSUMER', -- https://www.sqlskills.com/help/waits/CXCONSUMER + + -- Maybe comment these four out if you have mirroring issues + N'DBMIRROR_DBM_EVENT', -- https://www.sqlskills.com/help/waits/DBMIRROR_DBM_EVENT + N'DBMIRROR_EVENTS_QUEUE', -- https://www.sqlskills.com/help/waits/DBMIRROR_EVENTS_QUEUE + N'DBMIRROR_WORKER_QUEUE', -- https://www.sqlskills.com/help/waits/DBMIRROR_WORKER_QUEUE + N'DBMIRRORING_CMD', -- https://www.sqlskills.com/help/waits/DBMIRRORING_CMD + + N'DIRTY_PAGE_POLL', -- https://www.sqlskills.com/help/waits/DIRTY_PAGE_POLL + N'DISPATCHER_QUEUE_SEMAPHORE', -- https://www.sqlskills.com/help/waits/DISPATCHER_QUEUE_SEMAPHORE + N'EXECSYNC', -- https://www.sqlskills.com/help/waits/EXECSYNC + N'FSAGENT', -- https://www.sqlskills.com/help/waits/FSAGENT + N'FT_IFTS_SCHEDULER_IDLE_WAIT', -- https://www.sqlskills.com/help/waits/FT_IFTS_SCHEDULER_IDLE_WAIT + N'FT_IFTSHC_MUTEX', -- https://www.sqlskills.com/help/waits/FT_IFTSHC_MUTEX + + -- Maybe comment these six out if you have AG issues + N'HADR_CLUSAPI_CALL', -- https://www.sqlskills.com/help/waits/HADR_CLUSAPI_CALL + N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', -- https://www.sqlskills.com/help/waits/HADR_FILESTREAM_IOMGR_IOCOMPLETION + N'HADR_LOGCAPTURE_WAIT', -- https://www.sqlskills.com/help/waits/HADR_LOGCAPTURE_WAIT + N'HADR_NOTIFICATION_DEQUEUE', -- https://www.sqlskills.com/help/waits/HADR_NOTIFICATION_DEQUEUE + N'HADR_TIMER_TASK', -- https://www.sqlskills.com/help/waits/HADR_TIMER_TASK + N'HADR_WORK_QUEUE', -- https://www.sqlskills.com/help/waits/HADR_WORK_QUEUE + + N'KSOURCE_WAKEUP', -- https://www.sqlskills.com/help/waits/KSOURCE_WAKEUP + N'LAZYWRITER_SLEEP', -- https://www.sqlskills.com/help/waits/LAZYWRITER_SLEEP + N'LOGMGR_QUEUE', -- https://www.sqlskills.com/help/waits/LOGMGR_QUEUE + N'MEMORY_ALLOCATION_EXT', -- https://www.sqlskills.com/help/waits/MEMORY_ALLOCATION_EXT + N'ONDEMAND_TASK_QUEUE', -- https://www.sqlskills.com/help/waits/ONDEMAND_TASK_QUEUE + N'PARALLEL_REDO_DRAIN_WORKER', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_DRAIN_WORKER + N'PARALLEL_REDO_LOG_CACHE', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_LOG_CACHE + N'PARALLEL_REDO_TRAN_LIST', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_TRAN_LIST + N'PARALLEL_REDO_WORKER_SYNC', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_WORKER_SYNC + N'PARALLEL_REDO_WORKER_WAIT_WORK', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_WORKER_WAIT_WORK + N'PREEMPTIVE_XE_GETTARGETSTATE', -- https://www.sqlskills.com/help/waits/PREEMPTIVE_XE_GETTARGETSTATE + N'PWAIT_ALL_COMPONENTS_INITIALIZED', -- https://www.sqlskills.com/help/waits/PWAIT_ALL_COMPONENTS_INITIALIZED + N'PWAIT_DIRECTLOGCONSUMER_GETNEXT', -- https://www.sqlskills.com/help/waits/PWAIT_DIRECTLOGCONSUMER_GETNEXT + N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', -- https://www.sqlskills.com/help/waits/QDS_PERSIST_TASK_MAIN_LOOP_SLEEP + N'QDS_ASYNC_QUEUE', -- https://www.sqlskills.com/help/waits/QDS_ASYNC_QUEUE + N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', + -- https://www.sqlskills.com/help/waits/QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP + N'QDS_SHUTDOWN_QUEUE', -- https://www.sqlskills.com/help/waits/QDS_SHUTDOWN_QUEUE + N'REDO_THREAD_PENDING_WORK', -- https://www.sqlskills.com/help/waits/REDO_THREAD_PENDING_WORK + N'REQUEST_FOR_DEADLOCK_SEARCH', -- https://www.sqlskills.com/help/waits/REQUEST_FOR_DEADLOCK_SEARCH + N'RESOURCE_QUEUE', -- https://www.sqlskills.com/help/waits/RESOURCE_QUEUE + N'SERVER_IDLE_CHECK', -- https://www.sqlskills.com/help/waits/SERVER_IDLE_CHECK + N'SLEEP_BPOOL_FLUSH', -- https://www.sqlskills.com/help/waits/SLEEP_BPOOL_FLUSH + N'SLEEP_DBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_DBSTARTUP + N'SLEEP_DCOMSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_DCOMSTARTUP + N'SLEEP_MASTERDBREADY', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERDBREADY + N'SLEEP_MASTERMDREADY', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERMDREADY + N'SLEEP_MASTERUPGRADED', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERUPGRADED + N'SLEEP_MSDBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_MSDBSTARTUP + N'SLEEP_SYSTEMTASK', -- https://www.sqlskills.com/help/waits/SLEEP_SYSTEMTASK + N'SLEEP_TASK', -- https://www.sqlskills.com/help/waits/SLEEP_TASK + N'SLEEP_TEMPDBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_TEMPDBSTARTUP + N'SNI_HTTP_ACCEPT', -- https://www.sqlskills.com/help/waits/SNI_HTTP_ACCEPT + N'SOS_WORK_DISPATCHER', -- https://www.sqlskills.com/help/waits/SOS_WORK_DISPATCHER + N'SP_SERVER_DIAGNOSTICS_SLEEP', -- https://www.sqlskills.com/help/waits/SP_SERVER_DIAGNOSTICS_SLEEP + N'SQLTRACE_BUFFER_FLUSH', -- https://www.sqlskills.com/help/waits/SQLTRACE_BUFFER_FLUSH + N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', -- https://www.sqlskills.com/help/waits/SQLTRACE_INCREMENTAL_FLUSH_SLEEP + N'SQLTRACE_WAIT_ENTRIES', -- https://www.sqlskills.com/help/waits/SQLTRACE_WAIT_ENTRIES + N'WAIT_FOR_RESULTS', -- https://www.sqlskills.com/help/waits/WAIT_FOR_RESULTS + N'WAITFOR', -- https://www.sqlskills.com/help/waits/WAITFOR + N'WAITFOR_TASKSHUTDOWN', -- https://www.sqlskills.com/help/waits/WAITFOR_TASKSHUTDOWN + N'WAIT_XTP_RECOVERY', -- https://www.sqlskills.com/help/waits/WAIT_XTP_RECOVERY + N'WAIT_XTP_HOST_WAIT', -- https://www.sqlskills.com/help/waits/WAIT_XTP_HOST_WAIT + N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', -- https://www.sqlskills.com/help/waits/WAIT_XTP_OFFLINE_CKPT_NEW_LOG + N'WAIT_XTP_CKPT_CLOSE', -- https://www.sqlskills.com/help/waits/WAIT_XTP_CKPT_CLOSE + N'XE_DISPATCHER_JOIN', -- https://www.sqlskills.com/help/waits/XE_DISPATCHER_JOIN + N'XE_DISPATCHER_WAIT', -- https://www.sqlskills.com/help/waits/XE_DISPATCHER_WAIT + N'XE_TIMER_EVENT' -- https://www.sqlskills.com/help/waits/XE_TIMER_EVENT + ) + ) +SELECT + [W1].[wait_type] AS [WaitType], + CAST ([W1].[WaitS] AS DECIMAL (16, 2)) AS [Wait_S], + CAST ([W1].[ResourceS] AS DECIMAL (16, 2)) AS [Resource_S], + CAST ([W1].[SignalS] AS DECIMAL (16, 2)) AS [Signal_S], + [W1].[WaitCount] AS [WaitCount], + CAST ([W1].[Percentage] AS DECIMAL (5, 2)) AS [Percentage], + CAST (([W1].[WaitS] / [W1].[WaitCount]) AS DECIMAL (16, 4)) AS [AvgWait_S], + CAST (([W1].[ResourceS] / [W1].[WaitCount]) AS DECIMAL (16, 4)) AS [AvgRes_S], + CAST (([W1].[SignalS] / [W1].[WaitCount]) AS DECIMAL (16, 4)) AS [AvgSig_S], + CAST ('https://www.sqlskills.com/help/waits/' + MAX ([W1].[wait_type]) as XML) AS [Help/Info URL] +FROM [Waits] AS [W1] +INNER JOIN [Waits] AS [W2] + ON [W2].[RowNum] <= [W1].[RowNum] +GROUP BY [W1].[RowNum], [W1].[wait_type], [W1].[WaitS], + [W1].[ResourceS], [W1].[SignalS], [W1].[WaitCount], [W1].[Percentage] +HAVING SUM ([W2].[Percentage]) - [W1].[Percentage] < 95; -- percentage threshold +GO + +-- Cleanup +IF EXISTS (SELECT * FROM [tempdb].[sys].[objects] + WHERE [name] = N'##SQLskillsStats1') + DROP TABLE [##SQLskillsStats1]; + +IF EXISTS (SELECT * FROM [tempdb].[sys].[objects] + WHERE [name] = N'##SQLskillsStats2') + DROP TABLE [##SQLskillsStats2]; +GO \ No newline at end of file diff --git a/wait-stats-get-waits.sql b/wait-stats-get-waits.sql new file mode 100644 index 0000000..6297b60 --- /dev/null +++ b/wait-stats-get-waits.sql @@ -0,0 +1,13 @@ +DECLARE @WaitType1 NVARCHAR(128) = N'WaitTypeName' + ,@WaitType2 NVARCHAR(128) = N'WaitTypeName'; + +SELECT wait_type + ,wait_time_ms / 1000.0 AS Wait_Sec + ,(wait_time_ms - signal_wait_time_ms) / 1000.0 AS Resource_Sec + ,signal_wait_time_ms / 1000.0 AS Signal_Sec + ,waiting_tasks_count AS Wait_Count + --,100.0 * wait_time_ms / SUM(wait_time_ms) OVER () AS Percentage + ,ROW_NUMBER() OVER (ORDER BY wait_time_ms DESC) AS RowNum +FROM sys.dm_os_wait_stats +WHERE (@WaitType1 IS NOT NULL and wait_type = @WaitType1) +OR (@WaitType2 IS NOT NULL AND wait_type = @WaitType2); diff --git a/wait-stats-latch-snapshot.sql b/wait-stats-latch-snapshot.sql new file mode 100644 index 0000000..f29d1c7 --- /dev/null +++ b/wait-stats-latch-snapshot.sql @@ -0,0 +1,48 @@ +/*============================================================================ + File: LatchStats.sql + + Summary: Snapshot of Latch stats + + SQL Server Versions: 2005 onwards +------------------------------------------------------------------------------ + Written by Paul S. Randal, SQLskills.com + + (c) 2015, SQLskills.com. All rights reserved. + + For more scripts and sample code, check out + http://www.SQLskills.com + + You may alter this code for your own *non-commercial* purposes. You may + republish altered code as long as you include this copyright and give due + credit, but you must obtain prior permission before blogging this code. + + THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF + ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + PARTICULAR PURPOSE. +============================================================================*/ + +WITH [Latches] AS + (SELECT + [latch_class], + [wait_time_ms] / 1000.0 AS [WaitS], + [waiting_requests_count] AS [WaitCount], + 100.0 * [wait_time_ms] / SUM ([wait_time_ms]) OVER() AS [Percentage], + ROW_NUMBER() OVER(ORDER BY [wait_time_ms] DESC) AS [RowNum] + FROM sys.dm_os_latch_stats + WHERE [latch_class] NOT IN ( + N'BUFFER') + AND [wait_time_ms] > 0 +) +SELECT + MAX ([W1].[latch_class]) AS [LatchClass], + CAST (MAX ([W1].[WaitS]) AS DECIMAL(14, 2)) AS [Wait_S], + MAX ([W1].[WaitCount]) AS [WaitCount], + CAST (MAX ([W1].[Percentage]) AS DECIMAL(14, 2)) AS [Percentage], + CAST ((MAX ([W1].[WaitS]) / MAX ([W1].[WaitCount])) AS DECIMAL (14, 4)) AS [AvgWait_S] +FROM [Latches] AS [W1] +INNER JOIN [Latches] AS [W2] + ON [W2].[RowNum] <= [W1].[RowNum] +GROUP BY [W1].[RowNum] +HAVING SUM ([W2].[Percentage]) - MAX ([W1].[Percentage]) < 95; -- percentage threshold +GO