Determining page count on each SQL table without using DBCC - sql

I am trying to compress the largest tables in my database. I will do this by running the SP_ForEachDB stored procedure. However I cannot figure out how to view the total page count. I can get the row count with this query...
USE DEVELOP04_HiltonUS
GO
SELECT
[TableName] = so.name,
[RowCount] = MAX(si.rows)
FROM
sysobjects so,
sysindexes si
WHERE
so.xtype = 'U'
AND
si.id = OBJECT_ID(so.name)
GROUP BY
so.name
ORDER BY
2 DESC
Which returns:
TABLE NAME ROW COUNT
PlannedShift 38268660
BudgetStaffStat 19353104
BudgetKBIStat 14142631
EmployeeShiftAdjustment 13493745
Requirement 11020921
EmployeeShiftError 6857235
JobclassLaborData 5638692
and so on for all my tables.
I am looking for the same thing but returning page Count instead.

SELECT OBJECT_SCHEMA_NAME(s.object_id) schema_name,
OBJECT_NAME(s.object_id) table_name,
SUM(s.used_page_count) used_pages,
SUM(s.reserved_page_count) reserved_pages
FROM sys.dm_db_partition_stats s
JOIN sys.tables t
ON s.object_id = t.object_id
GROUP BY s.object_id
ORDER BY schema_name,
table_name;

Related

SQL Server - Get approximate size of table

