Рекомендуемый метод импорта CSV файла в Microsoft SQL Server 2008 R2?

Каков ваш рекомендуемый способ импорта CSV файлов в Microsoft SQL Server 2008 R2?

Мне бы хотелось что-то быстро, так как у меня есть каталог с большим количеством файлов .csv( > 500 МБ, распространяемых по 500 файлам .csv).

Я использую SQL Server 2008 R2 на Win 7 x64.

Обновление: решение

Вот как я решил проблему в конце:

  • Я отказался от попыток использовать LINQ для Entities для выполнения этой задачи. Он работает - но он не поддерживает объемную вставку, поэтому ее примерно в 20 раз медленнее. Возможно, следующая версия LINQ to Entities будет поддерживать это.
  • Взял совет, данный в этой теме, использовал объемную вставку.
  • Я создал хранимую процедуру T-SQL, которая использует объемную вставку. Данные переходят в промежуточную таблицу, затем нормализуются, а затем копируются в целевые таблицы.
  • Я отобразил хранимую процедуру на С#, используя структуру LINQ to Entities (есть видео на www.learnvisualstudio.net, показывающее, как это сделать).
  • Я написал весь код для циклического использования файлов и т.д. на С#.
  • Этот метод устраняет самое большое узкое место, которое считывает тонны данных с диска и вставляет их в базу данных.

Причина, по которой этот метод чрезвычайно быстрый при чтении CSV файлов? Microsoft SQL Server позволяет импортировать файлы непосредственно с жесткого диска прямо в базу данных, используя свои высоко оптимизированные подпрограммы. Большинство других решений на базе С# требуют гораздо больше кода, а некоторые (например, LINQ to Entities) вынуждены медленно передавать данные в базу данных по ссылке С# -to-SQL-server.

Да, я знаю, что было бы лучше иметь 100% -ный код С# для выполнения задания, но в конце:

  • (a) Для этой конкретной проблемы использование T-SQL требует гораздо меньше кода по сравнению с С#, около 1/10, особенно для того, чтобы логика денормализовала данные из промежуточной таблицы. Это проще и удобнее обслуживать.
  • (b) Использование T-SQL означает, что вы можете воспользоваться процедурами внутренней вставки вставки, что ускоряет работу с 20-минутного ожидания до 30-секундной паузы.

Ответ 1

Использование BULK INSERT в T-SQL script представляется хорошим решением.

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. Он может не только вставлять и/или обновлять, он также может очищать данные для вас.

Ответ 3

Первый официально поддерживаемый способ импорта больших текстовых файлов - это инструмент командной строки, называемый "bcp" (утилита Bulk Copy Utility), очень полезный для огромного количества двоичных данных.

Пожалуйста, ознакомьтесь с этой ссылкой: http://msdn.microsoft.com/en-us/library/ms162802.aspx

Однако в SQL Server 2008 я предполагаю, что команда BULK INSERT будет вашим выбором номер один, потому что на первом месте она стала частью стандартного набора команд. Если по какой-либо причине вы должны поддерживать вертикальную совместимость, я бы использовал утилиту bcp, также доступную для SQL Server 2000.

HTH:)

EDITED LATER: Googling around Я вспомнил, что SQL Server 2000 также имел команду BULK INSERT... однако, очевидно, была определенная причина, по которой я придерживался bcp.exe, и я не могу вспомнить, почему... возможно, некоторые ограничения, Думаю.

Ответ 4

Я должен порекомендовать это:

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

namespace ReadDataFromCSVFile
  {
    static class Program
      {
        static void Main()
        {
            string [email protected]"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) для того, чтобы зацикливаться между ними и вставить все их в одну таблицу.

Ответ 6

Я понимаю, что это не совсем ваш вопрос. Но, если вы попадаете в ситуацию, когда вы используете прямую вставку, используйте tablock и вставляете несколько строк. Зависит от размера строки, но я обычно иду за 600-800 строк во время. Если это загрузка в пустую таблицу, то иногда падение индексов и их создание после загрузки происходит быстрее. Если вы можете сортировать данные в кластерном индексе перед его загрузкой. Используйте IGNORE_CONSTRAINTS и IGNORE_TRIGGERS, если сможете. Поместите базу данных в однопользовательский режим, если сможете.

ИСПОЛЬЗОВАТЬ AdventureWorks2008R2; ИДТИ INSERT INTO Production.UnitMeasure с (tablock) (N'Y ', N'Yards', '20080923'), (N'Y3 ', N'Cubic Yards', '20080923'),; GO