Най-бързият начин за зареждане на данни от текстов файл, след което ги съхранявате в база данни

Имам проблем.

Разработвам проект, но съм заседнал в тази част:

Искам да заредя данни от текстов файл и да ги съхраня в базата данни за достъп, нещата са данните във всеки текстов файл около 12 000 реда с данни и обработката на всеки текстов файл отнема около 10 минути.

ЗАБЕЛЕЖКА: преди да съхраня данните, отделям всеки ред с данни от текстовия файл и го поставям в низ, след което проверявам дали данните вече са в базата данни или не. ако вътре в базата данни я актуализирам. Ако не, тогава използвам израз за вмъкване..

Използвам C#, за да разработя тази програма? има ли някакъв най-бърз начин за зареждане и съхраняване на тези данни?

АКТУАЛИЗИРАНО:

Това е моят код, надявам се, че ще помогне да разбера проблемите си:

    using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using System.Data.OleDb;

namespace DAF
{
    public partial class FrontForm : Form
    {
        public Boolean status;

        public FrontForm()
        {
            InitializeComponent();

            //define location of the database
            string connection = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\PC\Desktop\Graduation Project\Research\DAF\Data\DAFLogisticDepartment.mdb";

            //define location of the text file data
            DirectoryInfo di = new DirectoryInfo(@"C:\Users\PC\Desktop\Graduation Project\Research\DAF\Data\");
            FileInfo[] fiarr = di.GetFiles("*.txt");


            //define connection to database
            OleDbConnection con = new OleDbConnection(connection);
            String query;
            OleDbDataReader rdr = null;

            con.Open();
            //get all table from database
            OleDbCommand cmd = con.CreateCommand();
            DataTable dt = con.GetSchema("tables");
            DataRow[] dttable = dt.Select();
            con.Close();

            //read each new textfile inside the folder
            foreach (FileInfo fri in fiarr)
            {
                StreamReader sr = new StreamReader(fri.FullName, System.Text.Encoding.Default);
                String line;
                String tabledbs, dbsName;

                while ((line = sr.ReadLine()) != null)
                {
                    String VRSD, locationID, truckID, yearIn, yearOut, weekIn, weekOut, dayIn, dayOut, timeIn, timeOut, route;
                    int plantID;

                    //process each line of data and put into each variable
                    VRSD = line.Substring(0, 4).Trim();
                    plantID = Convert.ToInt32(line.Substring(4, 1).Trim());
                    locationID = line.Substring(5, 4).Trim();
                    truckID = line.Substring(24, 5).Trim();
                    yearIn = line.Substring(32, 4).Trim();
                    weekIn = line.Substring(36, 2).Trim();
                    dayIn = line.Substring(38, 1).Trim();
                    timeIn = line.Substring(39, 8).Trim();
                    yearOut = line.Substring(47, 4).Trim();
                    weekOut = line.Substring(51, 2).Trim();
                    dayOut = line.Substring(53, 1).Trim();
                    timeOut = line.Substring(54, 8).Trim();
                    route = line.Substring(64, 2).Trim();

                    //make database name
                    dbsName = plantID + locationID;

                    con.Open();
                    //check if the table exist in database
                    for (int i = 0; i < dttable.Length - 9; i++)
                    {
                        tabledbs = dttable[i]["TABLE_NAME"].ToString();
                        ArrayList indexlist = new ArrayList();

                        if (tabledbs == dbsName)
                        {
                            //if the table exist, status = true
                            status = true;
                            break;
                        }
                    }
                    con.Close();

                    con.Open();

                    if (status == true)
                    {

                        try
                        {        
                            //if the data not in the system, insert statement
                            query = @"insert into " + plantID + locationID + " values('" + VRSD.ToString() + "'," + plantID + ",'" + locationID + "','" + truckID + "','" + yearIn + "','" + weekIn + "','" + dayIn + "','" + timeIn + "','" + yearOut + "','" + weekOut + "','" + dayOut + "','" + timeOut + "')";
                            cmd = new OleDbCommand(query, con);
                            rdr = cmd.ExecuteReader();
                            con.Close();
                        }
                        catch
                        {
                            //if the data in the system, update statement
                            query = @"update " + dbsName + " set YearIn='" + yearIn + "', YearOut='" + yearOut + "', WeekIn='" + weekIn + "', WeekOut='" + weekOut + "', DayIn='" + dayIn + "', DayOut='" + dayOut + "', TimeIn='" + timeIn + "', TimeOut='" + timeOut + "' where LocationID='" + locationID + "' and PlantID=" + plantID + "";
                            cmd = new OleDbCommand(query, con);
                            rdr = cmd.ExecuteReader();
                            con.Close();
                        }

                    }
                    else
                    {
                        //create new table
                        string attribute = "VRSD String,PlantID Integer, LocationID String, TruckID String," +
                                            "YearIn String, WeekIn String, DayIn String, TimeIn String," +
                                            "YearOut String, WeekOut String, DayOut String, TimeOut String";

                        query = @"CREATE TABLE " + plantID + locationID + "(" + attribute + ")";
                        cmd = new OleDbCommand(query, con);
                        cmd.ExecuteNonQuery();

                        //insert the data
                        query = @"insert into " + plantID + locationID + " values('" + VRSD.ToString() + "'," + plantID + ",'" + locationID + "','" + truckID + "','" + yearIn + "','" + weekIn + "','" + dayIn + "','" + timeIn + "','" + yearOut + "','" + weekOut + "','" + dayOut + "','" + timeOut + "')";
                        cmd = new OleDbCommand(query, con);
                        rdr = cmd.ExecuteReader();
                        con.Close();
                    }

                    status = false;
                }
                sr.Close();

                //after the text file load into database, the text file moved to history folder
                MessageBox.Show(fri.FullName.ToString(), "File Manager", MessageBoxButtons.OK);
                fri.MoveTo(@"C:\Users\PC\Desktop\Graduation Project\Research\DAF\Data\History\" + fri.Name.ToString() + ".txt");
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            StandardReport sr = new StandardReport();
            sr.Show();
        }

        private void FrontForm_Load(object sender, EventArgs e)
        {

        }
    }
}

person Yohanes    schedule 11.02.2011    source източник
comment
Толкова ли са лоши 10 минути? Колко файла и колко често трябва да правите това? Можете ли да паралелизирате задачите, които изпълнявате? Профилирал ли си това, за да видиш къде се изразходва времето?   -  person btlog    schedule 11.02.2011
comment
ето нещата: шефът ми иска да зарежда 6 текстови файла всяка седмица.. И всеки текстов файл съдържа повече от 12 000 реда данни.. всеки път, когато шефът ми стартира програмата, програмата зарежда всеки текстов файл, проверява всеки ред в базата данни независимо дали данните съществуват или не. Ако съществува, той го актуализира, ако не го вмъква в dbs.. и всеки текстов файл отнема около 10 минути. Ако има 6 текстови файла, отнема 1 час.   -  person Yohanes    schedule 11.02.2011
comment
Добавям моя код.. Надявам се, че можете да ми помогнете.. :)   -  person Yohanes    schedule 11.02.2011
comment
@Yohanes Още един въпрос, какъв е форматът на текстовите файлове, които искате да вмъкнете? Малка извадка от данните би помогнала.   -  person Fionnuala    schedule 11.02.2011
comment
Имате 12k линии, x6... Очаквате ли повечето от тях да са нови или съществуващи линии?   -  person RichardW1001    schedule 11.02.2011
comment
Забелязвам, че създавате нова таблица, ако plantID + locationID не съществува, което ми се струва доста странен дизайн за база данни.   -  person Fionnuala    schedule 11.02.2011
comment
до Remou: добре, шефът ми иска да създаде нова таблица автоматично, ако данните съдържат нова таблица.. Мислех да използвам VBA вместо C#, но след като заредя тези данни в базата данни, все още трябва да ги обработя в отчет в Excel.. ето защо използвам C# като мост за тези 2 програми.. Това е пример за данни от 1 ред: VRSD3AAS ACHTERAS LIJN L09561A*201105521011900201106106282800A 50.. надявам се, че можете да ми помогнете да намеря начин да го направя бързо :) благодаря   -  person Yohanes    schedule 13.02.2011


Отговори (4)


Големият убиец на време тук ще бъде големият брой връзки към базата данни, които използвате - опитайте да създадете списък с команди в паметта (което няма да отнеме почти никакво време на обект в сравнение с четенето на данните от файла) и след като сте изградихте вашия списък, изпълнете ги през една единствена връзка. Отнема време за отваряне на всяка връзка и вие правите това много повече пъти, отколкото е необходимо. Редактиране - всъщност забелязах, че отваряте/затваряте 2 връзки на ред на файл!


В момента (псевдо код за яснота):

For each file (x6)

