The Adept DBA
Musings of 30 Something Database Administrator
Adsense
Monday, March 30, 2020
Introducing DoxieData.com
DoxieData.com is a new data exchange where you can purchase curated data sets. The initial offering is end of day stock market data. Doxie Data
Sunday, November 17, 2019
ColtonVending
We have recently started a vending machine company. If you are in the market for a vending machine please let us know: https://coltonvending.godaddysites.com/
Thursday, May 25, 2017
New Project Announcement
I've been working on a new project that I'd like to announce. In an attempt to help bring more transparency to health care costs I've started work on a new project, www.medpricemonkey.com. This website will provide detailed information on medical procedure cost including what people are paying for them at different providers.
I hope that this information will help consumers make more intelligent decisions about what they pay for their medical bills. I also hope that the transparency of that this data provides will help drive down prices in the medical industry as a whole. Please let me know what you think in the comments.
I hope that this information will help consumers make more intelligent decisions about what they pay for their medical bills. I also hope that the transparency of that this data provides will help drive down prices in the medical industry as a whole. Please let me know what you think in the comments.
Wednesday, August 5, 2015
Identify Foreign Keys in a DB2 database
When trying to identify what foreign keys existing in a DB2 database the sysibm.sysrels table is the best place to look. The query below will give you all the information you need.
select *
from sysibm.sysrels
where tbname = 'CHILD TABLE'
and reftbname = 'PARENT TABLE'
Tuesday, May 5, 2015
Persist Stored Procedure Execution Counts
/*
SELECT * FROM sys.procedures AS p left
JOIN sys.dm_exec_procedure_stats AS s ON s.[object_id] = p.[object_id]
drop table stored_procedure_monitor
use mydatabase
CREATE TABLE
dbo.stored_procedure_monitor(
stored_procedure_monitor_id int identity(1,1),
db_id int NOT NULL,
obj_id int NOT NULL,
schema_id int NOT NULL,
db_nme varchar(256) NOT NULL,
obj_nme varchar(256) NOT NULL,
exp_dte smalldatetime NULL,
create_dte datetime DEFAULT (getdate()) NOT NULL,
create_uid char(10) DEFAULT
(substring(suser_sname(),charindex('\',suser_sname())+(1),(10))) NOT NULL,
update_dte datetime DEFAULT (getdate()) NOT NULL,
update_uid char(10) DEFAULT
(substring(suser_sname(),charindex('\',suser_sname())+(1),(10))) NOT NULL,
CONSTRAINT PK__stored_procedure_monitor PRIMARY KEY CLUSTERED (stored_procedure_monitor_id)
)
drop table
stored_procedure_monitor_executions
CREATE TABLE
dbo.stored_procedure_monitor_executions(
stored_procedure_monitor_id int NOT NULL,
cached_time datetime NOT NULL,
sql_handle varbinary(64) NOT NULL,
plan_handle varbinary(64) NOT NULL,
last_execution_time datetime NOT
NULL,
execution_count bigint NOT NULL,
total_worker_time bigint NOT NULL,
min_worker_time
bigint NOT NULL,
max_worker_time
bigint NOT NULL,
total_physical_reads
bigint NOT NULL,
min_physical_reads
bigint NOT NULL,
max_physical_reads
bigint NOT NULL,
total_logical_reads
bigint NOT NULL,
min_logical_reads
bigint NOT NULL,
max_logical_reads
bigint NOT NULL,
total_logical_writes
bigint NOT NULL,
min_logical_writes
bigint NOT NULL,
max_logical_writes
bigint NOT NULL,
total_elapsed_time
bigint NOT NULL,
min_elapsed_time
bigint NOT NULL,
max_elapsed_time
bigint NOT NULL,
exp_dte
smalldatetime null,
create_dte datetime DEFAULT (getdate()) NOT NULL,
create_uid char(10) DEFAULT
(substring(suser_sname(),charindex('\',suser_sname())+(1),(10))) NOT NULL,
update_dte datetime DEFAULT (getdate()) NOT NULL,
update_uid char(10) DEFAULT (substring(suser_sname(),charindex('\',suser_sname())+(1),(10)))
NOT NULL,
CONSTRAINT PK__stored_procedure_monitor_executions PRIMARY KEY CLUSTERED
(stored_procedure_monitor_id, cached_time, sql_handle, plan_handle)
)
*/
use mydatabase
go
create table #procedure (
db_id int NOT NULL,
db_nme varchar(256) NOT NULL,
obj_id int NOT NULL,
obj_nme varchar(256) NOT NULL,
schema_id int
NOT NULL)
declare @db_id int
declare @db_nme as varchar(256)
declare @sql nvarchar(4000)
declare curs cursor for
select distinct
database_id, name
from master.sys.databases
open curs
fetch next from curs into @db_id, @db_nme
while @@FETCH_STATUS = 0
begin
set @sql = 'select ' + cast(@db_id as varchar) + ' as db_id, ''' +
@db_nme + ''' as
db_nme, object_id as obj_id, name as obj_nme, schema_id from ' + @db_nme + '.sys.procedures'
insert into
#procedure (db_id, db_nme, obj_id, obj_nme, schema_id)
exec sp_executesql @sql
fetch next from curs into @db_id, @db_nme
end
close curs
deallocate curs
--insert any new stored procedures that
were identified
insert into mydatabase.dbo.stored_procedure_monitor(db_id, db_nme, obj_id, obj_nme, schema_id)
select db_id, db_nme, obj_id, obj_nme, schema_id
from #procedure p
where not exists
(select 1 from
mydatabase.dbo.stored_procedure_monitor
p2
where p.db_id = p2.db_id
and p.obj_id = p2.obj_id
and p.schema_id = p2.schema_id)
--expire any stored procedures which no
longer exist
update mydatabase.dbo.stored_procedure_monitor
set exp_dte = getdate()
from mydatabase.dbo.stored_procedure_monitor p2
where not exists (select 1 from #procedure p
where p.db_id = p2.db_id
and p.obj_id = p2.obj_id
and p.schema_id = p2.schema_id)
and exp_dte is null
--unexpire anything that exists again
update mydatabase.dbo.stored_procedure_monitor
set exp_dte = null
from mydatabase.dbo.stored_procedure_monitor p2
where exists (select 1 from
#procedure p
where p.db_id = p2.db_id
and p.obj_id = p2.obj_id
and p.schema_id = p2.schema_id
and exp_dte is not null)
--------------------------------------------------------------------------------------
---------------begin stored proc
executions
CREATE TABLE #executions(
db_id int not null,
obj_id int not null,
cached_time datetime
NOT NULL,
sql_handle varbinary(64) NOT NULL,
plan_handle varbinary(64) NOT NULL,
last_execution_time datetime NOT NULL,
execution_count bigint NOT NULL,
total_worker_time bigint NOT NULL,
min_worker_time
bigint NOT NULL,
max_worker_time
bigint NOT NULL,
total_physical_reads
bigint NOT NULL,
min_physical_reads
bigint NOT NULL,
max_physical_reads
bigint NOT NULL,
total_logical_reads
bigint NOT NULL,
min_logical_reads
bigint NOT NULL,
max_logical_reads
bigint NOT NULL,
total_logical_writes
bigint NOT NULL,
min_logical_writes
bigint NOT NULL,
max_logical_writes
bigint NOT NULL,
total_elapsed_time
bigint NOT NULL,
min_elapsed_time
bigint NOT NULL,
max_elapsed_time
bigint NOT NULL)
declare curs cursor for
select distinct db_id, db_nme
from mydatabase.dbo.stored_procedure_monitor
where exp_dte is null
open curs
fetch next from curs into @db_id, @db_nme
while @@FETCH_STATUS = 0
begin
set @sql = 'SELECT ' + CAST(@db_id as varchar) + ' as db_id, s.object_id, s.cached_time, s.sql_handle,
s.plan_handle, s.last_execution_time, s.execution_count, s.total_worker_time,
s.min_worker_time,
s.max_worker_time, s.total_physical_reads, s.min_physical_reads,
s.max_physical_reads, s.total_logical_reads, s.min_logical_reads,
s.max_logical_reads,
s.total_logical_writes, s.min_logical_writes, s.max_logical_writes,
s.total_elapsed_time, s.min_elapsed_time, s.max_elapsed_time
FROM
' + @db_nme + '.sys.procedures AS p
INNER
JOIN sys.dm_exec_procedure_stats AS s ON s.object_id = p.object_id and
s.database_id = ' + CAST(@db_id as varchar)
--select * from sys.dm_exec_procedure_stats
--insert into #procedure (db_id, db_nme, obj_id, obj_nme,
schema_id)
insert into
#executions (db_id, obj_id, cached_time, sql_handle,
plan_handle, last_execution_time, execution_count,
total_worker_time,
min_worker_time, max_worker_time,
total_physical_reads, min_physical_reads, max_physical_reads,
total_logical_reads, min_logical_reads,
max_logical_reads, total_logical_writes,
min_logical_writes, max_logical_writes, total_elapsed_time,
min_elapsed_time, max_elapsed_time)
exec sp_executesql @sql
fetch next from curs into @db_id, @db_nme
end
close curs
deallocate curs
--insert new stored procedure
executions
insert into mydatabase.dbo.stored_procedure_monitor_executions (stored_procedure_monitor_id, cached_time, sql_handle,
plan_handle, last_execution_time, execution_count,
total_worker_time,
min_worker_time, max_worker_time,
total_physical_reads, min_physical_reads, max_physical_reads,
total_logical_reads, min_logical_reads,
max_logical_reads, total_logical_writes,
min_logical_writes, max_logical_writes, total_elapsed_time,
min_elapsed_time, max_elapsed_time)
select stored_procedure_monitor_id, cached_time, sql_handle,
plan_handle, last_execution_time, execution_count,
total_worker_time,
min_worker_time, max_worker_time,
total_physical_reads, min_physical_reads, max_physical_reads,
total_logical_reads, min_logical_reads,
max_logical_reads, total_logical_writes,
min_logical_writes, max_logical_writes, total_elapsed_time,
min_elapsed_time, max_elapsed_time
from #executions e
inner join dbo.stored_procedure_monitor spm on e.obj_id = spm.obj_id and e.db_id = spm.db_id
where not exists (select 1
from mydatabase.dbo.stored_procedure_monitor_executions spme
where spme.stored_procedure_monitor_id
= spm.stored_procedure_monitor_id
and spme.cached_time = e.cached_time
and spme.sql_handle = e.sql_handle
and spme.plan_handle = e.plan_handle)
--update stored procedure executions
stats
update mydatabase.dbo.stored_procedure_monitor_executions
set last_execution_time = e.last_execution_time,
execution_count = e.execution_count,
total_worker_time =
e.total_worker_time,
min_worker_time = e.min_worker_time,
max_worker_time = e.max_worker_time,
total_physical_reads =
e.total_physical_reads,
min_physical_reads =
e.min_physical_reads,
max_physical_reads =
e.max_physical_reads,
total_logical_reads =
e.total_logical_reads,
min_logical_reads =
e.min_logical_reads,
max_logical_reads =
e.max_logical_reads,
total_logical_writes =
e.total_logical_writes,
min_logical_writes =
e.min_logical_writes,
max_logical_writes =
e.max_logical_writes,
total_elapsed_time =
e.total_elapsed_time,
min_elapsed_time =
e.min_elapsed_time,
max_elapsed_time =
e.max_elapsed_time,
update_dte = GETDATE()
from #executions e
inner join dbo.stored_procedure_monitor spm on e.obj_id = spm.obj_id and e.db_id = spm.db_id
where spm.stored_procedure_monitor_id
= mydatabase.dbo.stored_procedure_monitor_executions.stored_procedure_monitor_id and
mydatabase.dbo.stored_procedure_monitor_executions.cached_time = e.cached_time and
mydatabase.dbo.stored_procedure_monitor_executions.sql_handle = e.sql_handle and
mydatabase.dbo.stored_procedure_monitor_executions.plan_handle = e.plan_handle and
mydatabase.dbo.stored_procedure_monitor_executions.last_execution_time <>
e.last_execution_time
--record the time we noted the plan was
out of cache
update mydatabase.dbo.stored_procedure_monitor_executions
set exp_dte = GETDATE(),
update_dte = GETDATE()
where not exists (select 1
from #executions e
inner join dbo.stored_procedure_monitor spm on e.obj_id = spm.obj_id and e.db_id = spm.db_id
where spm.stored_procedure_monitor_id
= mydatabase.dbo.stored_procedure_monitor_executions.stored_procedure_monitor_id and
mydatabase.dbo.stored_procedure_monitor_executions.cached_time = e.cached_time and
mydatabase.dbo.stored_procedure_monitor_executions.sql_handle = e.sql_handle and
mydatabase.dbo.stored_procedure_monitor_executions.plan_handle = e.plan_handle and
mydatabase.dbo.stored_procedure_monitor_executions.last_execution_time =
e.last_execution_time)
and exp_dte is null
/*
select spm.db_nme,
spm.obj_nme,
SUM(execution_count) as
execution_count,
SUM(total_worker_time)/SUM(execution_count)
as avg_cpu_time,
MIN(min_worker_time) as
min_worker_time,
MAX(max_worker_time) as
max_worker_time,
sum(total_elapsed_time)
total_elapsed_time,
sum(total_elapsed_time)/SUM(execution_count)
as avg_execution_time,
min(min_elapsed_time) as
min_elapsed_time,
max(max_elapsed_time) as
max_elapsed_time
from mydatabase.dbo.stored_procedure_monitor
spm
left outer join mydatabase.dbo.stored_procedure_monitor_executions
spme on spm.stored_procedure_monitor_id = spme.stored_procedure_monitor_id
group by spm.db_nme, spm.obj_nme
order by
sum(total_elapsed_time)/SUM(execution_count) desc
*/
Identify unused indexes and tables
The below query will persist data from sys.dm_db_index_usage_stats so that a history of access to indexes can be maintained following SQL Server restarts. This script should be scheduled to run periodically (nightly is ideal).
use mydatabase
go
if not exists (select 1 from sysobjects where name = 'index_usage_stats')
CREATE TABLE dbo.index_usage_stats(
index_usage_stats_id
int identity (1,1) not null,
database_name
sysname NOT NULL,
database_id
smallint NOT NULL,
object_name sysname
NOT NULL,
object_id int NOT NULL,
index_name
sysname NULL,
index_id
int NOT NULL,
user_seeks
bigint NOT NULL,
user_scans
bigint NOT NULL,
user_lookups
bigint NOT NULL,
user_updates
bigint NOT NULL,
last_user_seek
datetime NULL,
last_user_scan
datetime NULL,
last_user_lookup
datetime NULL,
last_user_update
datetime NULL,
system_seeks
bigint NOT NULL,
system_scans
bigint NOT NULL,
system_lookups
bigint NOT NULL,
system_updates
bigint NOT NULL,
last_system_seek
datetime NULL,
last_system_scan
datetime NULL,
last_system_lookup
datetime NULL,
last_system_update
datetime NULL,
dpages
bigint null,
create_dte
smalldatetime not
null default getdate(),
instance_restart_id
int
)
if not exists (select 1 from sysobjects where name = 'instance_restart')
create table dbo.instance_restart (
instance_restart_id
int identity(1,1) not null,
instance_restart_dte
smalldatetime not
null)
declare @instance_restart_id as
int
declare @instance_restart_dte as
smalldatetime
select @instance_restart_dte =
create_date FROM master.sys.databases WHERE database_id = 2
--sql was last restarted at the time tempdb was
created
IF NOT EXISTS (select 1 from mydatabase.dbo.instance_restart where
instance_restart_dte = @instance_restart_dte)
insert into mydatabase.dbo.instance_restart (instance_restart_dte) select (@instance_restart_dte)
select @instance_restart_id =
max(instance_restart_id) from mydatabase.dbo.instance_restart
declare @dbname as sysname
declare @dbid int
declare @sql as nvarchar(4000)
declare curs cursor for
select name, database_id
from master.sys.databases
where database_id > 4 --do not monitor system databases, we don't necessarily
have access
open curs
fetch next from curs into
@dbname, @dbid
while @@fetch_status = 0
begin
print @dbname
set @sql = '
insert
into mydatabase.dbo.index_usage_stats (database_name, database_id, object_name,
object_id, index_name, index_id, user_seeks, user_scans, user_lookups,
user_updates,
last_user_seek,
last_user_scan, last_user_lookup, last_user_update, system_seeks, system_scans,
system_lookups,system_updates, last_system_seek, last_system_scan,
last_system_lookup,
last_system_update, dpages, instance_restart_id)
select
''' + @dbname + ''' as database_name, ' +
cast(@dbid as varchar) + ' as database_id, o.name as object_name, o.object_id, i.name
as index_name,
i.index_id,
isnull(s.user_seeks, 0), isnull(s.user_scans, 0), isnull(s.user_lookups, 0),
isnull(s.user_updates, 0), s.last_user_seek, s.last_user_scan,
s.last_user_lookup,
s.last_user_update, isnull(s.system_seeks, 0), isnull(s.system_scans, 0),
isnull(s.system_lookups,
0), isnull(s.system_updates, 0), s.last_system_seek, s.last_system_scan,
s.last_system_lookup,
s.last_system_update,
i2.dpages, ' + cast(@instance_restart_id as
varchar) + '
from
' + @dbname + '.sys.indexes i
inner
join ' + @dbname + '.sys.objects o on o.object_id = i.object_id
inner
join ' + @dbname + '.dbo.sysindexes i2 on i.object_id = i2.id and i.index_id =
i2.indid
left
outer join sys.dm_db_index_usage_stats s on i.object_id = s.object_id and
i.index_id = s.index_id and s.database_id = ' + cast(@dbid as varchar)
print @sql
exec sp_executesql @sql
fetch next from curs into
@dbname, @dbid
end
close curs
deallocate curs
Subscribe to:
Posts (Atom)