簡體   English   中英

從SQL Server選擇百萬條記錄

[英]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;
}

建議

  1. 最好從數據庫級別過濾掉記錄...
  2. 從數據庫中獲取所有記錄並將其保存在文件中。 訪問該文件以進行任何中間操作。

您在“提取變換負載”(ETL)中描述的內容。 我知道2個選項:

  1. SSIS是SQL Server的一部分
  2. Rhino.ETL

我更喜歡Rhino.Etl,因為它完全是用C#編寫的,您可以在Boo中創建腳本,並且測試和編寫ET​​L流程要容易得多。 而且該庫是為處理大量數據而構建的,因此內置了內存管理。

最后一點:雖然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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM