加载 2500 万条记录后,T-SQL 处理速度变慢



问题是为什么我在 2500 万条记录上速度变慢了。这是 SQL Server 配置问题、代码还是两者兼而有之?

加载大约 2500 万条记录后,在例程pGetOHLCBetweenTwoDates(...)(请参阅下面的代码)中,以下行

SqlDataReader rdr = sqlCmd.ExecuteReader();

从 T-SQL (SQL SERVER) 加载记录所需的时间是原来的 20 倍。每次传递加载多少条记录(50k、100k、250k)并不重要,速度减慢始终在 25m 左右(请参阅下面的日志摘录)。

这不是资源问题,运行它的系统有 128 GB 内存,双 8 核和 SQL Server 有 8 GB 内存可用,SQL Server 在本地运行,SQL Server 增加到 32 GB 看看这是否可以解决问题,它没有。我在 SQL Server 探查器端看到同样的事情 500-600 毫秒跳到 10,000 - 30,000 毫秒。

idxLoadPos 25249999 - 运行时间 00:00:00.9609748 idxLoadPos 25099999 - 运行时间 00:00:00.5936540 idxLoadPos 24949999 - 运行时间 00:00:00.5890105 idxLoadPos 24799999 - 运行时间 00:00:

11.5260435
<---<<加载
了大约 2500 万条记录 idxLoadPos 24649999 - 运行时间 00:00:10.9329704 idxLoadPos 24499999 - 运行时间 00:00
:11.2460554

法典:

public static int GetOHLCBetweenTwoDates(ref OHLCArray ohlcArray, int currentIndex, DateTime fromDate, DateTime toDate, DataFeedConfig dataFeedConfig)
{
// loads an array bottom up to match the standards in TA-LIBRARY in C Sharp
DateTime fDate = fromDate;
DateTime tDate = toDate;
int recordCount = SQL.GetCountBetweenTwoDates(fromDate, toDate, ohlcArray.TimePeriod, dataFeedConfig);
int maxReturnCount = LoadRecordCount;
//int maxReturnCount = 100000;
int getRecordCount = maxReturnCount;
int remainingRecordCount = recordCount;
int idxArrayLoadPosition = currentIndex;
Console.WriteLine("SQL - int - GetOHLCBetweenTwoDates from: {0}, to: {1}, getRecordCount: {2} ", fDate.ToString(), tDate.ToString(), getRecordCount.ToString());
while (fDate <= tDate & remainingRecordCount > 1) //0
{
getRecordCount = (remainingRecordCount < maxReturnCount) ? remainingRecordCount : maxReturnCount;
fDate = SQL.pGetOHLCBetweenTwoDates(ref ohlcArray, ref idxArrayLoadPosition, getRecordCount, fDate, tDate, ohlcArray.TimePeriod, dataFeedConfig);
remainingRecordCount -= (getRecordCount - 1); // no -1
Console.WriteLine("SQL - GetOHLCBetweenTwoDates from: {0}, to: {1}, getRecordCount: {2} ", fDate.ToString(), tDate.ToString(), getRecordCount.ToString());
}
idxArrayLoadPosition++;
if (idxArrayLoadPosition == -1) { idxArrayLoadPosition = 0; }
return idxArrayLoadPosition;
}
private static DateTime pGetOHLCBetweenTwoDates(ref OHLCArray ohlcArray, ref int idxArrayLoadPosition, int recordCount, DateTime fromDate, DateTime toDate, Enums.TimePeriodTypes tpt, DataFeedConfig dataFeedConfig)
{
DateTime returnDate = new DateTime(1901, 01, 01);
string database = "" + dataFeedConfig.Exchange + "." + dataFeedConfig.Issue + ".Data"; //string database = "[" + Exchange + "." + Issue + ".Data]";
string userName = dataFeedConfig.sqlLoginCredentials.SQLUserName;
string password = dataFeedConfig.sqlLoginCredentials.SQLPassword;
string server = dataFeedConfig.sqlLoginCredentials.SQLServerName;
string tableName = "Data." + tpt;
string connString = "server=" + server + ";uid=" + userName + ";pwd=" + password + ";database=" + database + ";Integrated Security=True;";
string databaseAndTable = "[" + database + "].[dbo].[" + tableName + "]"; /* [database].[dbo].[table], database = [Exchange.Issue.Data], table = [Data.TimePeriods(enum)] */
string sqlQueryString = "SELECT  TOP " + recordCount.ToString() + " * FROM " + databaseAndTable + " WHERE  [dtTime] >= '" + fromDate.ToString() + "' AND [dtTime] <= '" + toDate.ToString() + "' ORDER BY [dtTime] ASC";
using (SqlConnection sqlConnection = new SqlConnection(connString))
{
sqlConnection.Open();
using (SqlCommand sqlCmd = new SqlCommand(sqlQueryString, sqlConnection))
{
SqlDataReader rdr = sqlCmd.ExecuteReader();
while (rdr.Read())
{
ohlcArray.dtTime[idxArrayLoadPosition] = (DateTime)(rdr.GetSqlDateTime(0));
ohlcArray.High[idxArrayLoadPosition] = (double)(rdr.GetSqlDouble(1));
ohlcArray.Low[idxArrayLoadPosition] = (double)(rdr.GetSqlDouble(2));
ohlcArray.Open[idxArrayLoadPosition] = (double)(rdr.GetSqlDouble(3));
ohlcArray.Close[idxArrayLoadPosition] = (double)(rdr.GetSqlDouble(4));
ohlcArray.Volume[idxArrayLoadPosition] = int.Parse(rdr.GetSqlInt32(5).ToString());
returnDate = ohlcArray.dtTime[idxArrayLoadPosition];
idxArrayLoadPosition--;
}
rdr.Close();
}
sqlConnection.Close();
}
return returnDate;
}

