diff --git a/SQL Performance Dashboard.pbit b/SQL Performance Dashboard.pbit
index 1e205aaa..669be4a6 100644
Binary files a/SQL Performance Dashboard.pbit and b/SQL Performance Dashboard.pbit differ
diff --git a/SQLWATCHDB/Properties/AssemblyInfo.cs b/SQLWATCHDB/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..fe24ea46
--- /dev/null
+++ b/SQLWATCHDB/Properties/AssemblyInfo.cs
@@ -0,0 +1,23 @@
+using System.Reflection;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with the SQLCLR assembly.
+[assembly: AssemblyTitle("SQLWATCH")]
+[assembly: AssemblyDescription("https://sqlwatch.io")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("SQLWATCH")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/SQLWATCHDB/SQLWATCH.refactorlog b/SQLWATCHDB/SQLWATCH.refactorlog
new file mode 100644
index 00000000..82443593
--- /dev/null
+++ b/SQLWATCHDB/SQLWATCH.refactorlog
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SQLWATCHDB/SQLWATCH.sqlproj b/SQLWATCHDB/SQLWATCH.sqlproj
index 2abf2b7a..29f081bf 100644
--- a/SQLWATCHDB/SQLWATCH.sqlproj
+++ b/SQLWATCHDB/SQLWATCH.sqlproj
@@ -52,6 +52,7 @@
true
prompt
4
+ False
11.0
@@ -90,7 +91,10 @@
-
+
+
+
+
@@ -107,4 +111,24 @@
msdb
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(IntermediateTargetAssembly.Split(',')[1].Split('=')[1])
+
+
+
+
\ No newline at end of file
diff --git a/SQLWATCHDB/SQLWATCH.sqlproj.user b/SQLWATCHDB/SQLWATCH.sqlproj.user
index d014f64c..530a7233 100644
--- a/SQLWATCHDB/SQLWATCH.sqlproj.user
+++ b/SQLWATCHDB/SQLWATCH.sqlproj.user
@@ -1,3 +1,7 @@
+
+ (Blank)
+ StartNone
+
\ No newline at end of file
diff --git a/SQLWATCHDB/Script.PostDeployment1.sql b/SQLWATCHDB/Script.PostDeployment1.sql
index 1c827f24..efd9c8f2 100644
--- a/SQLWATCHDB/Script.PostDeployment1.sql
+++ b/SQLWATCHDB/Script.PostDeployment1.sql
@@ -19,6 +19,17 @@ if (select count(*) from [dbo].[sql_perf_mon_config_who_is_active_age]) = 0
--------------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------------
+/* databases with create_date = '1970-01-01' are from previous
+versions of SQLWATCH and we will now update create_date to the actual
+create_date (this will only apply to upgrades) */
+update swd
+ set [database_create_date] = db.[create_date]
+from [dbo].[sql_perf_mon_database] swd
+inner join sys.databases db
+ on db.[name] = swd.[database_name]
+ and swd.[database_create_date] = '1970-01-01'
+
+/* now add new databases */
exec [dbo].[sp_sql_perf_mon_add_database]
--------------------------------------------------------------------------------------
@@ -50,7 +61,7 @@ create nonclustered index tmp_idx_sql_perf_mon_perf_counters_types on #sql_perf_
/* based on https://blogs.msdn.microsoft.com/dfurman/2015/04/02/collecting-performance-counter-values-from-a-sql-azure-database/ */
insert into #sql_perf_mon_config_perf_counters([collect],[object_name],[counter_name], [instance_name],[base_counter_name])
values
- (0,'Access Methods','Forwarded Records/sec','',NULL)
+ (0,'Access Methods','Forwarded Records/sec','',NULL)
,(1,'Access Methods','Full Scans/sec','',NULL)
,(1,'Access Methods','Page Splits/sec','',NULL)
,(1,'Access Methods','Pages Allocated/sec','',NULL)
@@ -619,14 +630,23 @@ if (select count(*) from [dbo].[sql_perf_mon_config_report_time_interval]) = 0
end
--------------------------------------------------------------------------------------
---
+-- add snapshot types
--------------------------------------------------------------------------------------
-if (select count(*) from [dbo].[sql_perf_mon_config_snapshot_type]) = 0
- begin
- insert into [dbo].[sql_perf_mon_config_snapshot_type]
- values (1, 'Performance', 7),
- (2, 'Growth', 365)
- end
+;merge [dbo].[sql_perf_mon_config_snapshot_type] as target
+using (
+ /* performance data logger */
+ select [snapshot_type_id] = 1, [snapshot_type_desc] = 'Performance', [snapshot_retention_days] = 7
+ union
+ /* size data logger */
+ select [snapshot_type_id] = 2, [snapshot_type_desc] = 'Disk Utilisation', [snapshot_retention_days] = 365
+) as source
+on (source.[snapshot_type_id] = target.[snapshot_type_id])
+when matched and source.[snapshot_type_desc] <> target.[snapshot_type_desc] then
+ update set [snapshot_type_desc] = source.[snapshot_type_desc]
+when not matched then
+ insert ([snapshot_type_id],[snapshot_type_desc],[snapshot_retention_days])
+ values (source.[snapshot_type_id],source.[snapshot_type_desc],source.[snapshot_retention_days])
+;
--------------------------------------------------------------------------------------
--
@@ -791,3 +811,53 @@ if (select name from sysjobs where name = 'DBA-PERF-AUTO-CONFIG') is null
@active_end_time=235959, @schedule_id = @schedule_id OUTPUT
select @schedule_id
end
+
+if (select name from sysjobs where name = 'SQLWATCH-LOGGER-DISK-UTILISATION') is null
+ begin
+ set @jobId = null
+ EXEC msdb.dbo.sp_add_job @job_name=N'SQLWATCH-LOGGER-DISK-UTILISATION',
+ @enabled=1,
+ @notify_level_eventlog=0,
+ @notify_level_email=2,
+ @notify_level_page=2,
+ @delete_level=0,
+ @category_name=N'Data Collector',
+ @owner_login_name=N'sa', @job_id = @jobId OUTPUT
+ EXEC msdb.dbo.sp_add_jobserver @job_name=N'SQLWATCH-LOGGER-DISK-UTILISATION', @server_name = @server;
+ EXEC msdb.dbo.sp_add_jobstep @job_name=N'SQLWATCH-LOGGER-DISK-UTILISATION', @step_name=N'exec dbo.usp_logger_disk_utilisation',
+ @step_id=1,
+ @cmdexec_success_code=0,
+ @on_success_action=1,
+ @on_fail_action=2,
+ @retry_attempts=0,
+ @retry_interval=0,
+ @os_run_priority=0, @subsystem=N'TSQL',
+ @command=N'exec [dbo].[usp_logger_disk_utilisation]',
+ @database_name=@database,
+ @flags=0
+ EXEC msdb.dbo.sp_update_job @job_name=N'SQLWATCH-LOGGER-DISK-UTILISATION',
+ @enabled=1,
+ @start_step_id=1,
+ @notify_level_eventlog=0,
+ @notify_level_email=2,
+ @notify_level_page=2,
+ @delete_level=0,
+ @description=N'',
+ @category_name=N'Data Collector',
+ @owner_login_name=N'sa',
+ @notify_email_operator_name=N'',
+ @notify_page_operator_name=N''
+ set @schedule_id = null
+ EXEC msdb.dbo.sp_add_jobschedule @job_name=N'SQLWATCH-LOGGER-DISK-UTILISATION', @name=N'SQLWATCH-LOGGER-DISK-UTILISATION',
+ @enabled=1,
+ @freq_type=4,
+ @freq_interval=1,
+ @freq_subday_type=8,
+ @freq_subday_interval=1,
+ @freq_relative_interval=0,
+ @freq_recurrence_factor=1,
+ @active_start_date=20180909,
+ @active_end_date=99991231,
+ @active_start_time=437,
+ @active_end_time=235959, @schedule_id = @schedule_id OUTPUT
+ end
\ No newline at end of file
diff --git a/SQLWATCHDB/bin/Debug/SQLWATCH.dacpac b/SQLWATCHDB/bin/Debug/SQLWATCH.dacpac
index 017e64ed..b681c316 100644
Binary files a/SQLWATCHDB/bin/Debug/SQLWATCH.dacpac and b/SQLWATCHDB/bin/Debug/SQLWATCH.dacpac differ
diff --git a/SQLWATCHDB/bin/Debug/SQLWATCHDB.dll b/SQLWATCHDB/bin/Debug/SQLWATCHDB.dll
index d3c0e280..b49d23c5 100644
Binary files a/SQLWATCHDB/bin/Debug/SQLWATCHDB.dll and b/SQLWATCHDB/bin/Debug/SQLWATCHDB.dll differ
diff --git a/SQLWATCHDB/dbo/Procedures/sp_sql_perf_mon_add_database.sql b/SQLWATCHDB/dbo/Procedures/sp_sql_perf_mon_add_database.sql
index bc426674..18f4a1d5 100644
--- a/SQLWATCHDB/dbo/Procedures/sp_sql_perf_mon_add_database.sql
+++ b/SQLWATCHDB/dbo/Procedures/sp_sql_perf_mon_add_database.sql
@@ -16,20 +16,36 @@ as
set nocount on;
declare @databases table (
- [database_name] sysname primary key
- )
+ [database_name] sysname not null,
+ [database_create_date] datetime not null default '1970-01-01',
+ primary key clustered (
+ [database_name],[database_create_date]
+ )
+)
insert into @databases
- select [name] from sys.databases
+ select [name], [create_date]
+ from sys.databases
union all
/* mssqlsystemresource database appears in the performance counters
so we need it as a dimensions to be able to filter in the report */
- select 'mssqlsystemresource'
+ select 'mssqlsystemresource', '1970-01-01'
+
+ ;merge [dbo].[sql_perf_mon_database] as target
+ using @databases as source
+ on (
+ source.[database_name] = target.[database_name]
+ and source.[database_create_date] = target.[database_create_date]
+ )
+ /* dropped databases are going to be updated to current = 0 */
+ when not matched by source then
+ update set [database_current] = 0
+ /* new databases are going to be inserted */
+ when not matched by target then
+ insert ([database_name], [database_create_date])
+ values (source.[database_name], source.[database_create_date]);
- insert into [dbo].[sql_perf_mon_database]
- select s.[database_name]
- from @databases s
- left join [dbo].[sql_perf_mon_database] t
- on s.[database_name] = t.[database_name]
- where t.[database_name] is null
-
\ No newline at end of file
+ /* the above only accounts for databases that have been removed and re-added
+ if you rename database it will be treated as if it was removed and new
+ database created so you will lose history continuation. Why would you
+ rename a database anyway */
\ No newline at end of file
diff --git a/SQLWATCHDB/dbo/Procedures/sp_sql_perf_mon_logger.sql b/SQLWATCHDB/dbo/Procedures/sp_sql_perf_mon_logger.sql
index 00cb72b1..837c4e30 100644
--- a/SQLWATCHDB/dbo/Procedures/sp_sql_perf_mon_logger.sql
+++ b/SQLWATCHDB/dbo/Procedures/sp_sql_perf_mon_logger.sql
@@ -19,7 +19,7 @@ declare @sql nvarchar(4000)
--------------------------------------------------------------------------------------------------------------
-- detect which version of sql we are running as some dmvs are different in different versions of sql
--------------------------------------------------------------------------------------------------------------
- set @product_version = convert(nvarchar(128),serverproperty('productversioN'));
+ set @product_version = convert(nvarchar(128),serverproperty('productversion'));
select
@product_version_major = substring(@product_version, 1,charindex('.', @product_version) + 1 )
@@ -56,7 +56,6 @@ declare @sql nvarchar(4000)
set @date_snapshot_current = getdate();
insert into [dbo].[sql_perf_mon_snapshot_header]
values (@date_snapshot_current, 1)
-
--------------------------------------------------------------------------------------------------------------
-- 1. get cpu
diff --git a/SQLWATCHDB/dbo/Procedures/usp_logger_disk_utilisation.sql b/SQLWATCHDB/dbo/Procedures/usp_logger_disk_utilisation.sql
new file mode 100644
index 00000000..9b73ee9e
--- /dev/null
+++ b/SQLWATCHDB/dbo/Procedures/usp_logger_disk_utilisation.sql
@@ -0,0 +1,111 @@
+CREATE PROCEDURE [dbo].[usp_logger_disk_utilisation]
+AS
+set nocount on;
+
+declare @snapshot_type tinyint = 2
+declare @product_version nvarchar(128)
+declare @product_version_major decimal(10,2)
+declare @product_version_minor decimal(10,2)
+
+set @product_version = convert(nvarchar(128),serverproperty('productversion'));
+select @product_version_major = substring(@product_version, 1,charindex('.', @product_version) + 1 )
+ ,@product_version_minor = parsename(convert(varchar(32), @product_version), 2);
+--------------------------------------------------------------------------------------------------------------
+-- set the basics
+--------------------------------------------------------------------------------------------------------------
+declare @snapshot_time datetime = getdate();
+insert into [dbo].[sql_perf_mon_snapshot_header]
+values (@snapshot_time, @snapshot_type)
+
+--------------------------------------------------------------------------------------------------------------
+-- get sp_spaceused
+--------------------------------------------------------------------------------------------------------------
+declare @spaceused table (
+ [database_name] nvarchar(128),
+ [database_size] varchar(18),
+ [unallocated_space] varchar(18),
+ [reserved] varchar(18),
+ [data] varchar(18),
+ [index_size] varchar(18),
+ [unused] varchar(18)
+)
+insert into @spaceused
+ exec sp_MSforeachdb 'use [?]; exec sp_spaceused @oneresultset = 1;'
+
+--------------------------------------------------------------------------------------------------------------
+-- get log usage
+--------------------------------------------------------------------------------------------------------------
+declare @logspace_SQL2008 table (
+ [database_name] sysname,
+ [log_space_mb] decimal(18,2),
+ [log_space_used_perc] real,
+ [status] bit
+)
+
+declare @logspace table (
+ [database_name] sysname,
+ [total_log_size_in_bytes] bigint,
+ [used_log_space_in_bytes] bigint
+)
+
+if @product_version_major < 11
+ begin
+ insert into @logspace_SQL2008
+ exec ('DBCC SQLPERF(LOGSPACE);')
+
+ /* make into a 2012 format */
+ insert into @logspace
+ select
+ [database_name],
+ [total_log_size_in_bytes] = [log_space_mb] * 1024.0 * 1024.0,
+ [used_log_space_in_bytes] = ([log_space_mb] * [log_space_used_perc] / 100.0) * 1024.0 * 1024.0
+ from @logspace_SQL2008
+ end
+else
+ begin
+ insert into @logspace
+ exec sp_MSforeachdb '
+ use [?]
+ select
+ ''?'',
+ [total_log_size_in_bytes],
+ [used_log_space_in_bytes]
+ from sys.dm_db_log_space_usage'
+ end
+
+
+--------------------------------------------------------------------------------------------------------------
+-- combine results and insert into the table
+--------------------------------------------------------------------------------------------------------------
+insert into [dbo].[logger_disk_utilisation_database]
+select
+ su.[database_name]
+ , [database_create_date] = db.create_date
+ /*
+ conversion from sp_spaceused MiB format to bytes so we have consistent units
+ to test that this gives us an exact number:
+ sp_spaceused returns 7.63 MB for master database.
+ our conversion below gives us 8000634 bytes -> covnert back to MB:
+ 8000634 / 1024 / 1024 = 7.6299 MB
+ Try: http://www.wolframalpha.com/input/?i=8000634+bytes+in+MiB
+ */
+ , [database_size_bytes] = convert(bigint,convert(decimal(19,2),replace([database_size],' MB','')) * 1024 * 1024)
+ , [unallocated_space_bytes] = convert(bigint,convert(decimal(19,2),replace([unallocated_space],' MB','')) * 1024.0 * 1024.0)
+ , [reserved_bytes] = convert(bigint,convert(decimal(19,2),replace([reserved],' KB','')) * 1024.0)
+ , [data_bytes] = convert(bigint,convert(decimal(19,2),replace([data],' KB','')) * 1024.0)
+ , [index_size_bytes] = convert(bigint,convert(decimal(19,2),replace([index_size],' KB','')) * 1024.0)
+ , [unused_bytes] = convert(bigint,convert(decimal(19,2),replace([unused],' KB','')) * 1024.0)
+ , ls.[total_log_size_in_bytes]
+ , ls.[used_log_space_in_bytes]
+ , [snapshot_time] = @snapshot_time
+ , [snapshot_type_id] = @snapshot_type
+from @spaceused su
+inner join @logspace ls
+ on su.[database_name] = ls.[database_name]
+inner join sys.databases db
+ on db.[name] = su.[database_name]
+/* join on sqlwatch database list otherwise it will fail
+ for newly created databases not yet added to the list */
+inner join [dbo].[sql_perf_mon_database] swd
+ on swd.[database_name] = db.[name]
+ and swd.[database_create_date] = db.[create_date]
diff --git a/SQLWATCHDB/dbo/Tables/logger_disk_utilisation_database.sql b/SQLWATCHDB/dbo/Tables/logger_disk_utilisation_database.sql
new file mode 100644
index 00000000..f58034f5
--- /dev/null
+++ b/SQLWATCHDB/dbo/Tables/logger_disk_utilisation_database.sql
@@ -0,0 +1,25 @@
+CREATE TABLE [dbo].[logger_disk_utilisation_database]
+(
+ [database_name] sysname,
+ [database_create_date] datetime,
+ [database_size_bytes] bigint,
+ [unallocated_space_bytes] bigint,
+ [reserved_bytes] bigint,
+ [data_bytes] bigint,
+ [index_size_bytes] bigint,
+ [unused_bytes] bigint,
+ [log_size_total_bytes] bigint,
+ [log_size_used_bytes] bigint,
+ [snapshot_time] datetime,
+ [snapshot_type_id] tinyint,
+ constraint PK_logger_disk_util_database
+ primary key clustered ([snapshot_time], [database_name]),
+ constraint FK_logger_disk_util_database_database
+ foreign key ([database_name],[database_create_date])
+ references [dbo].[sql_perf_mon_database] ([database_name],[database_create_date])
+ on delete cascade,
+ constraint FK_logger_disk_util_database_snapshot
+ foreign key ([snapshot_time],[snapshot_type_id])
+ references [dbo].[sql_perf_mon_snapshot_header] ([snapshot_time],[snapshot_type_id])
+ on delete cascade
+)
diff --git a/SQLWATCHDB/dbo/Tables/sql_perf_mon_config_snapshot_header_type.sql b/SQLWATCHDB/dbo/Tables/sql_perf_mon_config_snapshot_type.sql
similarity index 100%
rename from SQLWATCHDB/dbo/Tables/sql_perf_mon_config_snapshot_header_type.sql
rename to SQLWATCHDB/dbo/Tables/sql_perf_mon_config_snapshot_type.sql
diff --git a/SQLWATCHDB/dbo/Tables/sql_perf_mon_database.sql b/SQLWATCHDB/dbo/Tables/sql_perf_mon_database.sql
index 3eb5dca9..7f12271c 100644
--- a/SQLWATCHDB/dbo/Tables/sql_perf_mon_database.sql
+++ b/SQLWATCHDB/dbo/Tables/sql_perf_mon_database.sql
@@ -1,4 +1,9 @@
CREATE TABLE [dbo].[sql_perf_mon_database]
(
- [database_name] sysname primary key
+ [database_name] sysname not null,
+ [database_create_date] datetime not null default '1970-01-01',
+ [database_current] bit not null default 1,
+ constraint PK_database primary key clustered (
+ [database_name],[database_create_date]
+ )
)
diff --git a/SQLWATCHDB/dbo/Tables/sql_perf_mon_master_files.sql b/SQLWATCHDB/dbo/Tables/sql_perf_mon_master_files.sql
new file mode 100644
index 00000000..7cf8249a
--- /dev/null
+++ b/SQLWATCHDB/dbo/Tables/sql_perf_mon_master_files.sql
@@ -0,0 +1,21 @@
+CREATE TABLE [dbo].[sql_perf_mon_master_files]
+(
+ [database_name] sysname,
+ [database_create_date] datetime,
+ [file_type] tinyint,
+ [file_physical_name] nvarchar(260),
+ [file_size] int,
+ [snapshot_time] datetime,
+ [snapshot_type_id] tinyint,
+ constraint PK_sql_perf_mon_master_files primary key clustered (
+ [snapshot_time], [database_name]
+ ),
+ constraint FK_sql_perf_mon_master_files_db foreign key ([database_name], [database_create_date])
+ references [dbo].[sql_perf_mon_database](
+ [database_name], [database_create_date]
+ ) on delete cascade,
+ constraint FK_sql_perf_mon_master_files_snapshot foreign key ([snapshot_time], [snapshot_type_id])
+ references [dbo].[sql_perf_mon_snapshot_header] (
+ [snapshot_time], [snapshot_type_id]
+ ) on delete cascade
+)