   Load file from stream

   For each line in file (x12k)

     Read data from line

     Open database connection (happens 72k times)
     Check whether table exists
     Close connection

     Open connection (x72k)
     Try to insert record
     If inserting fails, update existing record
     Close connection

     Next line

   Close filestream

Next file

Предложение: (и силно препоръчваме да помислите за последиците от динамичното добавяне на таблици, обикновено не е добро решение, но ако ви е наложено, може би нямате избор)

Create an in-memory list of commands 
  (or list of custom objects with property for each command type, create 
  table,insert,update)    

For each file (x6)

   Load file from stream

   For each line in file (x12k)

      Read data from line (all happens 72k times, but no external connections per line)

      Write your create table command
      Write your insert command
      Write your update command
      Add to relevent command lists

   Next Line

   Close filestream

Next File

Open database connection (x1)

For each command in your list
   Apply suitable logic as to whether command needs to execute
   Execute command if applicable
Next command

Close database connection
person RichardW1001    schedule 11.02.2011
comment
така че предполагате, че всички данни, които съхраних всички временно и след това ги сложих всички заедно в база данни наведнъж? все още съм объркан как да поставя/вмъквам всички данни в база данни в една връзка.. можете ли да ми дадете някакъв пример? Благодаря!! :) - person Yohanes; 13.02.2011
comment
са добавили груб пример за демонстрация - person RichardW1001; 14.02.2011

Защо не опитате да създадете и използвате SSIS пакет? Той е много добър в този вид неща, има отлични инструменти и е доста лесен за използване от код

http://msdn.microsoft.com/en-us/library/ms141026.aspx

http://blogs.msdn.com/b/michen/archive/2007/03/22/running-ssis-package-programmatically.aspx

person Veli Gebrev    schedule 11.02.2011
comment
Това ще помогне ли с Text и MS Access? Инсталирането на SQL Server изглежда пресилено за задачата. - person Fionnuala; 11.02.2011
comment
Не знам, ако работите с таблици с над 12 хиляди записа, не може да мине толкова време, преди да надраснете MS Access. Струва си да се разгледа сериозно, по-добре да има място за главата? - person RichardW1001; 11.02.2011
comment
@Remou, Да, SSIS може да работи с множество типове доставчици на източник и местоназначение за вашите данни, включително плоски файлове (текст) и JET/ACE (достъп) - person Veli Gebrev; 12.02.2011
comment
Наясно съм, че SSIS ще работи с много неща, но е много голям чук за малка грешка. - person Fionnuala; 12.02.2011
comment
Имайте предвид, че директорията, която съдържа данните, се съдържа в папка, наречена Graduation Project, която в комбинация с колона (поле) PlantID и това, което изглежда като много необичаен дизайн на база данни, предполага много. Например, че всичко може да се направи във VBA без никаква трудност и че SQL Server вероятно ще включва приложение към ИТ колежа, което, в зависимост от колежа, може да отнеме седмици за обработка. - person Fionnuala; 12.02.2011

Можете да използвате заявка, за да вмъкнете несравними записи, като използвате драйвера Jet за текст.

SELECT a.* INTO NewTable FROM 
(SELECT * From [Text;DSN=Import Link Specification;FMT=Delimited;HDR=NO;IMEX=2;CharacterSet=850;DATABASE=C:\Docs].[Import.txt]) As A
LEFT JOIN OldTable ON a.Key=OldTable.Key
WHERE a.Key Is Null

РЕДАКТИРАНЕ

Чудя се защо нямате основна таблица, съдържаща всички растения и местоположения. След това можете да вмъкнете всички файлове във временна таблица и съответно да добавите или актуализирате от temp.

foreach (FileInfo fri in fiarr)
    {
    string s = "[Text;DSN=Test Spec;"
         + "FMT=Fixed;HDR=Yes;IMEX=2;CharacterSet=850;DATABASE=" 
         + fri.DirectoryName + "].["
         + fri.Name + "]";

    query = "INSERT INTO Temp SELECT * FROM " + s;

    cmd.ExecuteNonQuery();
    }

Изглежда, че използвате формат с фиксирана дължина, така че DSN=Test Spec е спецификация на Access, създадена чрез експортиране на файла във формат с фиксирана ширина и след това запазване на спецификацията с помощта на бутона Разширени.

person Fionnuala    schedule 11.02.2011
comment
Предполагам. Общата идея е, че просто изпълнявате заявка срещу връзката. Ще видя дали мога да направя нещо с вашия код. - person Fionnuala; 11.02.2011
comment
BTW виждайки, че това е Access, дори не се нуждаете от C#, това може да се изпълни много просто във VBA като куп заявки. - person Fionnuala; 11.02.2011

Един проблем тук може да е, че вмъквате всеки запис ред по ред с оператори SINGLE SQL EXECUTE.

Друго решение би било:

  1. Прочетете текстовия файл в низов буфер (20 000 реда)
  2. Създайте обект DataTable
  3. В цикъл вмъкнете всеки ред в обекта DataTable.
  4. Накрая, с DataAdapter, запишете DataTable обратно в базата данни.
person Community    schedule 09.05.2012