はじめに
SQLite3 のメンテナンスを C# アプリケーションの起動時に実施する備忘録です。
改訂履歴
- 2026/08/14 : 初版公開。
本文
1. 環境
- .NET 8.0
- Microsoft.Data.Sqlite.Core 10.0.11
- SQLite3 3.53.3
- SQLitePCLRaw.bundle_e_sqlite3 2.1.12
- Visual Studio Community 2022
2. 実装
SQLiteManager クラスに Backup() と MaintenanceAsync(bool isSimple) を実装しました。Backup() の方は Microsoft.Data.Sqlite.SqliteConnection に async でバックアップできるメソッドがなかったので、同期処理になっています。
SQLiteManager.cs
using System.IO;
using Microsoft.Data.Sqlite;
namespace SQLiteMaintenanceExample;
/// <summary>
/// SQLite データベースの管理を行います。
/// </summary>
public static class SQLiteManager
{
private static readonly string s_connectionString = "Data Source=DataBase.sqlite";
/// <summary>
/// バックアップを行います。
/// </summary>
public static void Backup()
{
try
{
// exe と同じ場所に backup フォルダを作成する。
var backupDirectory = Path.Combine(AppContext.BaseDirectory, "backup");
Directory.CreateDirectory(backupDirectory);
// バックアップファイル名を作成する。
var fileName = $"DataBase_{DateTime.Now:yyyyMMdd_HHmmss}.sqlite";
var backupPath = Path.Combine(backupDirectory, fileName);
// 接続する。
using var source = new SqliteConnection(s_connectionString);
source.Open();
// バックアップ先の接続文字列を作成する。
var bkConnStringBuilder = new SqliteConnectionStringBuilder
{
DataSource = backupPath
};
// バックアップを行う。
using var destination = new SqliteConnection(bkConnStringBuilder.ToString());
destination.Open();
source.BackupDatabase(destination);
}
catch
{
// 異常処理を適宜実装する。
throw;
}
}
/// <summary>
/// メンテナンスを非同期で行います。
/// </summary>
/// <param name="isSimple">簡易メンテナンスの場合 <see langword="true"/>、それ以外の場合は <see langword="false"/>。</param>
public static async Task MaintenanceAsync(bool isSimple)
{
try
{
await using var connection = new SqliteConnection(s_connectionString);
await connection.OpenAsync();
// DB 破損チェック。
await using (SqliteCommand cmd = connection.CreateCommand())
{
cmd.CommandText = isSimple
? "PRAGMA quick_check;"
: "PRAGMA integrity_check;";
var result = (await cmd.ExecuteScalarAsync())?.ToString();
if (!string.Equals(result, "ok", StringComparison.Ordinal))
{
// 異常処理を適宜実装する。
throw new Exception("An error occurred.");
}
}
// インデックスの再構築。
if (!isSimple)
{
await using SqliteCommand cmd = connection.CreateCommand();
cmd.CommandText = "REINDEX;";
await cmd.ExecuteNonQueryAsync();
}
// 統計情報の更新。
if (!isSimple)
{
// PRAGMA optimize を実行するなら ANALYZE は不要なはずだが
// 念のため、明示的に実行しておく。
await using SqliteCommand cmd = connection.CreateCommand();
cmd.CommandText = "ANALYZE;";
await cmd.ExecuteNonQueryAsync();
}
// DB 最適化。
await using (SqliteCommand cmd = connection.CreateCommand())
{
cmd.CommandText = "PRAGMA optimize;";
await cmd.ExecuteNonQueryAsync();
}
// WAL ファイルの整理。
await using (SqliteCommand cmd = connection.CreateCommand())
{
// WAL モードの場合、WAL ファイルを整理して小さくする。
cmd.CommandText = "PRAGMA journal_mode;";
var journalMode = (await cmd.ExecuteScalarAsync())?.ToString();
if (string.Equals(journalMode, "wal", StringComparison.OrdinalIgnoreCase))
{
cmd.CommandText = "PRAGMA wal_checkpoint(TRUNCATE);";
await cmd.ExecuteNonQueryAsync();
}
}
// DB 圧縮。
await using (SqliteCommand cmd = connection.CreateCommand())
{
cmd.CommandText = "VACUUM;";
await cmd.ExecuteNonQueryAsync();
}
}
catch
{
// 異常処理を適宜実装する。
throw;
}
}
}
3. 使用例
WPF アプリケーションでの使用例です。
App.xaml.cs
using System.Windows;
namespace SQLiteMaintenanceExample;
/// <summary>
/// Windows Presentation Foundation アプリケーションのエントリーポイントを定義します。
/// </summary>
public partial class App : Application
{
// 取得元は、適宜変更する。
private static readonly bool s_isSimpleMaintenance = false;
/// <summary>
/// <see cref="Application.Startup"/> イベントを発生させます。
/// </summary>
/// <param name="e">イベントデータを含む <see cref="StartupEventArgs"/>。</param>
protected override async void OnStartup(StartupEventArgs e)
{
try
{
// データベースのバックアップとメンテナンスを実行する。
SQLiteManager.Backup();
await SQLiteManager.MaintenanceAsync(s_isSimpleMaintenance);
}
catch (Exception ex)
{
// 異常処理を適宜実装する。
MessageBox.Show(ex.ToString());
}
// メインウィンドウを表示する。
var mainWindow = new MainWindow();
MainWindow = mainWindow;
mainWindow.Show();
}
}
おわりに
DB は、パフォーマンスが低下してからが本番です。