0

みなさん午後。私はSQLiteにあまり詳しくないので、データベースのすべての設定をいじっていません。私はSQLServer、Oracle、さらにはAccessやmySQLにも精通しています。さて、現在、私は110,000以上のレコードを含むファイルを取得し、ファイルを1行ずつ読み取り、データを解析し、テーブルへの挿入ステートメントを実行しています。テーブルは、行の最初のフィールドであるレコードタイプによって異なります。さて、私は今それをロードしています、そしてそれは(私がこれを書いているように)12分間実行されており、14,000レコードしかインポートしていません。計算すると、1時間15分から1時間30分かかるということです。その時点でシステムの残りの部分がどのように動作するかによって異なります。レコードの種類が異なるため、できませんでした。SQLiteのオプションがあった場合は、一括挿入を実行します(あるかどうかはわかりません)。これはバックグラウンドワーカーとして実行されています。以下は、データをプルして解析する関数と、データをDBに挿入する関数です。これはMVC形式のC#アプリケーションであることに注意してください(私がそれを制御し、再構築する時間がないときのようなものでした):

MainForm.csバックグラウンドワーカー関数

#region Background Worker Functions

    #region private void InitializeBackgroundWorker()
    /*************************************************************************************
    *************************************************************************************/
    private void InitializeBackgroundWorker()
    {
        backgroundWorker.DoWork +=
            new DoWorkEventHandler(backgroundWorker1_DoWork);
        backgroundWorker.RunWorkerCompleted +=
            new RunWorkerCompletedEventHandler(
        backgroundWorker1_RunWorkerCompleted);
        backgroundWorker.ProgressChanged +=
            new ProgressChangedEventHandler(
        backgroundWorker1_ProgressChanged);
    }
    #endregion

/*****************************************************************************************************************************************************************************************************/

    #region private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    /*************************************************************************************
    *************************************************************************************/
    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        // Get the BackgroundWorker that raised this event.
        BackgroundWorker worker = sender as BackgroundWorker;

        // Assign the result of the computation
        // to the Result property of the DoWorkEventArgs
        // object. This is will be available to the 
        // RunWorkerCompleted eventhandler.

        //Creates a static singleton file list.  Remains on the stack and can be accessed anywhere without
        // reinstatiating
        object[] obj = (object[])e.Argument;
        string fileName = obj[0].ToString();
        DataController controller = new DataController(worker, e);
        controller.FileName = fileName;
        try
        {
            if (strProcess == "Import")
            {
                controller.Import();
            }
            else if (strProcess == "Export")
            {
                controller.ExportToExcel();
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message.ToString());
        }
    }
    #endregion

/*****************************************************************************************************************************************************************************************************/

    #region private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    /*************************************************************************************
    *************************************************************************************/
    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            MessageBox.Show(e.Error.StackTrace);
        }
        else
        {
            this.toolStripStatusLabel1.Text = "Import complete";
            generateReport();
            treeViewFigure.Nodes.Clear();
            BuildTree();
            treeViewFigure.TopNode.ExpandAll();
            labelIPBNumber.Text = controller.IPBNumber;
            this.Text += "IPB: " + labelIPBNumber.Text;

            cmbIndentureLevel.Items.Clear();
        }
    }
    #endregion

/*****************************************************************************************************************************************************************************************************/

    #region private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    /*************************************************************************************
    *************************************************************************************/
    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        string stat = e.UserState.ToString();
        this.toolStripStatusLabel1.Text = "";
        this.toolStripStatusLabel1.Text = stat;
        this.toolStripProgressBar1.Value = e.ProgressPercentage;
    }
    #endregion

#endregion

Importer.csインポート機能

    #region public void Import(string fileName)
    /*************************************************************************************
    *************************************************************************************/
    public void Import(string fileName)
    {
        if (!File.Exists(fileName))
        {
            throw new FileNotFoundException();
        }

        StreamReader read = File.OpenText(fileName);
        List<RecordBase> List = new List<RecordBase>();
        DataFactory factory = DataFactory.BuildFactory();

        int nLines = 0;

        while (!read.EndOfStream)
        {
            read.ReadLine();
            nLines++;
        }

        read.Close();
        read = File.OpenText(fileName);

        factory.lstObservers = _observers;
        factory.ClearDB();

        int count = 1;

        while (!read.EndOfStream)
        {
            string[] fields = read.ReadLine().Split('|');
            List<string> lstStr = new List<string>();
            foreach (string str in fields)
            {
                lstStr.Add(str);
            }

            lstStr.RemoveAt(fields.Length - 1);
            fields = lstStr.ToArray();

            string strValues = string.Join("','", fields);
            strValues = "'" + strValues + "'";
            if (fields.Length >= 39 && fields[0] == "03")
            {
                factory.ImportTaggedRecord(fields[38], count);
                int nIndex = strValues.IndexOf(fields[38]);
                strValues = strValues.Substring(0, nIndex - 2);
            }

            factory.ImportIPB(strValues, fields[0], count);

            progress.ProgressComplete = (count * 100) / nLines;
            progress.Message = "Importing Record: " + count++.ToString();
            Notify();
        }
    }
    #endregion