关于下一步要去哪个方向解决这个问题的任何想法?

编辑:更多信息...这些表具有以下结构:

string cTable = "CREATE TABLE " + dbAndTable + " ([dtTime] [datetime] NOT NULL,[Bid] [float] NULL, [Ask] [float] NULL,[Volume] [float] NULL) ON [PRIMARY] ";
string cIndex = "CREATE INDEX " + indexName + " ON " + dbAndTable + " (dtTime)";<br/>

[dTime]列应该是主键,而不仅仅是索引吗?

我的朋友,您最大的问题是您通过从字符串"fromdate"和"todate"转换为您使用提供的 CREATE TABLE 语句建立的日期时间数据类型来强制 SQL Server 为您执行的隐式数据转换。

这是对在如此大的表上运行的处理的惩罚。我相信你应该

  1. 修改 CREATE TABLE 语句以在表的 identity(1,1) 列上包含一个主键和聚集索引。

  2. 使用"买入价"、"卖出价"和"交易量"列的"包含"选项修改"创建索引"。

  3. 编写一个存储过程,将所需的顶部,下限日期和上限作为数据类型INT,日期时间,日期时间作为参数传递。

  4. 重构调用代码以执行存储过程。

据我所知,这些都是公认的最佳实践。

跟进:我注意到您在从数据库带回所有记录后正在实现分页......相反,使用 FETCH NEXT 使用 SQL SERVER 实现分页将加快处理速度。在存储过程中实现必要的参数。

首先我们需要知道延迟类型:

请运行 sp_whoisactive @get_plans=1。谷歌和下载谁活动,如果你没有。

然后检查等待类型列。它会告诉您等待类型。请在这里发布我们可以看看。

在不知道等待类型的情况下,有几个可能的原因: 1. 通常在加载 25m 行后,缓冲池会受到影响:现有的缓存数据或编译的计划可能会被推回,以便为加载的行腾出空间。

  1. 您可能有async_network_io等待类型,这并不一定意味着您有网络延迟,其中一个可能的原因是SQL SERVER在发送更多数据之前正在等待客户端处理数据。

最新更新