估计从SQL返回的数据集的大小

时间:2016-08-05 06:00:20

标签: c# sql-server dapper seq

我们有一个似乎消耗大量数据的系统,它使用Dapper进行数据库查询,使用Seq进行日志记录。我想知道除了SQL Profiler之外是否有办法将记录添加到Dapper以记录以MB为单位返回的数据集的大小 - 我们可以标记大型数据集以供审阅吗?

这个问题has been asked a while ago但是我想知道现在是否有一种方法可以在没有wireshark的情况下进行,理想情况下不会迭代行/单元格?

3 个答案:

答案 0 :(得分:1)

我将为基本存储库类中的连接配置Provider Statistics for SQL Server。您可以添加配置设置以将其打开,并轻松将此信息保存到日志文件或您想要的任何位置。

来自MSDN的示例代码

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;

namespace CS_Stats_Console_GetValue
{
  class Program
  {
    static void Main(string[] args)
    {
      string connectionString = GetConnectionString();

      using (SqlConnection awConnection = 
        new SqlConnection(connectionString))
      {
        // StatisticsEnabled is False by default.
        // It must be set to True to start the 
        // statistic collection process.
        awConnection.StatisticsEnabled = true;

        string productSQL = "SELECT * FROM Production.Product";
        SqlDataAdapter productAdapter = 
          new SqlDataAdapter(productSQL, awConnection);

        DataSet awDataSet = new DataSet();

        awConnection.Open();

        productAdapter.Fill(awDataSet, "ProductTable");
        // Retrieve the current statistics as
        // a collection of values at this point
        // and time.
        IDictionary currentStatistics =
          awConnection.RetrieveStatistics();

        Console.WriteLine("Total Counters: " +
          currentStatistics.Count.ToString());
        Console.WriteLine();

        // Retrieve a few individual values
        // related to the previous command.
        long bytesReceived =
            (long) currentStatistics["BytesReceived"];
        long bytesSent =
            (long) currentStatistics["BytesSent"];
        long selectCount =
            (long) currentStatistics["SelectCount"];
        long selectRows =
            (long) currentStatistics["SelectRows"];

        Console.WriteLine("BytesReceived: " +
            bytesReceived.ToString());
        Console.WriteLine("BytesSent: " +
            bytesSent.ToString());
        Console.WriteLine("SelectCount: " +
            selectCount.ToString());
        Console.WriteLine("SelectRows: " +
            selectRows.ToString());

        Console.WriteLine();
        Console.WriteLine("Press any key to continue");
        Console.ReadLine();
      }

    }
    private static string GetConnectionString()
    {
      // To avoid storing the connection string in your code,
      // you can retrive it from a configuration file.
      return "Data Source=localhost;Integrated Security=SSPI;" + 
        "Initial Catalog=AdventureWorks";
    }
  }
}

答案 1 :(得分:0)

不是一个完整的答案,但可能会帮助你。

sys.dm_exec_query_statssys.dm_exec_connections可能会帮助您跟踪大型结果集。例如:

SELECT * FROM sys.dm_exec_query_stats 
CROSS APPLY sys.dm_exec_sql_text(sql_handle)

(单位为8k页)。

此类为您提供了目前使用wireshark的内容(有点:)

SELECT * FROM sys.dm_exec_connections
CROSS APPLY sys.dm_exec_sql_text(most_recent_sql_handle)
ORDER BY num_writes DESC

https://msdn.microsoft.com/en-us/library/ms189741.aspx

https://msdn.microsoft.com/en-AU/library/ms181509.aspx

答案 2 :(得分:0)

您可以估算行总和每个列类型大小所需的大小,然后乘以行数。如果您的查询中没有TEXT / VARCHAR,那么它应该是准确的:

int rowSize = 0;
foreach(DataColumn dc in Dataset1.Tables[0].Columns) {
    rowSize += sizeof(dc.DataType);
}
int dataSize = rowSize * Dataset1.Tables[0].Rows.Count;

如果您需要更准确的数字,请使用Marshal.SizeOf总结每个单独值的大小:

int dataSize = 0;
foreach(DataRow dr in Dataset1.Tables[0].Rows) 
{
    int rowSize = 0;
    for (int i = 0; i < Dataset1.Tables[0].Columns.Count; i++)
    {
        rowSize += System.Runtime.InteropServices.Marshal.SizeOf(dr[i]);
    }
    dataSize += rowSize;
}

如果不考虑高精度,性能提升的想法:

  1. 计算样本的大小。假设,不是遍历所有行,而是每100个中选择1,然后将结果乘以100。
  2. 使用[Marshal.SizeOf]((https://msdn.microsoft.com/en-us/library/y3ybkfb3.aspx)来计算每个DataRow dr的大小,而不是迭代它的所有值。由于DataRow对象有额外的值,它会给你一个更高的数字属性,但这可以通过减去空DataRow的大小来调整。
  3. 事先知道单行的平均大小,按列数,然后乘以行数。