6

編集3:

私の問題は今のところ解決したと思います...サービスとテストアプリの両方を、SYSTEMアカウントではなくアカウントとして実行するように変更しましたNetworkService。ユーザー アカウントの変更によるメリットが持続するのか、それとも一時的なものなのかはまだわかりません。

元の質問:

小さな 224kB の SQLite DB を C# アプリケーションで開くのが非常に遅く、数ミリ秒から 1.5 秒以上かかることに気付きました。以下は私のコードで、今日の午後に追加したデバッグ ステートメントがすべて含まれています。cnn.Open();ここのログに示されているように、呼び出しに絞り込みました。

2014-03-27 15:05:39,864 DEBUG - Creating SQLiteConnection...
2014-03-27 15:05:39,927 DEBUG - SQLiteConnection Created!
2014-03-27 15:05:39,927 DEBUG - SQLiteConnection Opening...
2014-03-27 15:05:41,627 DEBUG - SQLiteConnection Opened!
2014-03-27 15:05:41,627 DEBUG - SQLiteCommand Creating...
2014-03-27 15:05:41,627 DEBUG - SQLiteCommand Created!
2014-03-27 15:05:41,627 DEBUG - SQLiteCommand executing reader...
2014-03-27 15:05:41,658 DEBUG - SQLiteCommand executed reader!
2014-03-27 15:05:41,658 DEBUG - DataTable Loading...
2014-03-27 15:05:41,767 DEBUG - DataTable Loaded!

ご覧のとおり、この例では、接続を開くのに 1.7 秒かかりました。これを繰り返してみましたが、後続の接続がほぼすぐに開くか、このように遅れるかを予測できません。

なんらかの接続プーリングの使用を検討しましたが、単一インスタンスのシングルスレッド アプリケーションでそれを追求する価値はありますか? 現在、SQLiteDatabase クラスのインスタンスを作成し、クエリごとに以下の関数を呼び出しています。

public DataTable GetDataTable(string sql)
{
    DataTable dt = new DataTable();
    try
    {
        Logging.LogDebug("Creating SQLiteConnection...");
        using (SQLiteConnection cnn = new SQLiteConnection(dbConnection))
        {
            Logging.LogDebug("SQLiteConnection Created!");
            Logging.LogDebug("SQLiteConnection Opening...");
            cnn.Open();
            Logging.LogDebug("SQLiteConnection Opened!");
            Logging.LogDebug("SQLiteCommand Creating...");
            using (SQLiteCommand mycommand = new SQLiteCommand(cnn))
            {
                Logging.LogDebug("SQLiteCommand Created!");
                mycommand.CommandText = sql;
                Logging.LogDebug("SQLiteCommand executing reader...");
                using (SQLiteDataReader reader = mycommand.ExecuteReader())
                {
                    Logging.LogDebug("SQLiteCommand executed reader!");
                    Logging.LogDebug("DataTable Loading...");
                    dt.Load(reader);
                    Logging.LogDebug("DataTable Loaded!");
                    reader.Close();
                }
            }
            cnn.Close();
        }
    }
    catch (Exception e)
    {
        throw new Exception(e.Message);
    }
    return dt;
}

編集:

確かにdbConnection、次の関数によって設定された接続文字列です。 inputFile開くファイル名の文字列パスです。

public SqLiteDatabase(String inputFile)
{
    dbConnection = String.Format("Data Source={0}", inputFile);
}

sqlそして、この時点では、 cnn.Open() が失速する時点まで到達していないため、無関係だと思います。

編集2:

わかりました、さらにテストを行いました。テストをローカルで実行すると、1000 回の反復ループが約 5 秒で完了し、cnn.Open(). ローカル PC で行ったのと同じ Windows インストーラーからテストを実行すると、約 25 分で完了し、cnn.Open().

TestOpenConn()テスト ディレクトリにあるファイルのコピーに対して実行するサービス プログラム (Windows サービスで実行されているのとまったく同じコード) から関数を呼び出すだけの小さなテスト プログラムを作成しました。これをサーバーまたはローカル PC で実行すると、許容できるパフォーマンスが得られます (サーバーでは呼び出しごとに 1.95 ミリ秒、ローカル PC では呼び出しごとに 4 ミリ秒)。

namespace EGC_Timing_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Logging.Init("log4net.xml", "test.log");
            var db = new SqLiteDatabase("config.sqlite");
            db.TestOpenConn();
        }
    }
}

テスト関数は次のとおりです。

public void TestOpenConn()
{
    // TODO: Remove this after testing loop of opening / closing SQLite DB repeatedly:
    const int iterations = 1000;
    Logging.LogDebug(String.Format("Running TestOpenConn for {0} opens...", iterations));
    var startTime = DateTime.Now;
    for (var i = 0; i < iterations; i++)
    {
        using (SQLiteConnection cnn = new SQLiteConnection(dbConnection))
        {
            Logging.LogDebug(String.Format("SQLiteConnection Opening, iteration {0} of {1}...", i, iterations));
            var startTimeInner = DateTime.Now;
            cnn.Open();
            var endTimeInner = DateTime.Now;
            var diffTimeInner = endTimeInner - startTimeInner;
            Logging.LogDebug(String.Format("SQLiteConnection Opened in {0}ms!", diffTimeInner.TotalMilliseconds));
            cnn.Close();
        }
    }
    var endTime = DateTime.Now;
    var diffTime = endTime - startTime;
    Logging.LogDebug(String.Format("Done running TestOpenConn for {0} opens!", iterations));
    Logging.LogInfo(String.Format("{0} iterations total:\t{1}", iterations, diffTime));
    Logging.LogInfo(String.Format("{0} iterations average:\t{1}ms", iterations, diffTime.TotalMilliseconds/iterations));
}
4

4 に答える 4

5

私の問題は今のところ解決したと思います...サービスとテストアプリの両方を、SYSTEMアカウントではなくアカウントとして実行するように変更しましたNetworkService。ユーザー アカウントの変更によるメリットが持続するのか、それとも一時的なものなのかはまだわかりません。

于 2014-04-01T12:20:30.290 に答える
3

System.Data.SQLiteオープンソースライブラリを使用していると仮定しています。

その場合、クラスのOpenメソッドに深刻なパフォーマンスの問題があることを Visual Studio Performance Profiler で簡単に確認できます。SQLiteConnectionまた、このクラスのソース コードを参照してください: https://system.data.sqlite.org/index.html/artifact/97648754af51ffd6

XML 構成と Windows 環境変数を読み取るために非常に多くのディスク アクセスが行われています。

私の提案は、呼び出しOpen()をできるだけ少なくして、この開いているSQLiteConnectionオブジェクトへの参照をメモリ内に保持することです。公演チケットはSQLite Forum

于 2015-08-21T00:05:48.723 に答える
0

データベースを使用して、適切なユーザーの「変更」権限をフォルダーに追加できます。フォルダーを右クリック > プロパティ > セキュリティ > 編集 > 追加 (IIS_Users を追加しました) > [変更] チェックボックスを選択 > [OK]

于 2014-08-07T19:54:41.160 に答える