Member 10696161 Ответов: 2

Как ускорить импорт большого csv-файла в базу данных mysql?


В данный момент у меня есть большой csv-файл, который имеет 11 мб и содержит большую часть данных, которые вставляются в... конец файла excel. Таким образом, это будет около 1 миллиона строк в 10 столбцах. Теперь я хотел бы написать код c#, который импортирует этот файл очень быстро.

Что я наделал?

Во - первых, я написал код, который импортирует все данные из csv-файла. Во-вторых, я могу вставить в базу данных mysql таблицу "order_status". Эти коды будут в разделе "Что вы пробовали?"

Но когда я вставляю 11 Мб большого файла, он импортирует много времени, которое будет составлять около 10 минут. И в половину времени пути при компиляции этого кода процесс памяти имеет около... 5 ГБ!

Теперь мне интересно, как я могу ускорить импорт данных из большого csv-файла. "MysqlBulkLoader" будет достаточно? Может быть, стоит переписать импортируемый код по-другому? Есть идеи? Спасибо за любую помощь.

Что я уже пробовал:

1) импорт данных из csv-файла:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections;
using System.Data.OleDb;
using System.IO;
using System.Configuration;
using MySql.Data.MySqlClient;

namespace ControlDataBase
{
    public partial class Import_data_mysql : Form
    {
        public Import_data_mysql()
        {
            InitializeComponent();
        }
        New_Tables frm2 = (New_Tables)Application.OpenForms["New_Tables"];

        private DataTable ImportFile()
        {
            DataTable imported_data = new DataTable();

            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "Open csv file";
            ofd.DefaultExt = "*.csv";
            ofd.Filter = "Documents (*.csv)|*.csv";
            ofd.ShowDialog();

            FileInfo fi = new FileInfo(ofd.FileName);
            string FileName1 = ofd.FileName;
            string excel = fi.FullName;

            using(StreamReader sr = new StreamReader(excel))
            {
                string header = sr.ReadLine();
                if (string.IsNullOrEmpty(header))
                {
                    MessageBox.Show("Not found or loaded not correct file.");
                    return null;
                }

                string[] header_columns = header.Split(';');
                foreach(string header_column in header_columns)
                {
                    imported_data.Columns.Add(header_column);
                }

                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();

                    if (string.IsNullOrEmpty(line)) continue;

                    string[] fields = line.Split(';');
                    DataRow imported_row = imported_data.NewRow();

                    for (int i = 0; i < fields.Count(); i++)
                    {
                        imported_row[i] = fields[i];
                    }

                    imported_data.Rows.Add(imported_row);
                }
            }
            return imported_data;
        }


2) вставка данных в базу данных mysql:

private void save_status_to_database(DataTable imported_data)
       {
           string connect = "datasource=localhost;port=3306;username=root;password=;CharSet=utf8mb4";
           using (MySqlConnection conn = new MySqlConnection(connect))
           {
               conn.Open();
               foreach (DataRow importRow in importowane_dane.Rows)
               {
                   string query5 = @INSERT IGNORE INTO try1.order_status(ID_WORKER, ID_ORDER, ID_MODULE, ID_PROJECT,
                   AMOUNT_OF_PRODUCTS, BEGIN_DATE, END_DATE) SELECT workers.ID_WORKER, orders.ID_ORDER, module.ID_MODULE,
                   projects.ID, @AMOUNT_OF_PRODUCTS, @BEGIN_DATE, @END_DATE FROM try1.workers INNER JOIN try1.orders
                   INNER JOIN try1.modules INNER JOIN try1.projects WHERE workers.FNAME = @FNAME AND workers.LNAME = @LNAME
                   AND workers.ID_WORKER = @ID_WORKER AND orders.DESC_ORDER = @DESC_ORDER
                   AND orders.ORDER_NUMBER = @ORDER_NUMBER AND modules.NAME = @MODULES_NAME
                   AND projects.PROJECT_NAME = @PROJECT_NAME"

                   MySqlCommand cmd = new MySqlCommand(query5, conn);

                   cmd.Parameters.AddWithValue("@ID_WORKER", importRow["ID_WORKER"]);
                   cmd.Parameters.AddWithValue("@FNAME", importRow["FNAME"]);
                   cmd.Parameters.AddWithValue("@LNAME", importRow["LNAME"]);
                   cmd.Parameters.AddWithValue("@DESC_ORDER", importRow["DESC_ORDER"]);
                   cmd.Parameters.AddWithValue("@ORDER_NUMBER", importRow["ORDER_NUMBER"]);
                   cmd.Parameters.AddWithValue("@MODULES_NAME", importRow["NAME"]);
                   cmd.Parameters.AddWithValue("@PROJECT_NAME", importRow["PROJECT_NAME"]);
                   cmd.Parameters.AddWithValue("@AMOUNT_OF_PRODUCTS", importRow["AMOUNT_OF_PRODUCTS"]);
                   cmd.Parameters.AddWithValue("@BEGIN_DATE", importRow["BEGIN_DATE"]);
                   cmd.Parameters.AddWithValue("@END_DATE", importRow["END_DATE"]);

                   cmd.ExecuteNonQuery();
               }
               conn.Close();
           }
           MessageBox.Show("Imported to database.");
       }


3) я попробовал запустить в режиме x64 и добавить <runtime> <gcallowverylargeobjects enabled="true"> В App.config. Но это пока не помогло.

2 Ответов

Рейтинг:
2

MadMyche

Мой выбор будет либо следующим: MySqlBulkLoader вы предложили или пакет SSIS; в зависимости от того, что быстрее.


Рейтинг:
0

Dave Kreskowiak

Одна из причин, по которой он настолько медленный и потребляет так много памяти, заключается в том, что Вы читаете весь файл в объект DataTable. Это займет целую вечность и поглотит тонну памяти.

Не. Просто обработайте каждую запись по мере ее чтения и сохраните ее в базе данных. Вам вообще не нужен DataTable или код, чтобы использовать его.