In production, issuing a SELECT COUNT can be a bad idea - it can be a performance hit depending on your database engine. In Oracle, if I want to get an idea of the size of a table without having to resort to a COUNT, I can do the following:
SELECT
table_name,
num_rows,
last_analyzed
FROM all_tables
WHERE table_name = 'MY_TABLE_NAME';
This will retrieve Oracle's table analyses if they're enabled. While the count isn't exact, it can give me an idea of how large a table is in case I need to query it (and the last_analyzed column lets me know how old that approximation is).
How can I do something similar in SQL Server? (Related - is this necessary for SQL Server? Oracle has to count row-by-row, hence the avoidance.)
Thanks!
You can use the management studio also
Right Click on table -> Properties -> Storage
or you can use the query like this:
sp_spaceused 'TableName'
To get it for all the tables you can use it like tihs:
CREATE TABLE #tmp
(
tableName varchar(100),
numberofRows varchar(100),
reservedSize varchar(50),
dataSize varchar(50),
indexSize varchar(50),
unusedSize varchar(50)
)
insert #tmp
EXEC sp_MSforeachtable #cmd="EXEC sp_spaceused '?'"
select * from #tmp
You can call sp_spaceused 'table_name'.
If you want to do this for all tables, wrap it inside sp_MSforeachtable:
sp_MSforeachtable 'sp_spaceused ''[?]'''
Calling sp_spaceused without any parameter will give you the database size.
Courtesy: #marc_s
SELECT
s.Name AS SchemaName,
t.NAME AS TableName,
p.rows AS RowCounts,
SUM(a.total_pages) * 8 AS TotalSpaceKB,
SUM(a.used_pages) * 8 AS UsedSpaceKB,
(SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
FROM
sys.tables t
INNER JOIN
sys.schemas s ON s.schema_id = t.schema_id
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%' -- filter out system tables for diagramming
AND t.is_ms_shipped = 0
AND i.OBJECT_ID > 255
GROUP BY
t.Name, s.Name, p.Rows
ORDER BY
s.Name, t.Name
If absolute accuracy isn't vital this is a very quick route to an approximate row count; if your SQL Server is a supported version it should have this dmv.
SELECT SUM (row_count)
FROM sys.dm_db_partition_stats
WHERE object_id=OBJECT_ID('MY_TABLE_NAME')
AND (index_id=0 or index_id=1);

SQL grouping results

I'm trying to get the last time a table was updated by the users:
Declare #Collect Table (Name Varchar(100),last_user_update datetime)
Insert into #Collect
EXEC sp_MSForEachTable 'SELECT ''?'' as TableName,
last_user_update
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID(''SP3D_DB_RESEARCH_MDB'') AND OBJECT_ID = OBJECT_ID(''?'')'
SELECT * FROM #Collect ORDER BY last_user_update DESC
The problem is that in the results, some tables are appearing 3 times (please see the image bellow)
Since it appears that all tables duplicated have the same last updated time. Is there any way to group the results by the table name?
If the values are indeed the same, you can just add DISTINCT to the query, and have it return unique results
SELECT DISTINCT ''?'' as TableName, last_user_update ...
If you want to group after the fact, and only the last update interests you, you can do
SELECT TableName, max(last_user_update) as last_update
FROM #Collect
GROUP BY TableName
ORDER BY 2 DESC
Tables can have multiple indexes. The dynamic management view sys.dm_db_index_usage_stats will have separate entries for each index.
If you want to see the index name for each one, try this:
SELECT
o.name as TableName,
i.name as IndexName,
istats.last_user_update
from sys.dm_db_index_usage_stats istats
inner join sys.objects o
on o.object_id = istats.object_id
inner join sys.indexes i
on i.index_id = istats.index_id
and i.object_id = istats.object_id
order by
o.name,
i.name
Or, if you don't care about that and just want the last update time, you can group by the table name:
SELECT
o.name as TableName,
max(istats.last_user_update)
from sys.dm_db_index_usage_stats istats
inner join sys.objects o
on o.object_id = istats.object_id
group by
o.name
You can do an insert directly into your table with this query:
declare #Collect table (Name varchar(100),last_user_update datetime)
insert into #Collect
select
o.name as TableName,
istats.last_user_update
from sys.dm_db_index_usage_stats istats
inner join sys.objects o
on o.object_id = istats.object_id
inner join sys.indexes i
on i.index_id = istats.index_id
and i.object_id = istats.object_id
where database_id = db_id('SP3D_DB_RESEARCH_MDB')
Also, I'm not sure what your goal is, but please understand that this view only has entries for indexes that have activity on them. If an index is unused, it is not in this view. The first access creates a row in the view. The real interesting stuff on this view is the seek and scan information.
See this note from MSDN:
When an index is used, a row is added to sys.dm_db_index_usage_stats
if a row does not already exist for the index. When the row is added,
its counters are initially set to zero.
If your goal is to enumerate all the indexes and then show the last update date for all of them, you'll need to join to sys.indexes and then left join to sys.dm_db_index_usage_stats.

T-SQL: Show stored procedures related to tables, cyclically

I'm using the following t-sql code:
USE [my_database]
SELECT DISTINCT so.name
FROM syscomments sc
INNER JOIN sysobjects so ON sc.id=so.id
WHERE sc.TEXT LIKE '%table_name%'
in order to show all the Stored Procedures that use the table table_name.
I want do this work for all tables in my database.
How can I perform this task and organize the output?
This uses information schema for both tables, and stored procedures. You can change or get rid of ROUTINE_TYPE condition to add functions, and you can change table type to return views.
This answer produces its results by checking what tables a stored procedure depends on. I think this will be a much more accurate result then checking if a name is in the query text. If the procedure refers to a table in a comment section, then this result will not be returned in the first query, but will be in the second and other answers given.
SELECT t.TABLE_NAME, s.ROUTINE_NAME
FROM INFORMATION_SCHEMA.TABLES t
INNER JOIN INFORMATION_SCHEMA.ROUTINES s ON
s.ROUTINE_NAME IN (SELECT referencing_entity_name
FROM sys.dm_sql_referencing_entities(TABLE_SCHEMA + '.' + TABLE_NAME, 'OBJECT'))
AND s.ROUTINE_TYPE = 'PROCEDURE'
WHERE t.TABLE_TYPE = 'BASE TABLE'
edit: Here's how to get the dependencies without the function. (I like this method the best)
SELECT DISTINCT t.name [TableName], p.name [ProcedureName]
FROM sys.objects t
LEFT JOIN sys.sql_dependencies d ON
d.referenced_major_id = t.object_id
LEFT JOIN sys.objects p ON
p.object_id = d.object_id
AND p.type = 'p'
WHERE t.type = 'u'
If your specific use is to just find any string that matches a table name, below will work:
SELECT t.TABLE_NAME, s.ROUTINE_NAME
FROM INFORMATION_SCHEMA.TABLES t
INNER JOIN INFORMATION_SCHEMA.ROUTINES s
ON CHARINDEX(t.TABLE_NAME, s.ROUTINE_DEFINITION) > 0
AND s.ROUTINE_TYPE = 'PROCEDURE'
WHERE t.TABLE_TYPE = 'BASE TABLE'
You could do a JOIN on LIKE:
select * from INFORMATION_SCHEMA.TABLES t
join
(
SELECT DISTINCT so.name
FROM syscomments sc
INNER JOIN sysobjects so ON sc.id=so.id
) x on x.name like '%' + t.TABLE_NAME + '%'
Note that your query doesn't restrict to procs - you'll also get views, defaults, and other objects too. If you just want procs, you can add where so.xtype = 'P' to your inner query.
Another version that uses sys tables only:
select t.name as TableName, p.name as SPName
from sys.objects t
join sys.syscomments c
on c.text like '%' + t.name + '%'
join sys.objects p
on p.object_id = c.id
where t.type = 'U' -- user table
and p.type = 'P' -- procedure
You can also use the built in function that's been around at least since SQL 2005 and works for tables, views, and stored procedures. I get the same number of results as Daniel's answer above when checking dependencies on a table in a fairly enterprisy database.
sp_depends [TableName]
sp_depends [TableName.Column]
sp_depends [StoredProcedureName]
http://msdn.microsoft.com/en-us/library/ms189487(v=sql.90).aspx

Query to get tables having indexing in a particular database

Can anyone provide me the query in sql server to extract the tables that have been done indexing, for a particular database....
Your question is somewhat unclear. This will return all tables with at least one index.
select DISTINCT OBJECT_NAME(object_id)
from sys.indexes
where type<>0
Or for SQL Server 2000
select DISTINCT OBJECT_NAME(id)
from sysindexes
where indid<>0
select object_name(object_id),* from sys.indexes where type <> 0
This will return you all the indexes available in your database. But beware, it also lists the system tables.
The sys.indexes DMV should have what you're looking for:
SELECT TableName = object_name(Object_Id)
, IndexName = Name
, IndexType = Type_Desc
FROM sys.indexes
The Type_Desc column will tell you whether you're looking at a heap, a clustered index, or a non-clustered index.
Joining to sys.tables will limit the results to user tables and leave out system tables:
SELECT TableName = st.Name
, IndexName = si.name
, IndexType = si.type_desc
FROM SYS.indexes si
JOIN SYS.tables st
ON si.object_id = st.object_id

SQL Server 2008 - find table with most rows

Is there a way in SQL Server 2008 to find the table with the most rows in the database?
This will get you close:
SELECT
[TableName] = so.name,
[RowCount] = MAX(si.rows)
FROM
sysobjects so,
sysindexes si
WHERE
so.xtype = 'U'
AND
si.id = OBJECT_ID(so.name)
GROUP BY
so.name
ORDER BY
2 DESC
Here's basically the same T-SQL that Chris Ballance provided, but using the new Object Catalog Views instead of the compatability views:
SELECT SchemaName = schemas.[name],
TableName = tables.[name],
IndexName = indexes.[name],
IndexType =
CASE indexes.type
WHEN 0 THEN 'Heap'
WHEN 1 THEN 'Clustered'
END,
IndexPartitionCount = partition_info.PartitionCount,
IndexTotalRows = partition_info.TotalRows
FROM sys.tables
JOIN sys.indexes
ON tables.object_id = indexes.object_id
AND indexes.type IN ( 0, 1 )
JOIN ( SELECT object_id, index_id, PartitionCount = COUNT(*), TotalRows = SUM(rows)
FROM sys.partitions
GROUP BY object_id, index_id
) partition_info
ON indexes.object_id = partition_info.object_id
AND indexes.index_id = partition_info.index_id
JOIN sys.schemas ON tables.schema_id = schemas.schema_id
ORDER BY SchemaName, TableName;
I just customize my SSMS 2008 to show the following additional columns
for tables
- Row Count
- Data Space Used (KB)
for databases
- Primary Data Location
- Last Backup Date
- Created Date
....
Works quicker for me most of the time without opening a query, I just click on the column header to go ASC or DESC