DataFactory.csImportIPB関数

    #region public void ImportIPB(string strValues, string strType)
    /*************************************************************************************
    *************************************************************************************/
    public void ImportIPB(string strValues, string strType, int nPosition)
    {
        string strCommand = string.Empty;

        switch (strType)
        {
            case "01":
                strCommand = Queries.strIPBInsert;
                break;
            case "02":
                strCommand = Queries.strFigureInsert;
                break;
            case "03":
                strCommand = Queries.strPartInsert;
                break;
        }

        ExecuteNonQuery(strCommand + strValues + ", " + nPosition.ToString() + ")");
    }
    #endregion

Database.csExecuteNonQueryメソッド

    #region public void ExecuteNonQuery(string strSQL)
    /*************************************************************************************
    *************************************************************************************/
    public void ExecuteNonQuery(string strSQL)
    {
        DbCommand dbCommand = _dbConnection.CreateCommand();
        dbCommand.CommandText = strSQL;
        dbCommand.Prepare();
        dbCommand.ExecuteNonQuery();
    }
    #endregion

誰かが提供されたものから改善できるものを見ることができますか?より速く動作するように設定できるバックグラウンドワーカーの設定はありますか?バックグラウンドワーカーのデフォルト設定はありますか?挿入を高速化するために(SQLite Expert Personalを使用して)変更できるdbファイルにはどのような設定がありますか?それは私のファイルのサイズだけですか?今、これを終えると、22分を過ぎて24,000レコードを記録しました。これは時間に敏感な問題ではないので、必要な時間をすべて取ってください。ありがとう。

更新:また、テーブルの1つに整数の主キー(IDフィールドとして機能)があることにも言及する必要があると思います。パフォーマンスの問題はありますか?

4

4 に答える 4

5

SQLiteTransactionインサート全体にシングルを使用します。現状では、ACID準拠を維持するために、挿入のたびにファイルへのフラッシュが強制されます。他のDbConnectionandと同様に、を使用し、完了したらDbTransaction、を使用します。挿入全体が成功または失敗し、パフォーマンスが向上します。BeginTransactionCommit

于 2010-08-31T18:19:42.887 に答える
1

挿入のパフォーマンスを向上させる最も重要なことは、単一のトランザクションのみを開始することです。これにより、インサートの速度が大幅に向上します。

この現象を説明するFAQエントリについては、こちらを参照してください。

于 2010-08-31T18:22:09.270 に答える
1

FWIW、SQLiteのコマンドラインクライアントには、データ読み込みの組み込みコマンドがあります。しかし、そのSQLiteクライアントのCコードを読むと、特別なことは何もしていないことがわかります。データファイルを1行ずつ読み取り、ループでINSERTを実行するだけです。

他の回答では、各行の後にI / Oフラッシュのオーバーヘッドを回避できるように、明示的なトランザクションを使用することが提案されています。私はそのアドバイスに同意します、それは確かに大きな利益をもたらすでしょう。

ロールバックジャーナルを無効にすることもできます。

PRAGMA journal_mode = OFF

または、書き込みを非同期に設定して、オペレーティングシステムがI/Oをバッファリングできるようにします。

PRAGMA synchronous = OFF

これらのプラグマの変更により、I/Oのオーバーヘッドが大幅に節約されます。ただし、ロールバックジャーナルがないと、ROLLBACKコマンドは機能せず、進行中のトランザクション中にアプリケーションがクラッシュすると、データベースが破損する可能性があります。同期書き込みがないと、オペレーティングシステムの障害によってデータが失われる可能性もあります。

怖がらせようとはしていませんが、パフォーマンスと保証されたI/Oの整合性の間にはトレードオフがあることを知っておく必要があります。ほとんどの場合、安全モードを有効にして操作することをお勧めします。また、ビッグデータの読み込みを行う必要がある場合は、一時的に無効にすることをお勧めします。その後、安全モードを再度有効にすることを忘れないでください。

于 2010-08-31T18:38:57.950 に答える
0

私は実験を重ねてきましたが、C#を使用して大規模なデータベースをSQLiteにインポートする最も簡単な方法は、実際にはcsvにダンプしてから、コマンドラインsqlite3.exeツールを使用することです。

私のラップトップに挿入する約2500万行を含む大きなファイルで

.NETラッパーを使用した最適化された挿入:30分(トランザクション、パラメーター化されたコマンド、ジャーナルオフなどで最適化)

CSVにダンプ(2分)してから、sqllite3.exeを使用してCSVをインポートします(5分):7分

于 2012-09-05T17:04:16.370 に答える