Wednesday, November 29, 2017

Use T-SQL to create caveman graphs



I found this technique on Rich Benner's SQL Server Blog: Visualising the Marvel Cinematic Universe in T-SQL and decided to play around with it after someone asked me to give him the sizes of all databases on a development instance of SQL Server

The way it works is that you take the size of the database and then divide that number against the total size of all databases. You then use the replicate function with the | (pipe) character to generate the 'graph'  so 8% will look like this ||||||||

You can use this for tables with most rows, a count per state etc etc. By looking at the output the graph column adds a nice visual effect to it IMHO


Here is what the final query looks like


SELECT 
       database_name = DB_NAME(database_id) 
     , total_size_GB = CAST(SUM(size) * 8. / 1024/1024 AS DECIMAL(30,2))
  , percent_size = (CONVERT(decimal(30,4),(SUM(size) /
     (SELECT SUM(CONVERT(decimal(30,4),size))  
     FROM sys.master_files WITH(NOWAIT)))) *100.00)
  , graph = replicate('|',((convert(decimal(30,2),(SUM(size) / 
    (SELECT SUM(CONVERT(decimal(30,2),size))  
     FROM sys.master_files WITH(NOWAIT)))) *100)))
FROM sys.master_files WITH(NOWAIT)
GROUP BY database_id
ORDER BY 3 DESC

And here is the output (I blanked out the DB name in the output below), there are 48 databases, 15 of them show a bar, the rest don't because they use less than 0.5% of space.


Do you see how you can quickly tell visually that the top DB is about twice as large as the next DB? 

Those guys in Lascaux would have been so proud, only if they could see this  :-)



5 comments:

  1. Good. Instead of referencing same table sys.master_files thrice , cte or
    sum over() can be used

    ;with dbsize_CTE as
    (
    select DBName = DB_NAME(database_id),
    CAST(SUM(size) * 8. / 1024/1024 AS DECIMAL(30,2)) as dbsize
    from sys.master_files WITH(NOWAIT)
    group by database_id
    ) ,

    totsize_CTE as
    (
    select sum(dbsize) as totsize
    from dbsize_CTE
    )

    select d.DBNAME,D.dbsize, percent_size = (D.dbsize/T.totsize) * 100.00 ,
    replicate ('|',(D.dbsize/T.totsize) * 100.00) as GraphPercent
    from dbsize_CTE as D,
    totsize_CTE as T
    order by percent_size desc

    ReplyDelete
  2. Simplistic and easy to adapt. Cool. Thanks for the post.

    ReplyDelete
  3. Wonderful ! Now,,, if only I can add in some colors ...

    ReplyDelete
  4. Thank you ! I tried to compare the actual execution plans. I also looked at statistics IO for both cases, Same, I think. Curious why, but will look more

    ReplyDelete
  5. sum over version

    select
    db_name(mf.database_id) database_name
    , sum(mf.size) * 8. / 1024 / 1024 total_size_GB
    , convert(
    numeric(19, 2)
    , sum(mf.size) * 100.0
    / sum(sum(mf.size)) over (partition by (select null))
    ) percent_size
    , replicate(
    '|'
    , sum(mf.size) * 100.0
    / sum(sum(mf.size)) over (partition by (select null))
    ) graph
    from
    sys.master_files mf
    group by
    mf.database_id
    order by
    percent_size desc

    ReplyDelete