[英]Selecting million records from SQL Server
我們需要索引(在ASP.NET中)存儲在SQL Server表中的所有記錄。 該表每行中也有大約2M條記錄,其中包含文本(nvarchar)數據。
是否可以一次性檢索所有記錄,因為我們需要為它們建立索引(用於搜索)? 另一個選擇是什么(我想避免分頁)?
注意 :我沒有顯示這些記錄,只需要一次性使用所有記錄,以便我可以通過后台線程對其進行索引。
我需要為查詢設置任何長時間超時嗎? 如果是,如果我從ASP.NET頁運行查詢,設置更長的超時時間最有效的方法是什么?
如果我需要這樣的東西,只是從數據庫方面考慮,我可能會將其導出到文件中。 然后,該文件可以很容易地移動。 遍歷這么大的數據集對所有相關人員來說都是巨大的痛苦。 您可以在批處理命令中使用SSIS,sqlcmd甚至bcp來完成它。
然后,您只需要擔心在應用程序方面對其進行的操作,導出后就不必擔心鎖定以及數據庫方面的所有問題。
我認為無論如何頁面都不是一個好地方。 應該有一個不同的過程或程序來執行此操作。 在相關說明中,例如http://incubator.apache.org/lucene.net/可能對您有所幫助?
是否可以一次性檢索所有記錄,因為我們需要為它們建立索引(用於搜索)? 另一個選擇是什么(我想避免分頁)?
內存管理問題/性能問題
如果要帶來200萬條記錄,則可能會遇到系統內存不足異常,因為所有這些記錄都將保留在DataSet中,而數據集的內存將在RAM中。
我需要為查詢設置任何長時間超時嗎? 如果是,如果我從ASP.NET頁運行查詢,設置更長的超時時間最有效的方法是什么?
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand())
{
cmd.CommandTimeout = 0;
}
建議
您在“提取變換負載”(ETL)中描述的內容。 我知道2個選項:
我更喜歡Rhino.Etl,因為它完全是用C#編寫的,您可以在Boo中創建腳本,並且測試和編寫ETL流程要容易得多。 而且該庫是為處理大量數據而構建的,因此內置了內存管理。
最后一點:雖然asp.net可能是開始建立索引過程的切入點,但是我不會在asp.net中運行該過程,因為它可能要花幾分鍾或幾小時,具體取決於記錄和處理的數量。
而是讓asp.net作為觸發后台任務以處理記錄的入口點。 理想情況下,完全獨立於asp.net,因此可以避免任何超時或關機問題。
批量處理記錄。 您將有兩個主要問題。 (1)您需要索引所有現有記錄。 (2)您將要使用添加,更新或刪除的記錄來更新索引。 刪除索引並重新創建索引似乎聽起來很容易,但應盡可能避免這樣做。 下面是一個示例,以10,000條記錄的批處理方式[Production].[TransactionHistory]
AdventureWorks2008R2
數據庫中的[Production].[TransactionHistory]
。 它不會將所有記錄加載到內存中。 我的本地計算機上的輸出Processed 113443 records in 00:00:00.2282294
產生已Processed 113443 records in 00:00:00.2282294
。 顯然,這沒有考慮遠程計算機和每個記錄的處理時間。
class Program
{
private static string ConnectionString
{
get { return ConfigurationManager.ConnectionStrings["db"].ConnectionString; }
}
static void Main(string[] args)
{
int recordCount = 0;
int lastId = -1;
bool done = false;
Stopwatch timer = Stopwatch.StartNew();
do
{
done = true;
IEnumerable<TransactionHistory> transactionDataRecords = GetTransactions(lastId, 10000);
foreach (TransactionHistory transactionHistory in transactionDataRecords)
{
lastId = transactionHistory.TransactionId;
done = false;
recordCount++;
}
} while (!done);
timer.Stop();
Console.WriteLine("Processed {0} records in {1}", recordCount, timer.Elapsed);
}
/// Get a new open connection
private static SqlConnection GetOpenConnection()
{
SqlConnection connection = new SqlConnection(ConnectionString);
connection.Open();
return connection;
}
private static IEnumerable<TransactionHistory> GetTransactions(int lastTransactionId, int count)
{
const string sql = "SELECT TOP(@count) [TransactionID],[TransactionDate],[TransactionType] FROM [Production].[TransactionHistory] WHERE [TransactionID] > @LastTransactionId ORDER BY [TransactionID]";
return GetData<TransactionHistory>((connection) =>
{
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@count", count);
command.Parameters.AddWithValue("@LastTransactionId", lastTransactionId);
return command;
}, DataRecordToTransactionHistory);
}
// funtion to convert a data record to the TransactionHistory object
private static TransactionHistory DataRecordToTransactionHistory(IDataRecord record)
{
TransactionHistory transactionHistory = new TransactionHistory();
transactionHistory.TransactionId = record.GetInt32(0);
transactionHistory.TransactionDate = record.GetDateTime(1);
transactionHistory.TransactionType = record.GetString(2);
return transactionHistory;
}
private static IEnumerable<T> GetData<T>(Func<SqlConnection, SqlCommand> commandBuilder, Func<IDataRecord, T> dataFunc)
{
using (SqlConnection connection = GetOpenConnection())
{
using (SqlCommand command = commandBuilder(connection))
{
using (IDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
T record = dataFunc(reader);
yield return record;
}
}
}
}
}
}
public class TransactionHistory
{
public int TransactionId { get; set; }
public DateTime TransactionDate { get; set; }
public string TransactionType { get; set; }
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.