Przygody z oprogramowaniem
  • Start
  • Szkolenia
    • Szkolenia otwarte
    • Katalog szkoleń
  • Usługi
    • Konsulting
    • Mentoring
    • Research & Development
  • Blog
  • Wiedza
    • Strefa wiedzy
    • BFsharp
    • SaaS
  • Klienci
  • Kontakt
0

Estimating Rows

10 August, 2007-SQL

Problem

Several months ago, I was thinking how to effectively support scrollbarscount the number of rows on huge lists. Although the former is impractical in practice, the latter could be valuable. For example, we could turn on grouping on our grids when the number of rows is small enough. Otherwise a user would know that she should narrow down her search criteria.

Solution

Actual count would be very expensive, so we should find a way to estimate that number. The best way to do this is to utilize Sql Server Estimated Plans. Enable estimated plan generation, submit the query and take the magic number from returned xml.

SET SHOWPLAN_XML ON;
GO

SELECT * FROM Production.Product WHERE name LIKE '%a%';

However there is one problem, SET SHOWPLAN_XML cannot be specified inside a stored procedure and must be the only statement in a batch. We could use Sql trace however it saves data to a file.
Other possibility is to make use of SQLCLR – several lines of code and everything is ready:

[Microsoft.SqlServer.Server.SqlProcedure]
public static void GetEstimatedRows(string sql,
    [param: SqlFacet(Precision = 19, Scale = 4)] out SqlDecimal estimatedRows)
{
    estimatedRows = -1;
 
    using (SqlConnection c = new SqlConnection("Context Connection=true"))
    {
        c.Open();
        SqlCommand cmd = new SqlCommand("set showplan_xml on;", c);
        cmd.ExecuteNonQuery();
 
        SqlCommand cmd2 = new SqlCommand(sql, c);
        using (XmlReader r = cmd2.ExecuteXmlReader())
        {
            while (r.Read())
            {
                if (r.Name == "StmtSimple")
                {
                    NumberFormatInfo provider = new NumberFormatInfo();
                    provider.NumberDecimalSeparator = ".";
                    estimatedRows = Convert.ToDecimal(r.GetAttribute("StatementEstRows"), provider);
                    break;
                }
            }
        }
    }
}

Now we’re able to estimate statement recordset size from within T-SQL:

DECLARE

@sql VARCHAR(MAX);
SET @sql = 'SELECT * FROM Production.Product WHERE name LIKE ''%a%''';
DECLARE @rows DECIMAL(19,4);
EXEC GetEstimatedRows @sql, @rows OUTPUT;
SELECT @rows;

Using the same tactic we can get arbitrary information out of the estimated plan. For example:

DECLARE @sql VARCHAR(MAX);

SET @sql = 'SELECT * FROM Production.Product WHERE name LIKE ''%a%''';
DECLARE @cost DECIMAL(19,7);
EXEC GetEstimatedPlanCost @sql, @cost OUTPUT;

SELECT @cost;

Kategorie

Architecture BFsharp Blog Business Framework C# CqRS DDD Debugging DSL EntityFramework Formula JavaScript Linq NHibernate SaaS Silverlight SQL Visual Studio WPF Wzorce

O mnie


RSS Feed

© macmichal.pl 2011 Wszystkie prawa zastrzeżone

Używamy ciasteczek, jeśli kontynuujesz zwiedzanie strony, zakładamy, że wyrażasz zgodę na ich używanie.RozumiemCzytaj więcej