【问题标题】:Recommended method to import a .csv file into Microsoft SQL Server 2008 R2?将 .csv 文件导入 Microsoft SQL Server 2008 R2 的推荐方法?
【发布时间】:2013-12-12 00:31:55
【问题描述】:

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

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

我在 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. 这种方法消除了最大的瓶颈,即从驱动器中读取大量数据并将其插入数据库。

这种方法在读取 .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 秒暂停。

【问题讨论】:

  • 不错的一个(并且p l u s on e)!感谢您的提示-对我也很有用。只是想知道为什么有一个 100% 的 C# 代码来完成这项工作会很好?对我来说,拥有一个完全没有任何 C# 代码的 100% T-SQL 解决方案真是太好了 :) 我使用 xp_dirtree 来获取我的 CSV 文件列表。见patrickkeisler.com/2012/11/…

标签: sql sql-server-2008


【解决方案1】:

在 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/

【讨论】:

  • 谢谢,这似乎工作得很好。我已经用解决方案最终的工作原理更新了这个问题。
  • 好的,我正计划做同样的事情,这很有帮助。然而,由于存储过程可以并行执行多次,我确实需要对随机临时表进行批量插入(意味着每次都有唯一的表名),一旦处理完成,我将清理临时表。跨度>
【解决方案2】:

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

【讨论】:

  • 感谢您提供有关 SSIS 的信息,它看起来很有趣。我必须安装 Visual Studio 2008 来检查它(它在 Visual Studio 2010 中不可用)。
  • SSIS 是垃圾,不要使用 SSIS。为什么?没有单元测试,有时会导致应用程序和 SSIS 包之间存在重复的业务逻辑等。仅当您的导入过程很简单时才使用 SSIS,您不需要进行单元测试,并且它的任何部分都没有使用与您的应用程序的其余部分类似的任何逻辑。
【解决方案3】:

第一个官方支持的导入大型文本文件的方法是使用名为“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 显然有一些原因,我不记得为什么......也许有一些限制,我猜。

【讨论】:

  • BCP 可以正常工作,但是,我决定使用批量插入,因为我可以使用 LINQ to Entity 框架轻松地将存储过程映射到 C#。谢谢推荐!
【解决方案4】:

我应该推荐这个:

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);
                 }
             }
      }

【讨论】:

  • 请提供简短描述。因此,我们可以了解您使用它是什么以及为什么使用它。对我这样的初学者很有帮助
【解决方案5】:

如果所有 CSV 的结构都相同,我建议您使用集成服务 (SSIS) 以便在它们之间循环并将它们全部插入同一个表中。

【讨论】:

  • 感谢您提供有关 SSIS 的信息,它看起来很有趣且非常强大。我必须安装 Visual Studio 2008 来检查它(它在 Visual Studio 2010 中不可用)。
【解决方案6】:

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

使用 AdventureWorks2008R2; 去 INSERT INTO Production.UnitMeasure with (tablock) 值 (N'FT2', N'Square Feet', '20080923'), (N'Y', N'Yards', '20080923'), (N'Y3', N'Cubic Yards', '20080923') ; 去吧

【讨论】:

  • 不错。我建议使用这种方法插入#temp 表,然后将#temp 与主表合并。出于某种原因,这样会快得多。
  • 可能主表处于活动状态,因此很难获得锁定。 #temp 表的好处是您拥有独占访问权限。表到表似乎比外部连接具有更高的优先级。我可以从经验告诉你,按聚集索引排序的加载是主要的。如果我无法对源进行排序,我会将其加载到 #temp 中,这样我就可以加载到按集群索引排序的真实表中。但是我们不应该使用 stackoverflow 作为讨论线程。
猜你喜欢
  • 2013-12-21
  • 1970-01-01
  • 1970-01-01
  • 2014-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-15
  • 1970-01-01
相关资源
最近更新 更多