SQL Server 2008 R2 SP1 and SQL Server 2012 RTM+ includes actual row count statistics in the sys.dm_exec_query_stats dynamic management view.\u00a0 This includes the total_rows, last_rows, min_rows and max_rows columns, which are intuitively named.<\/p>\n
One potential use of the row statistics data is to detect cardinality estimate issues where the actual count of rows is significantly different from the query plan\u2019s estimated rows.\u00a0 While I can see using this information as a valid approach, there are limits, and I\u2019ll walk through them in this post.<\/p>\n
To illustrate the use cases, I\u2019m going to use the Credit<\/a> database to execute three different queries.\u00a0 I\u2019ll show you the plan tree tab from SQL Sentry Plan Explorer<\/a> for each query.<\/p>\n Query 1: No Cardinality Estimate Issue<\/strong><\/p>\n The plan:<\/p>\n For each operation in this query, the estimated rows match the actual rows.<\/p>\n Query 2: Cardinality Estimate Issue, Leaf-Level + Final Operator<\/strong><\/p>\n The plan:<\/p>\n Unlike the previous query, for this query we have leaf-level estimated vs. actual row count skews and skews that flow up to the final operation.<\/p>\n Query 3: Cardinality Estimate Leaf-Level Skew and No Skew for Root Operator<\/strong><\/p>\n The plan:<\/p>\n\r\nSELECT region.region_name,\r\n member.lastname,\r\n member.firstname,\r\n member.member_no\r\nFROM dbo.member\r\nINNER JOIN dbo.region\r\n ON region.region_no = member.region_no\r\nWHERE region.region_no = 9;\r\nGO\r\n<\/pre>\n
<\/pre>\n
<\/a><\/p>\n\r\nDECLARE @Column INT = 2,\r\n @Value INT = 10;\r\n\r\nSELECT [member].[member_no],\r\n [member].[street],\r\n [member].[city],\r\n [charge].[charge_no],\r\n [charge].[provider_no],\r\n [charge].[category_no],\r\n [charge].[charge_dt],\r\n [charge].[charge_amt],\r\n [charge].[charge_code]\r\nFROM [dbo].[charge]\r\nINNER JOIN [dbo].[member]\r\n ON [member].[member_no] = [charge].[member_no]\r\nWHERE CHOOSE(@Column, [charge].[provider_no], [charge].[category_no]) = @Value;\r\nGO\r\n\r\n<\/pre>\n
<\/a><\/p>\n\r\nSELECT TOP (1000)\r\n [member].[member_no],\r\n [member].[lastname],\r\n [member].[firstname],\r\n [region].[region_no],\r\n [region].[region_name],\r\n [provider].[provider_name],\r\n [category].[category_desc],\r\n [charge].[charge_no],\r\n [charge].[provider_no],\r\n [charge].[category_no],\r\n [charge].[charge_dt],\r\n [charge].[charge_amt],\r\n [charge].[charge_code]\r\nFROM [dbo].[provider]\r\nINNER JOIN [dbo].[charge]\r\n ON [provider].[provider_no] = [charge].[provider_no]\r\nINNER JOIN [dbo].[member]\r\n ON [member].[member_no] = [charge].[member_no]\r\nINNER JOIN [dbo].[region]\r\n ON [region].[region_no] = [member].[region_no]\r\nINNER JOIN [dbo].[category]\r\n ON [category].[category_no] = [charge].[category_no];\r\nGO\r\n\r\n<\/pre>\n