In SQL-server 2008, How would I find (through an SQL query), the percentage of tablespace usage for a particular instance(or all instances) of a SQL Server(2008 R2)?
Also, what is the best way (query) to get the list of all the Named Instances of a SQL Server?
is this what you need:
EXEC sp_spaceused null, false
result:
database_name database_size unallocated space
--------------- ------------------ ------------------
DATABASE_NAME 220.25 MB 69.92 MB
reserved data index_size unused
------------------ ------------------ ------------------ ------------------
110672 KB 80368 KB 26944 KB 3360 KB
Use the script:
set nocount on
declare #indexes table(
QualifiedName nvarchar(512),
IndexId int,
FGName nvarchar(128),
Type nvarchar(50),
NumKeys int,
IndexKB numeric(28,0),
UsedKB numeric(28,0),
FreeKB numeric(28,0),
Rows numeric(28,0),
RowModCtr numeric(28,0),
OrigFillFactor int,
tableid bigint
)
insert into #indexes
select
db_name() + '.' + isnull(su.name,'<unknown-user>') + '.' + so.name + '.' + isnull(i.name,'<Heap>') QualifiedName,
i.index_id IndexId,
(select isnull(name,'') from sys.filegroups where data_space_id = i.data_space_id) FGName,
case
when so.type = 'V' then 'Indexed View: '
else ''
end +
case
when i.index_id = 0 then 'Heap'
when i.index_id = 1 then 'Clustered'
else 'Non Clustered'
end Type,
0 NumKeys,
a.used_pages* 8 IndexKB,
CASE
When a.type <> 1 Then a.used_pages * 8
When p.index_id < 2 Then a.data_pages * 8
Else 0
END UsedKB,
(a.total_pages-a.used_pages)* 8 FreeKB,
p.rows Rows,
0 RowModCtr,
i.fill_factor OrigFillFactor,
convert(bigint,db_id()) * power(convert(bigint,2),48) + convert(bigint,su.schema_id) * power(convert(bigint,2),32) + so.object_id tableid
from
sys.objects so with (readpast)
inner join sys.schemas su with (readpast) on su.schema_id = so.schema_id
inner join sys.indexes i with (readpast) on so.object_id = i.object_id
inner join sys.partitions p with (readpast) ON i.object_id = p.object_id and i.index_id = p.index_id
inner join sys.allocation_units a with (readpast) on p.partition_id = a.container_id
where
(so.type = 'U') and a.type_Desc = 'IN_ROW_DATA'
and isnull(INDEXPROPERTY(i.object_id, i.name, 'IsStatistics'),0) = 0
and isnull(INDEXPROPERTY(i.object_id, i.name, 'IsAutoStatistics'),0) = 0
and isnull(INDEXPROPERTY(i.object_id, i.name, 'IsHypothetical'),0) = 0
order by
IndexKB desc
select
i.QualifiedName,
i.IndexId,
i.FGName,
i.Type,
i.NumKeys,
i.IndexKB,
(i.UsedKB - isnull(t.s_UsedKB,0)) UsedKB,
(i.FreeKB - isnull(t.s_FreeKB,0)) FreeKB,
i.Rows,
i.RowModCtr,
i.OrigFillFactor
from
#indexes i
left outer join (
select tableid, sum(UsedKB) s_UsedKB, sum(FreeKB) s_FreeKB
from #indexes
where IndexId > 1
group by tableid
) t on t.tableid = i.tableid
and i.IndexId <= 1
order by
IndexKB desc
Related
In SQL Server, we have a number of tables, all containing a field last_modified that records when a particular record was created, modified, or flagged for deletion. I want to create a table of table names and the max() value of last_modified.
I'm brute forcing it as follows:
I run a query modified from Query to list number of records in each table in a database to list tables that have rows and eliminate some internal tables.
SELECT
t.NAME AS TableName,
p.[Rows]
FROM
sys.tables t
INNER JOIN
sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
WHERE
t.NAME NOT LIKE 'dt%' AND t.name not like '%ml%' and
t.NAME not in ('OrderHeaders', 'OrderHeaderExtendedText', 'OrderLIDetails', 'OrderLIDetailExtendedText', 'UserCustomerXRef', 'UserDetails', 'UserDetailExtendedText', 'UserTypeDescription') and
p.rows <> 0 and
i.OBJECT_ID > 255 AND
i.index_id <= 1
GROUP BY
t.NAME, p.[Rows]
ORDER BY
TableName
This gives me a table like this:
Then I paste this output into Excel and create a series of queries there:
A2.value reads BidCustomerXRef. C2.Value reads ="select top 1 last_modified, '" & A2 & "' as 'Table' from " & A2 & " where deleted = 'N' order by last_modified desc" and so I get
select top 1 last_modified, 'BidCustomerXRef' as 'Table'
from BidCustomerXref
where deleted = 'N'
order by last_modified desc`
So I copy all of those rows to my SQL query window and I get this:
What I want is a single table that looks like this:
TableName
last_modified
BidCustomerXRef
2022-06-21 21:30:07.287
Bids
2022-06-22 20:00:06.383
CustomerARDetail
2022-06-22 18:00:11.923
etc.
Here is one way you can do this. I am using the system tables to generate dynamic sql instead of using a dreaded cursor or other sort of iteration going row by agonizing row.
declare #sql nvarchar(max) = ''
select #sql += 'select TableName = ''' + s.name + '.' + t.name + ''', last_modified = (select max(last_modified) from ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' where deleted = ''N'') union all '
from sys.tables t
join sys.schemas s on s.schema_id = t.schema_id
join sys.indexes i ON t.object_id = i.object_id
join sys.partitions p ON i.object_id = p.object_id and i.index_id = p.index_id
where t.NAME NOT LIKE 'dt%'
and t.name not like '%ml%'
and t.NAME not in ('OrderHeaders', 'OrderHeaderExtendedText', 'OrderLIDetails', 'OrderLIDetailExtendedText', 'UserCustomerXRef', 'UserDetails', 'UserDetailExtendedText', 'UserTypeDescription')
and p.rows > 0
and i.object_id > 255
and i.index_id <= 1
order by t.name
select #sql = left(#sql, len(#sql) - 9) --removes the last UNION ALL
select #sql
--uncomment the line below once you have evaluated that the dynamic sql is correct
--exec sp_executesql #sql
I've been tasked with moving all tables in a single snapshot replication that have primary keys to the transaction replication. We get vendor updates and they may have added keys to tables that were in the Snapshot replication.
I've tried to break it down into 2 steps, finding all tables in a snapshot replication, and then checking to see if those tables have a primary key.
I've tried to piece together a few different code samples, but I may need to start over, here's what I've got so far.
--=============================================================================================
SELECT DB_NAME () PublisherDB
, sp.name AS PublisherName
, sa.name AS TableName
, UPPER (srv.srvname) AS SubscriberServerName
,*
FROM dbo.syspublications sp
JOIN dbo.sysarticles sa ON sp.pubid = sa.pubid
JOIN dbo.syssubscriptions s ON sa.artid = s.artid
JOIN master.dbo.sysservers srv ON s.srvid = srv.srvid;
--=============================================================================================
SELECT DB_NAME () AS db
, SCHEMA_NAME (o.schema_id) AS [Schema]
, so.name AS table_name
, so.type
, CASE WHEN TABLE_NAME IN (
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'PRIMARY KEY'
) THEN 1 ELSE 0 END AS HasPrimaryKey
--INTO #t2
FROM sys.objects o WITH (NOLOCK)
INNER JOIN sysobjects so WITH (NOLOCK)
--INNER JOIN #t1 ON t1.
LEFT OUTER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS t2 ON t2.TABLE_NAME = so.name ON so.id = o.object_id
WHERE (
(so.xtype = 'U') -- user table xtype: learn.microsoft.com/en-us/sql/relational-databases/system-compatibility-views/sys-sysobjects-transact-sql?view=sql-server-ver15
OR (so.xtype = 'V') -- view
OR (so.xtype = 'P') -- stored procedure
)
AND so.category <> 2
AND so.name IN (
SELECT DISTINCT OBJECT_NAME (objid) FROM dbo.sysarticles
)
ORDER BY so.name
, so.type;
--=============================================================================================
DECLARE #jobId UNIQUEIDENTIFIER;
DECLARE #jobName sysname;
SELECT #jobId = jobs.job_id
, #jobName = jobs.name
FROM msdb.dbo.sysjobs jobs (NOLOCK)
JOIN msdb.dbo.syscategories categories (NOLOCK) ON jobs.category_id = categories.category_id
WHERE categories.name = 'REPL-Snapshot'
AND jobs.name LIKE '%db-name%';
SELECT #jobId
, #jobName;
EXEC sp_start_job #job_id = #jobId;
This is what I ended up going with. I pieced together and tweaked various snippets of code I've found.
Some from here: https://dataedo.com/kb/query/sql-server/list-tables-with-their-primary-keys
Other code from here: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/50c6890b-8dc1-46c6-aeda-d97149a9692f/list-all-replicated-tables-and-their-destination?forum=sqlreplication
--====================================================================================================================================================
-- Get tables in Snapshot replication for the selected DB.
--====================================================================================================================================================
IF OBJECT_ID ('tempdb..#t1') IS NOT NULL DROP TABLE #t1;
SELECT pub.name AS [Publication]
, CASE WHEN pub.name LIKE '%Snapshot%' THEN 'SnapShot'
WHEN pub.name LIKE '%Transaction%' THEN 'Transaction' ELSE NULL END AS ReplicationType
, art.name AS [Article]
, serv.name AS [Subsriber]
, sub.dest_db AS [DestinationDB]
, obj.object_id
, CASE WHEN obj.type = 'U' THEN 'Table'
WHEN obj.type = 'V' THEN 'View'
WHEN obj.type = 'P' THEN 'SP' ELSE NULL END AS ObjectType
INTO #t1
FROM dbo.syssubscriptions sub
INNER JOIN sys.servers serv ON serv.server_id = sub.srvid
INNER JOIN dbo.sysarticles art ON art.artid = sub.artid
INNER JOIN dbo.syspublications pub ON pub.pubid = art.pubid
INNER JOIN sys.objects obj ON obj.object_id = art.objid
WHERE CASE WHEN pub.name LIKE '%Snapshot%' THEN 'SnapShot'
WHEN pub.name LIKE '%Transaction%' THEN 'Transaction' ELSE NULL END = 'Snapshot';
--====================================================================================================================================================
-- Check for primary keys on the above tables
--====================================================================================================================================================
SELECT SCHEMA_NAME (tab.schema_id) AS [schema_name]
, tab.[name] AS table_name
, pk.[name] AS pk_name
, SUBSTRING (column_names, 1, LEN (column_names) - 1) AS [columns]
FROM sys.tables tab
LEFT OUTER JOIN sys.indexes pk ON tab.object_id = pk.object_id
AND pk.is_primary_key = 1
CROSS APPLY (
SELECT col.[name] + ', '
FROM sys.index_columns ic
INNER JOIN sys.columns col ON ic.object_id = col.object_id
AND ic.column_id = col.column_id
WHERE ic.object_id = tab.object_id
AND ic.index_id = pk.index_id
ORDER BY col.column_id
FOR XML PATH ('')
) D(column_names)
WHERE pk.object_id IN (
SELECT object_id FROM #t1
)
ORDER BY SCHEMA_NAME (tab.schema_id)
, tab.[name];
I have to find the table space of the table.
I tried sp_spaceused 'MyTableName'
But it is not Working. Are there any other ways?
In Oracle the tablespace name is contained in the dba_tables view.
select owner, tablespace_name
from dba_tables
where table_name = 'MyTableName'
Alternatively you can use the user_tables view to see the table name and TS name of only tables the current schema contains.
select table_name, tablespace_name
from user_tables
where table_name = 'MyTableName'
This should work fine for you As it works for me.
Solution refered from: How to find the total tablespace usage in SQL Server 2008? by Oleg Dok
set nocount on
declare #indexes table(
QualifiedName nvarchar(512),
IndexId int,
FGName nvarchar(128),
Type nvarchar(50),
NumKeys int,
IndexKB numeric(28,0),
UsedKB numeric(28,0),
FreeKB numeric(28,0),
Rows numeric(28,0),
RowModCtr numeric(28,0),
OrigFillFactor int,
tableid bigint
)
insert into #indexes
select
db_name() + '.' + isnull(su.name,'<unknown-user>') + '.' + so.name + '.' + isnull(i.name,'<Heap>') QualifiedName,
i.index_id IndexId,
(select isnull(name,'') from sys.filegroups where data_space_id = i.data_space_id) FGName,
case
when so.type = 'V' then 'Indexed View: '
else ''
end +
case
when i.index_id = 0 then 'Heap'
when i.index_id = 1 then 'Clustered'
else 'Non Clustered'
end Type,
0 NumKeys,
a.used_pages* 8 IndexKB,
CASE
When a.type <> 1 Then a.used_pages * 8
When p.index_id < 2 Then a.data_pages * 8
Else 0
END UsedKB,
(a.total_pages-a.used_pages)* 8 FreeKB,
p.rows Rows,
0 RowModCtr,
i.fill_factor OrigFillFactor,
convert(bigint,db_id()) * power(convert(bigint,2),48) + convert(bigint,su.schema_id) * power(convert(bigint,2),32) + so.object_id tableid
from
sys.objects so with (readpast)
inner join sys.schemas su with (readpast) on su.schema_id = so.schema_id
inner join sys.indexes i with (readpast) on so.object_id = i.object_id
inner join sys.partitions p with (readpast) ON i.object_id = p.object_id and i.index_id = p.index_id
inner join sys.allocation_units a with (readpast) on p.partition_id = a.container_id
where
(so.type = 'U') and a.type_Desc = 'IN_ROW_DATA'
and isnull(INDEXPROPERTY(i.object_id, i.name, 'IsStatistics'),0) = 0
and isnull(INDEXPROPERTY(i.object_id, i.name, 'IsAutoStatistics'),0) = 0
and isnull(INDEXPROPERTY(i.object_id, i.name, 'IsHypothetical'),0) = 0
order by
IndexKB desc
select
i.QualifiedName,
i.IndexId,
i.FGName,
i.Type,
i.NumKeys,
i.IndexKB,
(i.UsedKB - isnull(t.s_UsedKB,0)) UsedKB,
(i.FreeKB - isnull(t.s_FreeKB,0)) FreeKB,
i.Rows,
i.RowModCtr,
i.OrigFillFactor
from
#indexes i
left outer join (
select tableid, sum(UsedKB) s_UsedKB, sum(FreeKB) s_FreeKB
from #indexes
where IndexId > 1
group by tableid
) t on t.tableid = i.tableid
and i.IndexId <= 1
order by
IndexKB desc
I am attempting to insert data about index usage into a control database of sorts.. The query I am using is below.. the issue I have is that when I execute the query from the control database (lets call it A) it returns 0 results, but if I execute it from the source database (lets call that B) it runs just fine..
why?
This behavior is being seen on both SQL Server 2012 DEV and SQL Server 2008 EE.
Example 1 returns zero results:
USE A;
INSERT INTO A.dbo.UnusedIndexes
SELECT
DB_NAME() AS DatabaseName
, SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(o.object_id) AS TableName
, ix.name AS IndexName
,((SUM(ps.used_page_count)over(partition by ix.index_id))*8)/1024 AS [IndexSizeMB]
, ix_usage_stats.user_updates
, ix_usage_stats.user_seeks + ix_usage_stats.user_scans + ix_usage_stats.user_lookups
AS [User_SeeksScansLookups]
, ix_usage_stats.system_updates
, ix_usage_stats.system_seeks + ix_usage_stats.system_scans + ix_usage_stats.system_lookups
AS [System_SeeksScansLookups]
, NULL as [Drop_Statement]
, NULL as [Create_statement]
,getdate() as [date_added]
FROM B.sys.indexes ix
Left join B.sys.dm_db_index_usage_stats ix_usage_stats
ON ix_usage_stats.object_id = ix.object_id
AND ix_usage_stats.index_id = ix.index_id
INNER JOIN B.sys.objects o ON ix.object_id = o.object_id
JOIN B.sys.dm_db_partition_stats ps ON ps.object_id = ix.object_id AND ix.index_id = ps.index_id
WHERE
ix.name IS NOT NULL -- exclude heaps
AND ix.type <> 1 -- exclude the clustered indexes
AND o.is_ms_shipped = 0 -- exclude system objects
AND o.type NOT IN('F', 'UQ') -- exclude the foreign keys and unique contraints
AND SCHEMA_NAME(o.schema_id) not in ('dbo','stats', 'reporting')
AND (ix_usage_stats.user_seeks = 0 or ix_usage_stats.user_seeks is NULL)
AND (ix_usage_stats.user_scans = 0 or ix_usage_stats.user_scans is null)
AND (ix_usage_stats.user_lookups = 0 or ix_usage_stats.user_lookups is null)
Example 2 returns the expected results, populating A.dbo.UnusedIndexes:
USE B;
INSERT INTO A.dbo.UnusedIndexes
SELECT
DB_NAME() AS DatabaseName
, SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(o.object_id) AS TableName
, ix.name AS IndexName
,((SUM(ps.used_page_count)over(partition by ix.index_id))*8)/1024 AS [IndexSizeMB]
, ix_usage_stats.user_updates
, ix_usage_stats.user_seeks + ix_usage_stats.user_scans + ix_usage_stats.user_lookups
AS [User_SeeksScansLookups]
, ix_usage_stats.system_updates
, ix_usage_stats.system_seeks + ix_usage_stats.system_scans + ix_usage_stats.system_lookups
AS [System_SeeksScansLookups]
, NULL as [Drop_Statement]
, NULL as [Create_statement]
,getdate() as [date_added]
FROM B.sys.indexes ix
Left join B.sys.dm_db_index_usage_stats ix_usage_stats
ON ix_usage_stats.object_id = ix.object_id
AND ix_usage_stats.index_id = ix.index_id
INNER JOIN B.sys.objects o ON ix.object_id = o.object_id
JOIN B.sys.dm_db_partition_stats ps ON ps.object_id = ix.object_id AND ix.index_id = ps.index_id
WHERE
ix.name IS NOT NULL -- exclude heaps
AND ix.type <> 1 -- exclude the clustered indexes
AND o.is_ms_shipped = 0 -- exclude system objects
AND o.type NOT IN('F', 'UQ') -- exclude the foreign keys and unique contraints
AND SCHEMA_NAME(o.schema_id) not in ('dbo','stats', 'reporting')
AND (ix_usage_stats.user_seeks = 0 or ix_usage_stats.user_seeks is NULL)
AND (ix_usage_stats.user_scans = 0 or ix_usage_stats.user_scans is null)
AND (ix_usage_stats.user_lookups = 0 or ix_usage_stats.user_lookups is null)
This works all day long:
USE A;
Select * from B.sys.indexes
Any help would be great - and unfortunately I am unable to execute this from database B, so the easy solution won't work.
Solved
Figured it out. the DB_NAME() was the issue. removing that and setting it to 'B' as databasename fixed the issue.
Try using sp_executesql from the target database:
USE A;
INSERT INTO A.dbo.UnusedIndexes
EXEC B.sys.sp_executesql N'
SELECT DB_NAME() AS DatabaseName
,SCHEMA_NAME(o.Schema_ID) AS SchemaName
,OBJECT_NAME(o.object_id) AS TableName
,ix.NAME AS IndexName
,((SUM(ps.used_page_count) OVER (PARTITION BY ix.index_id)) * 8) / 1024 AS [IndexSizeMB]
,ix_usage_stats.user_updates
,ix_usage_stats.user_seeks + ix_usage_stats.user_scans + ix_usage_stats.user_lookups AS [User_SeeksScansLookups]
,ix_usage_stats.system_updates
,ix_usage_stats.system_seeks + ix_usage_stats.system_scans + ix_usage_stats.system_lookups AS [System_SeeksScansLookups]
,NULL AS [Drop_Statement]
,NULL AS [Create_statement]
,getdate() AS [date_added]
FROM sys.indexes ix
LEFT JOIN sys.dm_db_index_usage_stats ix_usage_stats
ON ix_usage_stats.object_id = ix.object_id
AND ix_usage_stats.index_id = ix.index_id
INNER JOIN sys.objects o
ON ix.object_id = o.object_id
JOIN sys.dm_db_partition_stats ps
ON ps.object_id = ix.object_id
AND ix.index_id = ps.index_id
WHERE 1 = 1
AND ix.name IS NOT NULL -- exclude heaps
AND ix.type <> 1 -- exclude the clustered indexes
AND o.is_ms_shipped = 0 -- exclude system objects
AND o.type NOT IN(''F'', ''UQ'') -- exclude the foreign keys and unique contraints
AND SCHEMA_NAME(o.schema_id) not in (''dbo'',''stats'', ''reporting'')
AND (
ix_usage_stats.user_seeks = 0
OR ix_usage_stats.user_seeks IS NULL
)
AND (
ix_usage_stats.user_scans = 0
OR ix_usage_stats.user_scans IS NULL
)
AND (
ix_usage_stats.user_lookups = 0
OR ix_usage_stats.user_lookups IS NULL
)
'
I did batch to run SQL query like
use [AxDWH_Central_Reporting]
GO
EXEC sp_spaceused #updateusage = N'TRUE'
GO
It displays 2 tables and generates some ugly report with some kind of 'P' unneeded letters... See below
Changed database context to 'AxDWH_Central_Reporting'.
database_name Pdatabase_size Punallocated space
--------------------------------------------------------------------------------------------------------------------------------P------------------P------------------
AxDWH_Central_Reporting P10485.69 MB P7436.85 MB
reserved Pdata Pindex_size Punused
------------------P------------------P------------------P------------------
3121176 KB P3111728 KB P7744 KB P1704 KB
----------------------------------------------------------------
I also tryed to generate 1 table from this procedure with next query
declare
#dbname sysname,
#dbsize bigint,
#logsize bigint,
#reservedpages bigint
select
#reservedpages = sum(a.total_pages)
from
sys.partitions p join sys.allocation_units a on p.partition_id = a.container_id left join sys.internal_tables it on p.object_id = it.object_id
select
#dbsize = sum(convert(bigint,case when status & 64 = 0 then size else 0 end)),
#logsize = sum(convert(bigint,case when status & 64 <> 0 then size else 0 end))
from
dbo.sysfiles
select
'database name' = db_name(),
'database size' = ltrim(str((convert (dec (15,2),#dbsize) + convert (dec (15,2),#logsize)) * 8192 / 1048576,15,2) + ' MB'),
'unallocated space' = ltrim(str((case when #dbsize >= #reservedpages then
(convert (dec (15,2),#dbsize) - convert (dec (15,2),#reservedpages)) * 8192 / 1048576 else 0 end),15,2) + ' MB')
But got similar ugly report:
database name Pdatabase size Punallocated space
--------------------------------------------------------------------------------------------------------------------------------P------------------P------------------
master P5.75 MB P1.52 MB
(1 rows affected)
Is it possible to change the layout formatting for report? To make it more beautifull?
I doubt you can get SQLCMD and sp_spaceused formatted nicely - why don't you just use some other means of getting the information you need?
In SQL Server 2005 and up, use this piece of T-SQL to display the tables and the size they use:
SELECT
t.NAME AS TableName,
i.name as indexName,
p.[Rows],
sum(a.total_pages) as TotalPages,
sum(a.used_pages) as UsedPages,
sum(a.data_pages) as DataPages,
(sum(a.total_pages) * 8) / 1024 as TotalSpaceMB,
(sum(a.used_pages) * 8) / 1024 as UsedSpaceMB,
(sum(a.data_pages) * 8) / 1024 as DataSpaceMB
FROM
sys.tables t
INNER JOIN
sys.indexes i ON t.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
t.NAME NOT LIKE 'dt%' AND
i.OBJECT_ID > 255 AND
i.index_id <= 1
GROUP BY
t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
ORDER BY
object_name(i.object_id)
Works just fine for me! :-)
Marc