{"id":4160,"date":"2012-08-23T23:40:33","date_gmt":"2012-08-23T23:40:33","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/sql-monitor-data-repository\/"},"modified":"2016-07-28T10:51:30","modified_gmt":"2016-07-28T10:51:30","slug":"sql-monitor-data-repository","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/sql-monitor-data-repository\/","title":{"rendered":"SQL Monitor&#8217;s data repository"},"content":{"rendered":"<p>As one of the developers of <a href=\"http:\/\/www.red-gate.com\/products\/dba\/sql-monitor\/\">SQL Monitor<\/a>, I often get requests passed on by our support people from customers who are looking to dip into SQL Monitor&#8217;s own data repository, in order to pull out bits of information that they&#8217;re interested in. Since there&#8217;s clearly interest out there in playing around directly with the data repository, I thought I&#8217;d write some blog posts to start to describe how it all works. The hardest part for me is knowing where to begin, since the schema of the data repository is pretty big. Hmmm&#8230; I guess it&#8217;s tricky for anyone to write anything but the most trivial of queries against the data repository without understanding the hierarchy of monitored objects, so perhaps my first post should start there.<\/p>\n<p>I always imagine that whenever a customer fires up SSMS and starts to explore their SQL Monitor data repository database, they become immediately bewildered by the schema &#8211; that was certainly my experience when I did so for the first time. The following query shows the number of different object types in the data repository schema:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT type_desc,\n    COUNT(*) AS [count]\n  FROM sys.objects\n  GROUP BY type_desc\n  ORDER BY type_desc;<\/pre>\n<div class=\"sql-query-results\">\n<table>\n<tbody>\n<tr>\n<th>&#160;<\/th>\n<th>type_desc<\/th>\n<th>count<\/th>\n<\/tr>\n<tr>\n<th>1<\/th>\n<td>DEFAULT_CONSTRAINT<\/td>\n<td>63<\/td>\n<\/tr>\n<tr>\n<th>2<\/th>\n<td>FOREIGN_KEY_CONSTRAINT<\/td>\n<td>181<\/td>\n<\/tr>\n<tr>\n<th>3<\/th>\n<td>INTERNAL_TABLE<\/td>\n<td>3<\/td>\n<\/tr>\n<tr>\n<th>4<\/th>\n<td>PRIMARY_KEY_CONSTRAINT<\/td>\n<td>190<\/td>\n<\/tr>\n<tr>\n<th>5<\/th>\n<td>SERVICE_QUEUE<\/td>\n<td>3<\/td>\n<\/tr>\n<tr>\n<th>6<\/th>\n<td>SQL_INLINE_TABLE_VALUED_FUNCTION<\/td>\n<td>381<\/td>\n<\/tr>\n<tr>\n<th>7<\/th>\n<td>SQL_SCALAR_FUNCTION<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<th>8<\/th>\n<td>SQL_STORED_PROCEDURE<\/td>\n<td>100<\/td>\n<\/tr>\n<tr>\n<th>9<\/th>\n<td>SYSTEM_TABLE<\/td>\n<td>41<\/td>\n<\/tr>\n<tr>\n<th>10<\/th>\n<td>UNIQUE_CONSTRAINT<\/td>\n<td>54<\/td>\n<\/tr>\n<tr>\n<th>11<\/th>\n<td>USER_TABLE<\/td>\n<td>193<\/td>\n<\/tr>\n<tr>\n<th>12<\/th>\n<td>VIEW<\/td>\n<td>124<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>With 193 tables, 124 views, 100 stored procedures and 381 table valued functions, that&#8217;s quite a hefty schema, and when you browse through it using SSMS, it can be a bit daunting at first. So, where to begin? Well, let&#8217;s narrow things down a bit and only look at the tables belonging to the <em>data<\/em> schema. That&#8217;s where all of the collected monitoring data is stored by SQL Monitor. The following query gives us the names of those tables:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT sch.name + '.' + obj.name AS [name]\n  FROM sys.objects obj \n  JOIN \n    sys.schemas sch\n  ON\n    sch.schema_id = obj.schema_id\n  WHERE obj.type_desc = 'USER_TABLE'\n    AND sch.name = 'data'\n  ORDER BY sch.name,\n    obj.name;<\/pre>\n<p>This query still returns 110 tables. I won&#8217;t show them all here, but let&#8217;s have a look at the first few of them:<\/p>\n<\/p>\n<div class=\"sql-query-results\">\n<table>\n<tbody>\n<tr>\n<th>&#160;<\/th>\n<th>name<\/th>\n<\/tr>\n<tr>\n<th>1<\/th>\n<td>data.Cluster_Keys<\/td>\n<\/tr>\n<tr>\n<th>2<\/th>\n<td>data.Cluster_Machine_ClockSkew_UnstableSamples<\/td>\n<\/tr>\n<tr>\n<th>3<\/th>\n<td>data.Cluster_Machine_Cluster_StableSamples<\/td>\n<\/tr>\n<tr>\n<th>4<\/th>\n<td>data.Cluster_Machine_Keys<\/td>\n<\/tr>\n<tr>\n<th>5<\/th>\n<td>data.Cluster_Machine_LogicalDisk_Capacity_StableSamples<\/td>\n<\/tr>\n<tr>\n<th>6<\/th>\n<td>data.Cluster_Machine_LogicalDisk_Keys<\/td>\n<\/tr>\n<tr>\n<th>7<\/th>\n<td>data.Cluster_Machine_LogicalDisk_Sightings<\/td>\n<\/tr>\n<tr>\n<th>8<\/th>\n<td>data.Cluster_Machine_LogicalDisk_UnstableSamples<\/td>\n<\/tr>\n<tr>\n<th>9<\/th>\n<td>data.Cluster_Machine_LogicalDisk_Volume_StableSamples<\/td>\n<\/tr>\n<tr>\n<th>10<\/th>\n<td>data.Cluster_Machine_Memory_Capacity_StableSamples<\/td>\n<\/tr>\n<tr>\n<th>11<\/th>\n<td>data.Cluster_Machine_Memory_UnstableSamples<\/td>\n<\/tr>\n<tr>\n<th>12<\/th>\n<td>data.Cluster_Machine_Network_Capacity_StableSamples<\/td>\n<\/tr>\n<tr>\n<th>13<\/th>\n<td>data.Cluster_Machine_Network_Keys<\/td>\n<\/tr>\n<tr>\n<th>14<\/th>\n<td>data.Cluster_Machine_Network_Sightings<\/td>\n<\/tr>\n<tr>\n<th>15<\/th>\n<td>data.Cluster_Machine_Network_UnstableSamples<\/td>\n<\/tr>\n<tr>\n<th>16<\/th>\n<td>data.Cluster_Machine_OperatingSystem_StableSamples<\/td>\n<\/tr>\n<tr>\n<th>17<\/th>\n<td>data.Cluster_Machine_Ping_UnstableSamples<\/td>\n<\/tr>\n<tr>\n<th>18<\/th>\n<td>data.Cluster_Machine_Process_Instances<\/td>\n<\/tr>\n<tr>\n<th>19<\/th>\n<td>data.Cluster_Machine_Process_Keys<\/td>\n<\/tr>\n<tr>\n<th>20<\/th>\n<td>data.Cluster_Machine_Process_Owner_Instances<\/td>\n<\/tr>\n<tr>\n<th>21<\/th>\n<td>data.Cluster_Machine_Process_Sightings<\/td>\n<\/tr>\n<tr>\n<th>22<\/th>\n<td>data.Cluster_Machine_Process_UnstableSamples<\/td>\n<\/tr>\n<tr>\n<th>23<\/th>\n<td>&#8230;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>There are two things I want to draw your attention to:<\/p>\n<ol>\n<li>The table names describe a hierarchy of the different <em>types<\/em> of object that are monitored by SQL Monitor (e.g. clusters, machines and disks).<\/li>\n<li>For each object type in the hierarchy, there are multiple tables, ending in the suffixes <em>_Keys<\/em>, <em>_Sightings<\/em>, <em>_StableSamples<\/em> and <em>_UnstableSamples<\/em>.<\/li>\n<\/ol>\n<p>Not every object type has a table for every suffix, but the <em>_Keys<\/em> suffix is especially important and a <em>_Keys<\/em> table does indeed exist for every object type. In fact, if we limit the query to return only those tables ending in <em>_Keys<\/em>, we reveal the full object hierarchy:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT sch.name + '.' + obj.name AS [name]\n  FROM sys.objects obj \n  JOIN \n    sys.schemas sch\n  ON\n    sch.schema_id = obj.schema_id\n  WHERE obj.type_desc = 'USER_TABLE'\n    AND sch.name = 'data'\n    AND obj.name LIKE '%_Keys'\n  ORDER BY sch.name,\n    obj.name;<\/pre>\n<div class=\"sql-query-results\">\n<table>\n<tbody>\n<tr>\n<th>&#160;<\/th>\n<th>name<\/th>\n<\/tr>\n<tr>\n<th>1<\/th>\n<td>data.Cluster_Keys<\/td>\n<\/tr>\n<tr>\n<th>2<\/th>\n<td>data.Cluster_Machine_Keys<\/td>\n<\/tr>\n<tr>\n<th>3<\/th>\n<td>data.Cluster_Machine_LogicalDisk_Keys<\/td>\n<\/tr>\n<tr>\n<th>4<\/th>\n<td>data.Cluster_Machine_Network_Keys<\/td>\n<\/tr>\n<tr>\n<th>5<\/th>\n<td>data.Cluster_Machine_Process_Keys<\/td>\n<\/tr>\n<tr>\n<th>6<\/th>\n<td>data.Cluster_Machine_Services_Keys<\/td>\n<\/tr>\n<tr>\n<th>7<\/th>\n<td>data.Cluster_ResourceGroup_Keys<\/td>\n<\/tr>\n<tr>\n<th>8<\/th>\n<td>data.Cluster_ResourceGroup_Resource_Keys<\/td>\n<\/tr>\n<tr>\n<th>9<\/th>\n<td>data.Cluster_SqlServer_Agent_Job_History_Keys<\/td>\n<\/tr>\n<tr>\n<th>10<\/th>\n<td>data.Cluster_SqlServer_Agent_Job_Keys<\/td>\n<\/tr>\n<tr>\n<th>11<\/th>\n<td>data.Cluster_SqlServer_Database_BackupType_Backup_Keys<\/td>\n<\/tr>\n<tr>\n<th>12<\/th>\n<td>data.Cluster_SqlServer_Database_BackupType_Keys<\/td>\n<\/tr>\n<tr>\n<th>13<\/th>\n<td>data.Cluster_SqlServer_Database_CustomMetric_Keys<\/td>\n<\/tr>\n<tr>\n<th>14<\/th>\n<td>data.Cluster_SqlServer_Database_File_Keys<\/td>\n<\/tr>\n<tr>\n<th>15<\/th>\n<td>data.Cluster_SqlServer_Database_Keys<\/td>\n<\/tr>\n<tr>\n<th>16<\/th>\n<td>data.Cluster_SqlServer_Database_Table_Index_Keys<\/td>\n<\/tr>\n<tr>\n<th>17<\/th>\n<td>data.Cluster_SqlServer_Database_Table_Keys<\/td>\n<\/tr>\n<tr>\n<th>18<\/th>\n<td>data.Cluster_SqlServer_Error_Keys<\/td>\n<\/tr>\n<tr>\n<th>19<\/th>\n<td>data.Cluster_SqlServer_Keys<\/td>\n<\/tr>\n<tr>\n<th>20<\/th>\n<td>data.Cluster_SqlServer_Services_Keys<\/td>\n<\/tr>\n<tr>\n<th>21<\/th>\n<td>data.Cluster_SqlServer_SqlProcess_Keys<\/td>\n<\/tr>\n<tr>\n<th>22<\/th>\n<td>data.Cluster_SqlServer_TopQueries_Keys<\/td>\n<\/tr>\n<tr>\n<th>23<\/th>\n<td>data.Cluster_SqlServer_Trace_Keys<\/td>\n<\/tr>\n<tr>\n<th>24<\/th>\n<td>data.Group_Keys<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>The full object type hierarchy looks like this:<\/p>\n<\/p>\n<ul>\n<li>     Cluster\n<ul>\n<li>         Machine\n<ul>\n<li>LogicalDisk<\/li>\n<li>Network<\/li>\n<li>Process<\/li>\n<li>Services<\/li>\n<\/ul>\n<\/li>\n<li>         ResourceGroup\n<ul>\n<li>Resource<\/li>\n<\/ul>\n<\/li>\n<li>         SqlServer\n<ul>\n<li>             Agent\n<ul>\n<li>                 Job\n<ul>\n<li>History<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>             Database\n<ul>\n<li>                 BackupType\n<ul>\n<li>Backup<\/li>\n<\/ul>\n<\/li>\n<li>CustomMetric<\/li>\n<li>File<\/li>\n<li>                 Table\n<ul>\n<li>Index<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Error<\/li>\n<li>Services<\/li>\n<li>SqlProcess<\/li>\n<li>TopQueries<\/li>\n<li>Trace<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Group<\/li>\n<\/ul>\n<p>Okay, but what about the individual objects themselves represented at each level in this hierarchy? Well that&#8217;s what the <em>_Keys<\/em> tables are for. This is probably best illustrated by way of a simple example &#8211; how can I query my own data repository to find the databases on my own PC for which monitoring data has been collected? Like this:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT clstr._Name AS cluster_name,\n    srvr._Name AS instance_name,\n    db._Name AS database_name\n  FROM data.Cluster_SqlServer_Database_Keys db\n  JOIN \n    data.Cluster_SqlServer_Keys srvr\n  ON\n    db.ParentId = srvr.Id  -- Note here how the parent of a Database is a Server\n  JOIN \n    data.Cluster_Keys clstr\n  ON\n    srvr.ParentId = clstr.Id -- Note here how the parent of a Server is a Cluster\n  WHERE clstr._Name = 'dev-chrisl2' -- This is the hostname of my own PC\n  ORDER BY clstr._Name,\n    srvr._Name,\n    db._Name;<\/pre>\n<div class=\"sql-query-results\">\n<table>\n<tbody>\n<tr>\n<th>&#160;<\/th>\n<th>cluster_name<\/th>\n<th>instance_name<\/th>\n<th>database_name<\/th>\n<\/tr>\n<tr>\n<th>1<\/th>\n<td>dev-chrisl2<\/td>\n<td><\/td>\n<td>SqlMonitorData<\/td>\n<\/tr>\n<tr>\n<th>2<\/th>\n<td>dev-chrisl2<\/td>\n<td><\/td>\n<td>master<\/td>\n<\/tr>\n<tr>\n<th>3<\/th>\n<td>dev-chrisl2<\/td>\n<td><\/td>\n<td>model<\/td>\n<\/tr>\n<tr>\n<th>4<\/th>\n<td>dev-chrisl2<\/td>\n<td><\/td>\n<td>msdb<\/td>\n<\/tr>\n<tr>\n<th>5<\/th>\n<td>dev-chrisl2<\/td>\n<td><\/td>\n<td>mssqlsystemresource<\/td>\n<\/tr>\n<tr>\n<th>6<\/th>\n<td>dev-chrisl2<\/td>\n<td><\/td>\n<td>tempdb<\/td>\n<\/tr>\n<tr>\n<th>7<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2005<\/td>\n<td>SqlMonitorData<\/td>\n<\/tr>\n<tr>\n<th>8<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2005<\/td>\n<td>TestDatabase<\/td>\n<\/tr>\n<tr>\n<th>9<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2005<\/td>\n<td>master<\/td>\n<\/tr>\n<tr>\n<th>10<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2005<\/td>\n<td>model<\/td>\n<\/tr>\n<tr>\n<th>11<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2005<\/td>\n<td>msdb<\/td>\n<\/tr>\n<tr>\n<th>12<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2005<\/td>\n<td>mssqlsystemresource<\/td>\n<\/tr>\n<tr>\n<th>13<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2005<\/td>\n<td>tempdb<\/td>\n<\/tr>\n<tr>\n<th>14<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2008<\/td>\n<td>SqlMonitorData<\/td>\n<\/tr>\n<tr>\n<th>15<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2008<\/td>\n<td>master<\/td>\n<\/tr>\n<tr>\n<th>16<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2008<\/td>\n<td>model<\/td>\n<\/tr>\n<tr>\n<th>17<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2008<\/td>\n<td>msdb<\/td>\n<\/tr>\n<tr>\n<th>18<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2008<\/td>\n<td>mssqlsystemresource<\/td>\n<\/tr>\n<tr>\n<th>19<\/th>\n<td>dev-chrisl2<\/td>\n<td>sql2008<\/td>\n<td>tempdb<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>These results show that I have three SQL Server instances on my machine (a default instance, one named <em>sql2005<\/em> and one named <em>sql2008<\/em>), and each instance has the usual set of system databases, along with a database named <em>SqlMonitorData<\/em>. Basically, this is where I test SQL Monitor on different versions of SQL Server, when I&#8217;m developing. There are a few important things we can learn from this query:<\/p>\n<ol>\n<li>Each <em>_Keys<\/em> table has a column named <em>Id<\/em>. This is the primary key.<\/li>\n<li>Each <em>_Keys<\/em> table has a column named <em>ParentId<\/em>. A foreign key relationship is defined between each <em>_Keys<\/em> table and its parent <em>_Keys<\/em> table in the hierarchy. There are two exceptions to this, <em>Cluster_Keys<\/em> and <em>Group_Keys<\/em>, because clusters and groups live at the root level of the object hierarchy.<\/li>\n<li>Each <em>_Keys<\/em> table has a column named <em>_Name<\/em>. This is used to uniquely identify objects in the table within the scope of the same shared parent object.<\/li>\n<\/ol>\n<p>Actually, that last item isn&#8217;t always true. In some cases, the <em>_Name<\/em> column is actually called something else. For example, the <em>data.Cluster_Machine_Services_Keys<\/em> table has a column named <em>_ServiceName<\/em> instead of <em>_Name<\/em> (sorry for the inconsistency). In other cases, a name isn&#8217;t sufficient to uniquely identify an object. For example, right now my PC has multiple processes running, all sharing the same name, <em>Chrome<\/em> (one for each tab open in my web-browser). In such cases, multiple columns are used to uniquely identify an object within the scope of the same shared parent object.<\/p>\n<p>Well, that&#8217;s it for now. I&#8217;ve given you enough information for you to explore the <em>_Keys<\/em> tables to see how objects are stored in your own data repositories. In a future post, I&#8217;ll try to explain how monitoring data is stored for each object, using the <em>_StableSamples<\/em> and <em>_UnstableSamples<\/em> tables. If you have any questions about this post, or suggestions for future posts, just submit them in the comments section below.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As one of the developers of SQL Monitor, I often get requests passed on by our support people from customers who are looking to dip into SQL Monitor&#8217;s own data repository, in order to pull out bits of information that they&#8217;re interested in. Since there&#8217;s clearly interest out there in playing around directly with the&#8230;&hellip;<\/p>\n","protected":false},"author":37766,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[],"coauthors":[],"class_list":["post-4160","post","type-post","status-publish","format-standard","hentry","category-blogs"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/4160","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/37766"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=4160"}],"version-history":[{"count":69,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/4160\/revisions"}],"predecessor-version":[{"id":42210,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/4160\/revisions\/42210"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=4160"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=4160"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=4160"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=4160"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}