将.csv文件导入Microsoft SQL Server 2008 R2的推荐方法?

时间:2011-02-16 00:50:58

标签: sql sql-server-2008

您建议将.csv文件导入Microsoft SQL Server 2008 R2的方法是什么?

我想要一些快速的东西,因为我有一个包含大量.csv文件的目录(分布在500 .csv文件中的500MB左右)。

我在Win 7 x64上使用SQL Server 2008 R2。

更新:解决方案

以下是我解决问题的方法:

  1. 我放弃了尝试使用LINQ to Entities来完成这项工作。它可以工作 - 但它不支持批量插入,所以它大约慢20倍。也许下一版本的LINQ to Entities将支持这一点。
  2. 接受了关于此主题的建议,使用了批量插入。
  3. 我创建了一个使用批量插入的T-SQL存储过程。数据进入临时表,进行规范化,然后复制到目标表中。
  4. 我使用LINQ to Entities框架将存储过程映射到C#(www.learnvisualstudio.net上有一个视频,展示了如何执行此操作)。
  5. 我在C#中编写了所有代码来循环浏览文件等。
  6. 这种方法消除了最大的瓶颈,即从驱动器读取大量数据并将其插入数据库。
  7. 这种方法读取.csv文件的速度非常快? Microsoft SQL Server可以使用自己的高度优化的例程将文件直接从硬盘驱动器直接导入数据库。大多数其他基于C#的解决方案需要更多代码,而有些(如LINQ to Entities)最终必须通过C#-to-SQL-server链接将数据缓慢地传输到数据库中。

    是的,我知道拥有100%纯C#代码来做这项工作更好,但最终:

    • (a)对于这个特殊问题,与C#相比,使用T-SQL需要少的代码,大约是1/10,特别是对于从登台表反规范化数据的逻辑。这更简单,更易于维护。
    • (b)使用T-SQL意味着您可以利用本机批量插入程序,从20分钟等待到30秒暂停加速。

6 个答案:

答案 0 :(得分:7)

在T-SQL脚本中使用BULK INSERT似乎是一个很好的解决方案。

http://blog.sqlauthority.com/2008/02/06/sql-server-import-csv-file-into-sql-server-using-bulk-insert-load-comma-delimited-file-into-sql-server/

您可以使用xp_cmdshell和dir命令(稍微清理)获取目录中的文件列表。在过去,我尝试使用sp_OAMethod和VBScript函数执行类似的操作,并且必须使用dir方法,因为我无法使用FSO对象获取文件列表。

http://www.sqlusa.com/bestpractices2008/list-files-in-directory/

答案 1 :(得分:3)

如果您必须对除插入文件之外的文件中的数据执行任何操作,那么我建议您使用SSIS。它不仅可以插入和/或更新,还可以为您清理数据。

答案 2 :(得分:2)

第一种官方支持的导入大型文本文件的方法是使用命令行工具“bcp”(批量复制实用程序),对大量二进制数据非常有用。

请查看此链接:http://msdn.microsoft.com/en-us/library/ms162802.aspx

但是,在SQL Server 2008中,我假设BULK INSERT命令是您的首选,因为它首先成为标准命令集的一部分。如果由于任何原因你必须保持垂直兼容性,我会坚持使用bcp实用程序,也可用于SQL Server 2000.

HTH:)

稍后编辑:谷歌搜索我还记得SQL Server 2000也有BULK INSERT命令......但是,显然有一些原因我坚持使用bcp.exe,我不记得为什么......或许有一些限制,我想。

答案 3 :(得分:2)

我应该推荐这个:

using System;
using System.Data;
using Microsoft.VisualBasic.FileIO;

namespace ReadDataFromCSVFile
  {
    static class Program
      {
        static void Main()
        {
            string csv_file_path=@"C:\Users\Administrator\Desktop\test.csv";
            DataTable csvData = GetDataTabletFromCSVFile(csv_file_path);
            Console.WriteLine("Rows count:" + csvData.Rows.Count);            
            Console.ReadLine();
        }
    private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
        {
            DataTable csvData = new DataTable();
            try
            {
              using(TextFieldParser csvReader = new TextFieldParser(csv_file_path))
                 {
                    csvReader.SetDelimiters(new string[] { "," });
                    csvReader.HasFieldsEnclosedInQuotes = true;
                    string[] colFields = csvReader.ReadFields();
                    foreach (string column in colFields)
                    {
                        DataColumn datecolumn = new DataColumn(column);
                        datecolumn.AllowDBNull = true;
                        csvData.Columns.Add(datecolumn);
                    }
                    while (!csvReader.EndOfData)
                    {
                        string[] fieldData = csvReader.ReadFields();
                        //Making empty value as null
                        for (int i = 0; i < fieldData.Length; i++)
                        {
                            if (fieldData[i] == "")
                            {
                                fieldData[i] = null;
                            }
                        }
                        csvData.Rows.Add(fieldData);
                    }
                }
            }
            catch (Exception ex)
            {
            }
            return csvData;
        }
      }
    }

//Copy the DataTable to SQL Server using SqlBulkCopy

    function static void InsertDataIntoSQLServerUsingSQLBulkCopy(DataTable csvData)
    {
       using(SqlConnection dbConnection = new SqlConnection("Data Source=ProductHost;Initial Catalog=yourDB;Integrated Security=SSPI;"))
            {
              dbConnection.Open();
              using (SqlBulkCopy s = new SqlBulkCopy(dbConnection))
                {
                    s.DestinationTableName = "Your table name";

                    foreach (var column in csvFileData.Columns)
                    s.ColumnMappings.Add(column.ToString(), column.ToString());

                    s.WriteToServer(csvFileData);
                 }
             }
      }

答案 4 :(得分:1)

如果所有CSV的结构相同,我建议您使用Integration Services(SSIS)在它们之间循环并将它们全部插入到同一个表中。

答案 5 :(得分:1)

我知道这不是你的问题。但是,如果您遇到使用直插入的情况,请使用tablock并插入多行。取决于行大小,但我通常会在600-800行。如果它是加载到空表中,那么有时删除索引并在加载后创建它们会更快。如果可以在聚集索引加载之前对其进行排序。如果可以,请使用IGNORE_CONSTRAINTS和IGNORE_TRIGGERS。如果可以,请将数据库置于单用户模式。

USE AdventureWorks2008R2; 走 使用(tablock)插入Production.UnitMeasure VALUES(N'FT2',N'Square Feet','20080923'),(N'Y',N'Yards','20080923'),(N'Y3',N'Cubic Yards','20080923') ; GO