【问题标题】:How to speed up import a large csv file to mysql database?如何加快将大型 csv 文件导入 mysql 数据库的速度?
【发布时间】:2019-11-24 11:37:33
【问题描述】:

此时我有一个 11 MB 的大型 csv 文件,其中包含许多插入到... excel 文件末尾的数据。所以它将是大约 10 列中的 100 万行。现在我想编写一个 c# 代码,它可以更快地导入这个文件。

我做了什么?

首先,我编写了从 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;
        }

其次,我可以将mysql数据库插入“order_status”表:

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

但是当我插入 11 MB 的大文件时,它会导入很多时间,大约需要 10 分钟。在编译这段代码的一半时间里,进程内存大约有...... 5 GB!

现在我想知道如何加快从大型 csv 文件导入数据的速度。 MysqlBulkLoader 就够了吗?也许应该以其他方式重写导入代码?有任何想法吗?感谢您的帮助。

我尝试了什么?

我尝试在 x64 模式下运行并在 App.config 中添加 &lt;runtime&gt; &lt;gcAllowVeryLargeObjects enabled="true" /&gt; &lt;/runtime&gt;。但它还没有帮助。

【问题讨论】:

    标签: c# mysql .net csv import


    【解决方案1】:

    我认为 ImportFile 功能很好,应该没有问题。 额外的时间花在 SQLQuery 和 foreach 上。您应该使用一些更新批处理功能,而不是一个查询一行。

    INSERT INTO tbl_name
        (a,b,c)
    VALUES
        (1,2,3),
        (4,5,6),
        (7,8,9);
    

    1.从文件构建imported_data

    2.从imported_data构建Sql查询

    3.运行查询

    也许你可以同时做 1 和 2。祝你好运!

    【讨论】:

      猜你喜欢
      • 2016-04-29
      • 2020-02-06
      • 2019-11-09
      • 1970-01-01
      • 2011-10-19
      • 2011-04-16
      • 1970-01-01
      • 2022-07-25
      • 1970-01-01
      相关资源
      最近更新 更多