編集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));
}