Table Space growth based on each year

  • Does there a way or script to find the rows, space used by the specific tables based on every year.

    Thanks

  • Admingod (10/28/2015)


    Does there a way or script to find the rows, space used by the specific tables based on every year.

    Thanks

    No, you have to monitor/audit it yourself. Normally I use sys.partitions, sys.allocation_units, sys.tables etc. to periodically gather the information.

    😎

  • Same here. It allows you to track growth over time, but I only track databases. I don't go down to the table level, although it does sound like an interesting idea. That's a whole new level of graphing. 😉

  • At the database level, I'll say "kind of" but only if you know what your database backup sizes have been or that info is still in the MSDB database.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • I am populating all the table information to main table on daily basis based on date time stamp. However, how to create a script to query against the table. Any ideas?

    Thanks

  • I have all the information gathered in the tables, howerver i want to show the row count and size growth based on the each year for specific tables.

    Thanks

  • So you're already gathering the data about the space used by each table? It sounds like you've got the hard part done already. Post the DDL for your table and some consumable sample data so we have something to work with. Also, what do you expect to see for your output?

  • Admingod (10/28/2015)


    I am populating all the table information to main table on daily basis based on date time stamp. However, how to create a script to query against the table. Any ideas?

    Thanks

    Here is one I sometimes use, the MONITORING_DB database being the central collection point

    😎

    CREATE PROCEDURE [dbo].[LOG_MY_TABLES]

    AS

    SET NOCOUNT ON;

    DECLARE @SQL_STR NVARCHAR(MAX) = N'

    USE {{@DBNAME}}

    INSERT INTO MONITORING_DB.dbo.TBL_TABLE_LOG

    (

    [SERVER_NAME]

    ,[DB_NAME]

    ,[SCHEMA_NAME]

    ,[TABLE_NAME]

    ,[INDEX_NAME]

    ,[ROWS]

    ,[TOTAL_PAGES]

    ,[USED_PAGES]

    ,[DATA_PAGES]

    ,[TOTAL_MB]

    ,[USED_MB]

    ,[DATA_MB]

    )

    SELECT

    @@SERVERNAME AS [SERVER_NAME]

    ,DB_NAME(DB_ID()) AS [DB_NAME]

    ,OBJECT_SCHEMA_NAME(SPART.object_id) AS [SCHEMA_NAME]

    ,STAB.name AS [TABLE_NAME]

    ,SIDX.name AS [INDEX_NAME]

    ,SPART.rows AS [ROWS]

    ,SUM(SALU.total_pages ) AS [TOTAL_PAGES]

    ,SUM(SALU.used_pages ) AS [USED_PAGES]

    ,SUM(SALU.data_pages ) AS [DATA_PAGES]

    ,(8 * SUM(SALU.total_pages )) / 1024.0 AS [TOTAL_MB]

    ,(8 * SUM(SALU.used_pages )) / 1024.0 AS [USED_MB]

    ,(8 * SUM(SALU.data_pages )) / 1024.0 AS [DATA_MB]

    FROM sys.tables STAB

    INNER JOIN sys.indexes SIDX

    ON STAB.object_id = SIDX.object_id

    INNER JOIN sys.partitions SPART

    ON SIDX.object_id = SPART.object_id

    AND SIDX.index_id = SPART.index_id

    INNER JOIN sys.allocation_units SALU

    ON SPART.partition_id = SALU.container_id

    WHERE SIDX.index_id IN (0,1)

    AND STAB.object_id > 255

    GROUP BY STAB.name

    ,SIDX.name

    ,SPART.object_id

    ,SPART.rows

    ;

    ';

    DECLARE @EXEC_STR NVARCHAR(MAX) = N'';

    SELECT @EXEC_STR =

    (

    SELECT

    REPLACE(@SQL_STR,N'{{@DBNAME}}', QUOTENAME(SDB.name))

    FROM master.sys.databases SDB

    WHERE SDB.name NOT IN (N'master',N'tempdb',N'model',N'msdb')

    AND SDB.state_desc = N'ONLINE'

    FOR XML PATH(''),TYPE).value('.[1]','NVARCHAR(MAX)');

    EXEC (@EXEC_STR);

    Edit: Added QUOTENAME to prevent malicious database naming sql injection;-).

  • Eirikur Eiriksson (10/28/2015)


    Admingod (10/28/2015)


    I am populating all the table information to main table on daily basis based on date time stamp. However, how to create a script to query against the table. Any ideas?

    Thanks

    Here is one I sometimes use, the MONITORING_DB database being the central collection point

    😎

    CREATE PROCEDURE [dbo].[LOG_MY_TABLES]

    AS

    SET NOCOUNT ON;

    DECLARE @SQL_STR NVARCHAR(MAX) = N'

    USE {{@DBNAME}}

    INSERT INTO MONITORING_DB.dbo.TBL_TABLE_LOG

    (

    [SERVER_NAME]

    ,[DB_NAME]

    ,[SCHEMA_NAME]

    ,[TABLE_NAME]

    ,[INDEX_NAME]

    ,[ROWS]

    ,[TOTAL_PAGES]

    ,[USED_PAGES]

    ,[DATA_PAGES]

    ,[TOTAL_MB]

    ,[USED_MB]

    ,[DATA_MB]

    )

    SELECT

    @@SERVERNAME AS [SERVER_NAME]

    ,DB_NAME(DB_ID()) AS [DB_NAME]

    ,OBJECT_SCHEMA_NAME(SPART.object_id) AS [SCHEMA_NAME]

    ,STAB.name AS [TABLE_NAME]

    ,SIDX.name AS [INDEX_NAME]

    ,SPART.rows AS [ROWS]

    ,SUM(SALU.total_pages ) AS [TOTAL_PAGES]

    ,SUM(SALU.used_pages ) AS [USED_PAGES]

    ,SUM(SALU.data_pages ) AS [DATA_PAGES]

    ,(8 * SUM(SALU.total_pages )) / 1024.0 AS [TOTAL_MB]

    ,(8 * SUM(SALU.used_pages )) / 1024.0 AS [USED_MB]

    ,(8 * SUM(SALU.data_pages )) / 1024.0 AS [DATA_MB]

    FROM sys.tables STAB

    INNER JOIN sys.indexes SIDX

    ON STAB.object_id = SIDX.object_id

    INNER JOIN sys.partitions SPART

    ON SIDX.object_id = SPART.object_id

    AND SIDX.index_id = SPART.index_id

    INNER JOIN sys.allocation_units SALU

    ON SPART.partition_id = SALU.container_id

    WHERE SIDX.index_id IN (0,1)

    AND STAB.object_id > 255

    GROUP BY STAB.name

    ,SIDX.name

    ,SPART.object_id

    ,SPART.rows

    ;

    ';

    DECLARE @EXEC_STR NVARCHAR(MAX) = N'';

    SELECT @EXEC_STR =

    (

    SELECT

    REPLACE(@SQL_STR,N'{{@DBNAME}}', SDB.name)

    FROM master.sys.databases SDB

    WHERE SDB.name NOT IN (N'master',N'tempdb',N'model',N'msdb')

    AND SDB.state_desc = N'ONLINE'

    FOR XML PATH(''),TYPE).value('.[1]','NVARCHAR(MAX)');

    EXEC (@EXEC_STR);

    That's pretty slick, Eirikur. I appreciate how you use string replacement using the rows in sys.databases to generate the final SQL to fire. I've noticed that there aren't many of us who use that approach, even though it's so very efficient. Thanks for sharing it.

    Back to the OP. Can you post the DDL of your data collection table, some consumable sample data and what you'd like to see in the output?

  • Ed Wagner (10/29/2015)


    That's pretty slick, Eirikur. I appreciate how you use string replacement using the rows in sys.databases to generate the final SQL to fire. I've noticed that there aren't many of us who use that approach, even though it's so very efficient. Thanks for sharing it.

    I don't believe I knew you back when I did lightning rounds at SPID for this method. Joe Flemming walked up to me and gave me a bear hug because I had just made something he was having severe problems doing a whole lot easier using such token replacement methods.

    It does come with a warning though. You absolute must delouse any type of user input because it's still a concatenation of sorts. For example, the use of QUOTENAME (or similar if you need more than 128 characters) is still important, in such cases as well as other delousing techniques.

    For the DBA, though... I agree.... It's freakin' awesome and makes life sooooooo much easier.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Jeff Moden (10/29/2015)


    Ed Wagner (10/29/2015)


    That's pretty slick, Eirikur. I appreciate how you use string replacement using the rows in sys.databases to generate the final SQL to fire. I've noticed that there aren't many of us who use that approach, even though it's so very efficient. Thanks for sharing it.

    I don't believe I knew you back when I did lightning rounds at SPID for this method. Joe Flemming walked up to me and gave me a bear hug because I had just made something he was having severe problems doing a whole lot easier using such token replacement methods.

    It does come with a warning though. You absolute must delouse any type of user input because it's still a concatenation of sorts. For example, the use of QUOTENAME (or similar if you need more than 128 characters) is still important, in such cases as well as other delousing techniques.

    For the DBA, though... I agree.... It's freakin' awesome and makes life sooooooo much easier.

    I think you're right. I can just imaging Joe bear-hugging you for something cool like this. I wish I would have seen the surprised look on your face when he did it. 😛

    For this case, I'm going to be the only one who has permission to run it and there won't be any input to clean, but your point is well-taken. It's absolutely string concatenation, but it'll be clean as built. Just out of habit, when I created it, the QUOTENAME function is added around the name in the final SELECT that builds the full list.

    It's not only much simpler, but it's also faster to build the strings. As an added bonus, we get to avoid a loop. 😀 I honestly don't know why some people rail against it, but it is what it is.

  • Maybe a bit redundant now.

    Only a single database is targeted.

    Ben

    -- ben brugman

    -- 20151029

    --

    CREATE TABLE ##TableSizes (name sysname, rows varchar(16),

    reserved varchar(16), data varchar(16), index_size varchar(16),unused varchar(16))

    INSERT ##TableSizes

    EXEC sp_MSforeachtable @command1="EXEC sp_spaceused '?'"

    update ##TableSizes set

    Reserved = replace(reserved,'kb',''),

    index_size = replace(index_size,'kb',''),

    data = replace(data,'kb',''),

    unused = replace(unused,'kb','')

    CREATE TABLE ##TableSizes2 (name sysname, rows bigint,

    reserved bigint, data bigint, index_size bigint,unused bigint)

    insert into ##TableSizes2 select * from ##TableSizes

    SELECT * FROM ##TableSizes2

    ORDER BY reserved desc

    drop table ##TableSizes

    drop table ##TableSizes2

  • Ed Wagner (10/29/2015)


    Jeff Moden (10/29/2015)


    Ed Wagner (10/29/2015)


    That's pretty slick, Eirikur. I appreciate how you use string replacement using the rows in sys.databases to generate the final SQL to fire. I've noticed that there aren't many of us who use that approach, even though it's so very efficient. Thanks for sharing it.

    I don't believe I knew you back when I did lightning rounds at SPID for this method. Joe Flemming walked up to me and gave me a bear hug because I had just made something he was having severe problems doing a whole lot easier using such token replacement methods.

    It does come with a warning though. You absolute must delouse any type of user input because it's still a concatenation of sorts. For example, the use of QUOTENAME (or similar if you need more than 128 characters) is still important, in such cases as well as other delousing techniques.

    For the DBA, though... I agree.... It's freakin' awesome and makes life sooooooo much easier.

    I think you're right. I can just imaging Joe bear-hugging you for something cool like this. I wish I would have seen the surprised look on your face when he did it. 😛

    For this case, I'm going to be the only one who has permission to run it and there won't be any input to clean, but your point is well-taken. It's absolutely string concatenation, but it'll be clean as built. Just out of habit, when I created it, the QUOTENAME function is added around the name in the final SELECT that builds the full list.

    It's not only much simpler, but it's also faster to build the strings. As an added bonus, we get to avoid a loop. 😀 I honestly don't know why some people rail against it, but it is what it is.

    Jeff is absolutely right, quotename must be there, consider this

    😎

    USE master;

    GO

    SET NOCOUNT ON;

    CREATE DATABASE [MALICIOUSNAME];

    CREATE DATABASE [MALICIOUSNAME; DROP DATABASE XXX];

    and then the stored procedure's output

    USE MALICIOUSNAME; DROP DATABASE XXX

    INSERT INTO MONITORING_DB.dbo.TBL_TABLE_LOG

    (

    [SERVER_NAME]

    ,[DB_NAME]

    ,[SCHEMA_NAME]

    ,[TABLE_NAME]

    ,[INDEX_NAME]

    ,[ROWS]

    ,[TOTAL_PAGES]

    ,[USED_PAGES]

    ,[DATA_PAGES]

    ,[TOTAL_MB]

    ,[USED_MB]

    ,[DATA_MB]

    )

    SELECT

    @@SERVERNAME AS [SERVER_NAME]

    ,DB_NAME(DB_ID()) AS [DB_NAME]

    ,OBJECT_SCHEMA_NAME(SPART.object_id) AS [SCHEMA_NAME]

    ,STAB.name AS [TABLE_NAME]

    ,SIDX.name AS [INDEX_NAME]

    ,SPART.rows AS [ROWS]

    ,SUM(SALU.total_pages ) AS [TOTAL_PAGES]

    ,SUM(SALU.used_pages ) AS [USED_PAGES]

    ,SUM(SALU.data_pages ) AS [DATA_PAGES]

    ,(8 * SUM(SALU.total_pages )) / 1024.0 AS [TOTAL_MB]

    ,(8 * SUM(SALU.used_pages )) / 1024.0 AS [USED_MB]

    ,(8 * SUM(SALU.data_pages )) / 1024.0 AS [DATA_MB]

    FROM sys.tables STAB

    INNER JOIN sys.indexes SIDX

    ON STAB.object_id = SIDX.object_id

    INNER JOIN sys.partitions SPART

    ON SIDX.object_id = SPART.object_id

    AND SIDX.index_id = SPART.index_id

    INNER JOIN sys.allocation_units SALU

    ON SPART.partition_id = SALU.container_id

    WHERE SIDX.index_id IN (0,1)

    AND STAB.object_id > 255

    GROUP BY STAB.name

    ,SIDX.name

    ,SPART.object_id

    ,SPART.rows

    ;

    Runs without an error!

  • Ed Wagner (10/29/2015)


    That's pretty slick, Eirikur. I appreciate how you use string replacement using the rows in sys.databases to generate the final SQL to fire. I've noticed that there aren't many of us who use that approach, even though it's so very efficient. Thanks for sharing it.

    You are welcome Ed;-)

    I use this method quite extensively as it lessens the maintenance, think of systems with hundreds or thousands of client specific databases, often tens of databases per client.

    😎

  • I put the QUOTENAME around the database name in the query that concatenates the final SQL.

    SELECT @EXEC_STR =

    (

    SELECT REPLACE(@SQL_STR,N'{{@DBNAME}}', QUOTENAME(SDB.name))

    FROM master.sys.databases SDB

    WHERE SDB.name NOT IN (N'master',N'tempdb',N'model',N'msdb')

    AND SDB.state_desc = N'ONLINE'

    FOR XML PATH(''),TYPE).value('.[1]','NVARCHAR(MAX)');

Viewing 15 posts - 1 through 14 (of 14 total)

You must be logged in to reply to this topic. Login to reply