C# 最好的解决方法是什么+;帮助我充分理解到目前为止我发现的东西

C# 最好的解决方法是什么+;帮助我充分理解到目前为止我发现的东西,c#,.net,sql-server,performance,linq-to-sql,C#,.net,Sql Server,Performance,Linq To Sql,所以我在这里看到了这篇文章并阅读了它,看起来批量复制可能是一条出路 我还有一些问题,想知道事情到底是如何运作的 所以我找到了两本教程 第一种方式使用2个ado.net 2.0功能。批量插入和批量复制。第二种方法使用LINQtoSQL和OpenXML 这对我很有吸引力,因为我已经在使用LINQtoSQL,并且更喜欢它而不是ado.net。然而,正如一个人在帖子中指出的那样,他只是以性能为代价来处理这个问题(我认为这没有错) 首先,我将在第一个教程中讨论这两种方法 我使用的是VS2010 Ex

所以我在这里看到了这篇文章并阅读了它,看起来批量复制可能是一条出路

我还有一些问题,想知道事情到底是如何运作的

所以我找到了两本教程

第一种方式使用2个ado.net 2.0功能。批量插入和批量复制。第二种方法使用LINQtoSQL和OpenXML

这对我很有吸引力,因为我已经在使用LINQtoSQL,并且更喜欢它而不是ado.net。然而,正如一个人在帖子中指出的那样,他只是以性能为代价来处理这个问题(我认为这没有错)

首先,我将在第一个教程中讨论这两种方法

