估计从 SQL 返回的数据集的大小
Estimate the size of a dataset returned from SQL
我们的系统似乎消耗了大量数据,它使用 Dapper 进行数据库查询,使用 Seq 进行日志记录。我想知道除了使用 SQL Profiler 之外,是否有一种方法可以将日志记录添加到 Dapper 以记录以 MB 为单位返回的数据集的大小 - 这样我们就可以标记大型数据集以供审查?
这个问题 has been asked a while ago 但我想知道现在是否有一种方法可以不用 wireshark 并且最好不用遍历 rows/cells?
不是真正完整的答案,但可能对您有所帮助。
sys.dm_exec_query_stats
和 sys.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
您可以估算一行所需的大小,将每个列类型的大小相加,然后乘以行数。如果您的查询中没有 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;
}
如果不考虑高精度,提高性能的想法:
- 计算一个样本的大小。比方说,不是遍历所有行,而是每 100 行中选择 1 行,然后最后将结果乘以 100。
- 使用 [Marshal.SizeOf]((https://msdn.microsoft.com/en-us/library/y3ybkfb3.aspx) 计算每个 DataRow 的大小
dr
而不是遍历它的所有值。它会给你一个更大的数字,因为DataRow 对象具有其他属性,但您可以通过减去空 DataRow 的大小来调整这些属性。
- 事先知道单行的平均大小,通过它的列数,然后乘以行数。
我会为基础存储库 class 中的连接配置 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";
}
}
}
我们仅通过 capping/limiting 查询大小就解决了这个限制。这使我们不必担心大小和进行双重查询。我们使用的 PR 您也可以使用 https://github.com/DapperLib/Dapper/pull/1758/files
我们的系统似乎消耗了大量数据,它使用 Dapper 进行数据库查询,使用 Seq 进行日志记录。我想知道除了使用 SQL Profiler 之外,是否有一种方法可以将日志记录添加到 Dapper 以记录以 MB 为单位返回的数据集的大小 - 这样我们就可以标记大型数据集以供审查?
这个问题 has been asked a while ago 但我想知道现在是否有一种方法可以不用 wireshark 并且最好不用遍历 rows/cells?
不是真正完整的答案,但可能对您有所帮助。
sys.dm_exec_query_stats
和 sys.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
您可以估算一行所需的大小,将每个列类型的大小相加,然后乘以行数。如果您的查询中没有 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;
}
如果不考虑高精度,提高性能的想法:
- 计算一个样本的大小。比方说,不是遍历所有行,而是每 100 行中选择 1 行,然后最后将结果乘以 100。
- 使用 [Marshal.SizeOf]((https://msdn.microsoft.com/en-us/library/y3ybkfb3.aspx) 计算每个 DataRow 的大小
dr
而不是遍历它的所有值。它会给你一个更大的数字,因为DataRow 对象具有其他属性,但您可以通过减去空 DataRow 的大小来调整这些属性。 - 事先知道单行的平均大小,通过它的列数,然后乘以行数。
我会为基础存储库 class 中的连接配置 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";
}
}
}
我们仅通过 capping/limiting 查询大小就解决了这个限制。这使我们不必担心大小和进行双重查询。我们使用的 PR 您也可以使用 https://github.com/DapperLib/Dapper/pull/1758/files