代码之家  ›  专栏  ›  技术社区  ›  Gup3rSuR4c

Sql Server 2008大型事务优化(700k+行/事务)

  •  5
  • Gup3rSuR4c  · 技术社区  · 14 年前

    数据库基本上需要每月更新一次。必须清除主表,然后从CSV文件中重新填充。问题是SQLServer会为它生成一个非常大的日志。我成功地灌满了一次,但想通过吹扫然后再灌满来测试整个过程。

    这时我得到一个错误,日志文件被填满了。它从88MB(通过维护计划缩减后)跳到248MB,然后完全停止进程,永远不会完成。

    感谢您提前回复!

    根据@mattmc3的建议,我已经为整个过程实现了SqlBulkCopy。它的工作原理很神奇,除了,我的循环在最后一个需要插入的块上崩溃了。我不太确定哪里出了问题,见鬼,我甚至不知道这是不是一个适当的循环,所以我很感谢一些帮助。

    我知道这是最后一次GetDataTable或SetSqlBulkCopy调用的问题。我试着插入788189行,788000行进入,剩下的189行正在崩溃。。。

    string[] Rows;
    
    using (StreamReader Reader = new StreamReader("C:/?.csv")) {
        Rows = Reader.ReadToEnd().TrimEnd().Split(new char[1] {
            '\n'
         }, StringSplitOptions.RemoveEmptyEntries);
    };
    
    int RowsInserted = 0;
    
    using (SqlConnection Connection = new SqlConnection("")) {
        Connection.Open();
    
        DataTable Table = null;
    
        while ((RowsInserted < Rows.Length) && ((Rows.Length - RowsInserted) >= 1000)) {
            Table = GetDataTable(Rows.Skip(RowsInserted).Take(1000).ToArray());
    
            SetSqlBulkCopy(Table, Connection);
    
            RowsInserted += 1000;
        };
    
        Table = GetDataTable(Rows.Skip(RowsInserted).ToArray());
    
        SetSqlBulkCopy(Table, Connection);
    
        Connection.Close();
    };
    
    static DataTable GetDataTable(
        string[] Rows) {
        using (DataTable Table = new DataTable()) {
            Table.Columns.Add(new DataColumn("A"));
            Table.Columns.Add(new DataColumn("B"));
            Table.Columns.Add(new DataColumn("C"));
            Table.Columns.Add(new DataColumn("D"));
    
            for (short a = 0, b = (short)Rows.Length; a < b; a++) {
                string[] Columns = Rows[a].Split(new char[1] {
                    ','
                }, StringSplitOptions.RemoveEmptyEntries);
    
                DataRow Row = Table.NewRow();
    
                Row["A"] = Columns[0];
                Row["B"] = Columns[1];
                Row["C"] = Columns[2];
                Row["D"] = Columns[3];
    
                Table.Rows.Add(Row);
            };
    
            return (Table);
        };
    }
    
    static void SetSqlBulkCopy(
        DataTable Table,
        SqlConnection Connection) {
        using (SqlBulkCopy SqlBulkCopy = new SqlBulkCopy(Connection)) {
            SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("A", "A"));
            SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("B", "B"));
            SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("C", "C"));
            SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("D", "D"));
    
            SqlBulkCopy.BatchSize = Table.Rows.Count;
            SqlBulkCopy.DestinationTableName = "E";
            SqlBulkCopy.WriteToServer(Table);
        };
    }
    

    编辑/最终代码: 因此,该应用程序现在已经完成,工作惊人,相当迅速@谢谢你的帮助!以下是最后一段代码,供任何可能觉得有用的人使用:

    List<string> Rows = new List<string>();
    
    using (StreamReader Reader = new StreamReader(@"?.csv")) {
        string Line = string.Empty;
    
        while (!String.IsNullOrWhiteSpace(Line = Reader.ReadLine())) {
            Rows.Add(Line);
        };
    };
    
    if (Rows.Count > 0) {
        int RowsInserted = 0;
    
        DataTable Table = new DataTable();
    
        Table.Columns.Add(new DataColumn("Id"));
        Table.Columns.Add(new DataColumn("A"));
    
        while ((RowsInserted < Rows.Count) && ((Rows.Count - RowsInserted) >= 1000)) {
            Table = GetDataTable(Rows.Skip(RowsInserted).Take(1000).ToList(), Table);
    
            PerformSqlBulkCopy(Table);
    
            RowsInserted += 1000;
    
            Table.Clear();
        };
    
        Table = GetDataTable(Rows.Skip(RowsInserted).ToList(), Table);
    
        PerformSqlBulkCopy(Table);
    };
    
    static DataTable GetDataTable(
        List<string> Rows,
        DataTable Table) {
        for (short a = 0, b = (short)Rows.Count; a < b; a++) {
            string[] Columns = Rows[a].Split(new char[1] {
                ','
            }, StringSplitOptions.RemoveEmptyEntries);
    
            DataRow Row = Table.NewRow();
    
            Row["A"] = "";
    
            Table.Rows.Add(Row);
        };
    
        return (Table);
    }
    
    static void PerformSqlBulkCopy(
        DataTable Table) {
        using (SqlBulkCopy SqlBulkCopy = new SqlBulkCopy(@"", SqlBulkCopyOptions.TableLock)) {
            SqlBulkCopy.BatchSize = Table.Rows.Count;
            SqlBulkCopy.DestinationTableName = "";
            SqlBulkCopy.WriteToServer(Table);
        };
    }
    
    3 回复  |  直到 14 年前
        1
  •  5
  •   mattmc3    14 年前

    如果要在SQLServer中对表进行大容量插入,则应该这样做( BCP , Bulk Insert Insert Into...Select ,或在.NET中 SqlBulkCopy http://msdn.microsoft.com/en-us/library/ms189275.aspx

        2
  •  2
  •   Aheho    14 年前

    可以分别为每个数据库设置恢复模型。也许是 简单的 恢复模式将适用于您。简单模型:

    自动回收日志空间以保持较小的空间需求,从根本上消除了管理事务日志空间的需要。

    好好读一读 here .

        3
  •  1
  •   Raj More    14 年前

    无法绕过在SQLServer中使用事务日志。