我使用的是VS2010 Express(用于测试我使用的VS2008教程,但不确定我刚刚加载了哪些.net版本的示例文件并运行了它们),.net 4.0、MVC 2.0、SQl Server 2005

  • ado.net 2.0是最新版本吗
  • 基于我正在使用的技术,我将要展示的内容是否有一些更新,以某种方式改进它
  • 这些教程遗漏了什么我应该知道的吗
  • BulkInsert

    所有的例子我都用这个表

    CREATE TABLE [dbo].[TBL_TEST_TEST]
    (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        [NAME] [varchar](50) 
    )
    
    SP代码

    USE [Test]
    GO
    /****** Object:  StoredProcedure [dbo].[sp_BatchInsert]    Script Date: 05/19/2010 15:12:47 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[sp_BatchInsert] (@Name VARCHAR(50) )
    AS
    BEGIN
                INSERT INTO TBL_TEST_TEST VALUES (@Name);
    END 
    
    C#代码

    插入批量大小为1000的500000条记录所需的时间为“2分54秒”

    当然,这不是我坐在那里看秒表的正式时间(我肯定有更好的方法,但我懒得看它们在哪里)

    因此,我发现与我的所有其他版本相比,这有点慢(除了LINQtoSQLINSERT版本),我不确定为什么

    接下来,我看了一本

    /// <summary>
    /// An ado.net 2.0 way to mass insert records. This seems to be the fastest.
    /// http://www.codeproject.com/KB/cs/MultipleInsertsIn1dbTrip.aspx#_Toc196622241
    /// </summary>
    private static void BatchBulkCopy()
    {
        // Get the DataTable 
        DataTable dtInsertRows = GetDataTable();
    
        using (SqlBulkCopy sbc = new SqlBulkCopy(connectionString, SqlBulkCopyOptions.KeepIdentity))
        {
            sbc.DestinationTableName = "TBL_TEST_TEST";
    
            // Number of records to be processed in one go
            sbc.BatchSize = 500000;
    
            // Map the Source Column from DataTabel to the Destination Columns in SQL Server 2005 Person Table
            // sbc.ColumnMappings.Add("ID", "ID");
            sbc.ColumnMappings.Add("NAME", "NAME");
    
            // Number of records after which client has to be notified about its status
            sbc.NotifyAfter = dtInsertRows.Rows.Count;
    
            // Event that gets fired when NotifyAfter number of records are processed.
            sbc.SqlRowsCopied += new SqlRowsCopiedEventHandler(sbc_SqlRowsCopied);
    
            // Finally write to server
            sbc.WriteToServer(dtInsertRows);
            sbc.Close();
        }
    
    }
    
    C代码

    //
    ///这是使用LINQtoSQL生成表对象。
    ///然后将其序列化为xml文档并发送到存储过程
    ///然后进行批量插入(我认为使用OpenXML)
    ///  http://www.codeproject.com/KB/linq/BulkOperations_LinqToSQL.aspx
    /// 
    私有静态void LinqInsertXMLBatch()
    {
    使用(TestDataContext db=newtestdatacontext())
    {
    TBL_测试[]测试记录=新的TBL_测试[500000];
    对于(整数计数=0;计数<500000;计数++)
    {
    TBL_测试记录=新的TBL_测试记录();
    testRecord.NAME=“NAME:”+计数;
    testRecords[计数]=testRecord;
    }
    StringBuilder sBuilder=新StringBuilder();
    System.IO.StringWriter sWriter=新的System.IO.StringWriter(sBuilder);
    XmlSerializer serializer=新的XmlSerializer(typeof(TBL_TEST_TEST[]);
    serializer.Serialize(sWriter,testRecords);
    db.insertTestData(sBuilder.ToString());
    }
    }
    
    所以我喜欢这个,因为我可以使用对象,尽管它有点多余。我不明白SP是如何工作的。好像我不明白整件事。我不知道OPENXML是否有一些批插入,但我甚至不知道如何将这个示例SP更改为适合我的表,因为正如我所说,我不知道发生了什么

    我也不知道如果对象中有更多的表,会发生什么。比如说我有一个ProductName表,它与产品表或类似的东西有关系

    在LINQtoSQL中,您可以获取product name对象,并对同一对象中的product表进行更改。所以我不知道该如何考虑这一点。我不确定我是否需要做单独的插入或什么

    对于500000条记录来说,这段时间相当不错,花了52秒

    当然,最后一种方法就是使用linq来完成这一切,这非常糟糕

    /// <summary>
    /// This is using linq to sql to to insert lots of records. 
    /// This way is slow as it uses no mass insert.
    /// Only tried to insert 50,000 records as I did not want to sit around till it did 500,000 records.
    /// http://www.codeproject.com/KB/linq/BulkOperations_LinqToSQL.aspx
    /// </summary>
    private static void LinqInsertAll()
    {
        using (TestDataContext db = new TestDataContext())
        {
            db.CommandTimeout = 600;
            for (int count = 0; count < 50000; count++)
            {
                TBL_TEST_TEST testRecord = new TBL_TEST_TEST();
                testRecord.NAME = "Name : " + count;
                db.TBL_TEST_TESTs.InsertOnSubmit(testRecord);
            }
            db.SubmitChanges();
        }
    }
    
    //
    ///这是使用LINQtoSQL插入大量记录。
    ///这种方法速度慢,因为它不使用质量插入。
    ///只是尝试插入50000条记录,因为我不想坐在那里直到它插入500000条记录。
    /// http://www.codeproject.com/KB/linq/BulkOperations_LinqToSQL.aspx
    /// 
    私有静态void LinqInsertAll()
    {
    使用(TestDataContext db=newtestdatacontext())
    {
    db.CommandTimeout=600;
    用于(整数计数=0;计数<50000;计数++)
    {
    TBL_测试记录=新的TBL_测试记录();
    testRecord.NAME=“NAME:”+计数;
    db.TBL\U测试\U测试。InsertOnSubmit(测试记录);
    }
    db.SubmitChanges();
    }
    }
    
    我只录了50000张唱片,花了一分钟的时间

    所以我将它缩小到linq到sql批量插入方式或批量复制。我只是不知道当你们有任何一种关系的时候该怎么做。我不知道他们在做更新而不是插入时是如何站起来的,因为我还没有试过

    我认为我永远都不需要在一种类型中插入/更新超过50000条记录,但同时我知道我必须在插入之前对记录进行验证,这样会降低速度,这会使linq to sql作为对象变得更好,特别是如果在插入到对象之前首先解析xml文件中的数据数据库

    完整C#代码

    使用系统;
    使用System.Collections.Generic;
    使用System.Linq;
    使用系统文本;
    使用System.Xml.Serialization;
    使用系统数据;
    使用System.Data.SqlClient;
    命名空间可测试
    {
    班级计划
    {
    私有静态字符串connectionString=“”;
    静态void Main(字符串[]参数)
    {
    BatchInsert();
    控制台。写入线(“完成”);
    }
    /// 
    ///这是使用LINQtoSQL插入大量记录。
    ///这种方法速度慢,因为它不使用质量插入。
    ///只是尝试插入50000条记录,因为我不想坐在那里直到它插入500000条记录。
    /// http://www.codeproject.com/KB/linq/BulkOperations_LinqToSQL.aspx
    /// 
    私有静态void LinqInsertAll()
    {
    使用(TestDataContext db=newtestdatacontext())
    {
    
    /// <summary>
    /// An ado.net 2.0 way to mass insert records. This seems to be the fastest.
    /// http://www.codeproject.com/KB/cs/MultipleInsertsIn1dbTrip.aspx#_Toc196622241
    /// </summary>
    private static void BatchBulkCopy()
    {
        // Get the DataTable 
        DataTable dtInsertRows = GetDataTable();
    
        using (SqlBulkCopy sbc = new SqlBulkCopy(connectionString, SqlBulkCopyOptions.KeepIdentity))
        {
            sbc.DestinationTableName = "TBL_TEST_TEST";
    
            // Number of records to be processed in one go
            sbc.BatchSize = 500000;
    
            // Map the Source Column from DataTabel to the Destination Columns in SQL Server 2005 Person Table
            // sbc.ColumnMappings.Add("ID", "ID");
            sbc.ColumnMappings.Add("NAME", "NAME");
    
            // Number of records after which client has to be notified about its status
            sbc.NotifyAfter = dtInsertRows.Rows.Count;
    
            // Event that gets fired when NotifyAfter number of records are processed.
            sbc.SqlRowsCopied += new SqlRowsCopiedEventHandler(sbc_SqlRowsCopied);
    
            // Finally write to server
            sbc.WriteToServer(dtInsertRows);
            sbc.Close();
        }
    
    }
    
    USE [Test]
    GO
    /****** Object:  StoredProcedure [dbo].[spTEST_InsertXMLTEST_TEST]    Script Date: 05/19/2010 15:39:03 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[spTEST_InsertXMLTEST_TEST](@UpdatedProdData nText)
    AS 
     DECLARE @hDoc int   
    
     exec sp_xml_preparedocument @hDoc OUTPUT,@UpdatedProdData 
    
     INSERT INTO TBL_TEST_TEST(NAME)
     SELECT XMLProdTable.NAME
        FROM OPENXML(@hDoc, 'ArrayOfTBL_TEST_TEST/TBL_TEST_TEST', 2)   
           WITH (
                    ID Int,                 
                    NAME varchar(100)
                ) XMLProdTable
    
    EXEC sp_xml_removedocument @hDoc
    
    /// <summary>
    /// This is using linq to sql to make the table objects. 
    /// It is then serailzed to to an xml document and sent to a stored proedure
    /// that then does a bulk insert(I think with OpenXML)
    ///  http://www.codeproject.com/KB/linq/BulkOperations_LinqToSQL.aspx
    /// </summary>
    private static void LinqInsertXMLBatch()
    {
        using (TestDataContext db = new TestDataContext())
        {
            TBL_TEST_TEST[] testRecords = new TBL_TEST_TEST[500000];
            for (int count = 0; count < 500000; count++)
            {
                TBL_TEST_TEST testRecord = new TBL_TEST_TEST();
                testRecord.NAME = "Name : " + count;
                testRecords[count] = testRecord;
            }
    
            StringBuilder sBuilder = new StringBuilder();
            System.IO.StringWriter sWriter = new System.IO.StringWriter(sBuilder);
            XmlSerializer serializer = new XmlSerializer(typeof(TBL_TEST_TEST[]));
            serializer.Serialize(sWriter, testRecords);
            db.insertTestData(sBuilder.ToString());
        }
    }
    
    /// <summary>
    /// This is using linq to sql to to insert lots of records. 
    /// This way is slow as it uses no mass insert.
    /// Only tried to insert 50,000 records as I did not want to sit around till it did 500,000 records.
    /// http://www.codeproject.com/KB/linq/BulkOperations_LinqToSQL.aspx
    /// </summary>
    private static void LinqInsertAll()
    {
        using (TestDataContext db = new TestDataContext())
        {
            db.CommandTimeout = 600;
            for (int count = 0; count < 50000; count++)
            {
                TBL_TEST_TEST testRecord = new TBL_TEST_TEST();
                testRecord.NAME = "Name : " + count;
                db.TBL_TEST_TESTs.InsertOnSubmit(testRecord);
            }
            db.SubmitChanges();
        }
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
    using System.Data;
    using System.Data.SqlClient;
    
    namespace TestIQueryable
    {
        class Program
        {
            private static string connectionString = "";
            static void Main(string[] args)
            {
                BatchInsert();
                Console.WriteLine("done");
            }
    
            /// <summary>
            /// This is using linq to sql to to insert lots of records. 
            /// This way is slow as it uses no mass insert.
            /// Only tried to insert 50,000 records as I did not want to sit around till it did 500,000 records.
            /// http://www.codeproject.com/KB/linq/BulkOperations_LinqToSQL.aspx
            /// </summary>
            private static void LinqInsertAll()
            {
                using (TestDataContext db = new TestDataContext())
                {
                    db.CommandTimeout = 600;
                    for (int count = 0; count < 50000; count++)
                    {
                        TBL_TEST_TEST testRecord = new TBL_TEST_TEST();
                        testRecord.NAME = "Name : " + count;
                        db.TBL_TEST_TESTs.InsertOnSubmit(testRecord);
                    }
                    db.SubmitChanges();
                }
            }
    
            /// <summary>
            /// This is using linq to sql to make the table objects. 
            /// It is then serailzed to to an xml document and sent to a stored proedure
            /// that then does a bulk insert(I think with OpenXML)
            ///  http://www.codeproject.com/KB/linq/BulkOperations_LinqToSQL.aspx
            /// </summary>
            private static void LinqInsertXMLBatch()
            {
                using (TestDataContext db = new TestDataContext())
                {
                    TBL_TEST_TEST[] testRecords = new TBL_TEST_TEST[500000];
                    for (int count = 0; count < 500000; count++)
                    {
                        TBL_TEST_TEST testRecord = new TBL_TEST_TEST();
                        testRecord.NAME = "Name : " + count;
                        testRecords[count] = testRecord;
                    }
    
                    StringBuilder sBuilder = new StringBuilder();
                    System.IO.StringWriter sWriter = new System.IO.StringWriter(sBuilder);
                    XmlSerializer serializer = new XmlSerializer(typeof(TBL_TEST_TEST[]));
                    serializer.Serialize(sWriter, testRecords);
                    db.insertTestData(sBuilder.ToString());
                }
            }
    
            /// <summary>
            /// An ado.net 2.0 way to mass insert records. This seems to be the fastest.
            /// http://www.codeproject.com/KB/cs/MultipleInsertsIn1dbTrip.aspx#_Toc196622241
            /// </summary>
            private static void BatchBulkCopy()
            {
                // Get the DataTable 
                DataTable dtInsertRows = GetDataTable();
    
                using (SqlBulkCopy sbc = new SqlBulkCopy(connectionString, SqlBulkCopyOptions.KeepIdentity))
                {
                    sbc.DestinationTableName = "TBL_TEST_TEST";
    
                    // Number of records to be processed in one go
                    sbc.BatchSize = 500000;
    
                    // Map the Source Column from DataTabel to the Destination Columns in SQL Server 2005 Person Table
                    // sbc.ColumnMappings.Add("ID", "ID");
                    sbc.ColumnMappings.Add("NAME", "NAME");
    
                    // Number of records after which client has to be notified about its status
                    sbc.NotifyAfter = dtInsertRows.Rows.Count;
    
                    // Event that gets fired when NotifyAfter number of records are processed.
                    sbc.SqlRowsCopied += new SqlRowsCopiedEventHandler(sbc_SqlRowsCopied);
    
                    // Finally write to server
                    sbc.WriteToServer(dtInsertRows);
                    sbc.Close();
                }
    
            }
    
    
            /// <summary>
            /// Another ado.net 2.0 way that uses a stored procedure to do a bulk insert.
            /// Seems slower then "BatchBulkCopy" way and it crashes when you try to insert 500,000 records in one go.
            /// http://www.codeproject.com/KB/cs/MultipleInsertsIn1dbTrip.aspx#_Toc196622241
            /// </summary>
            private static void BatchInsert()
            {
                // Get the DataTable with Rows State as RowState.Added
                DataTable dtInsertRows = GetDataTable();
    
                SqlConnection connection = new SqlConnection(connectionString);
                SqlCommand command = new SqlCommand("sp_BatchInsert", connection);
                command.CommandType = CommandType.StoredProcedure;
                command.UpdatedRowSource = UpdateRowSource.None;
    
                // Set the Parameter with appropriate Source Column Name
                command.Parameters.Add("@Name", SqlDbType.VarChar, 50, dtInsertRows.Columns[0].ColumnName);
    
                SqlDataAdapter adpt = new SqlDataAdapter();
                adpt.InsertCommand = command;
                // Specify the number of records to be Inserted/Updated in one go. Default is 1.
                adpt.UpdateBatchSize = 500000;
    
                connection.Open();
                int recordsInserted = adpt.Update(dtInsertRows);
                connection.Close();
            }
    
    
    
            private static DataTable GetDataTable()
            {
                // You First need a DataTable and have all the insert values in it
                DataTable dtInsertRows = new DataTable();
                dtInsertRows.Columns.Add("NAME");
    
                for (int i = 0; i < 500000; i++)
                {
                    DataRow drInsertRow = dtInsertRows.NewRow();
                    string name = "Name : " + i;
                    drInsertRow["NAME"] = name;
                    dtInsertRows.Rows.Add(drInsertRow);
    
    
                }
                return dtInsertRows;
    
            }
    
    
            static void sbc_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
            {
                Console.WriteLine("Number of records affected : " + e.RowsCopied.ToString());
            }
    
    
        }
    }