私の意見では、組み込みデータベース(SQL CEなど)とサーバー側のリレーショナルデータベース(SQLiteと組み込みバージョンのFirebirdを除く他のすべてのデータベース)を比較するのは正しくありません。
それらの主な違いは、汎用サーバー側リレーショナルデータベース (MS SQL、MySQL、Firebird Classic、SuperServerなど)は独立したサービスとしてインストールされ、メインアプリケーションの範囲外で実行されます 。そのため、マルチコアおよびマルチCPUアーキテクチャの本質的なサポートにより、プリキャッシング、VSSなどのOS機能を使用して、集中的なデータベース操作の場合にスループットを向上させ、同じ量のメモリを要求できるため、パフォーマンスが大幅に向上します。 OSは単一のサービス/アプリケーションを提供できます。また、それらのパフォーマンスインジケーターは、アプリケーションからほぼ独立していますが、ハードウェアに大きく依存していることも意味します。この点で、どのデータベースのサーバーバージョンも、組み込みバージョンに比べて常にパフォーマンスが高いと言えます。
SQL CE(Firebird Embedded、SQLite、TurboSQLなど)は組み込みDBエンジン 、つまり、データベース全体が単一(または最大2つ)のDLLファイルにパックされ、アプリケーションと一緒に配布されます。明らかなサイズ制限のため(30 MBのDLLを2〜3 MBの長さのアプリケーションと一緒に配布する必要がありますか?)、それらはアプリケーションのコンテキストで直接実行されます また、データアクセス操作のメモリとパフォーマンスの合計は、アプリケーションの他の部分と共有されます --これは、使用可能なメモリ、CPU時間、ディスクスループットなどの両方に関係します。データアクセススレッドと並行して計算集約型のスレッドを実行すると、データベースのパフォーマンスが大幅に低下する可能性があります。
アプリケーションの領域が異なるため、これらのデータベースにはさまざまなオプションのパレットがあります。server-dbは、広範なユーザーと権利の管理、ビューとストアドプロシージャのサポートを提供しますが、組み込みデータベースは通常、ユーザーと権利の管理のサポートがなく、ビューのサポートが制限されています。およびストアドプロシージャ(後者はサーバー側で実行する利点の大部分を失います)。データスループットはRDBMSの通常のボトルネックであり、サーバーバージョンは通常ストライプRAIDボリュームにインストールされますが、組み込みDBは多くの場合メモリ指向であり(すべての実際のデータをメモリに保持するようにしてください)、データストレージアクセス操作を最小限に抑えます。
>
したがって、おそらく意味があるのは、MS SQL CE 4.0、SQLite、Firebird Embedded、TurboSQLなどの.Net用のさまざまな組み込みRDBMSのパフォーマンスを比較することです。 。 通常の非ピーク操作中に大幅な違いはないと思いますが、一部のデータベースでは、OSとの統合が優れているため、大規模なBLOBのサポートが向上する場合があります。
-更新-
迅速な実装は非常に興味深い結果を示しているため、最後の言葉を取り戻す必要があります。
両方のデータプロバイダーをテストするための短いコンソールアプリケーションを作成しました。これらを自分で試してみたい場合のソースコードは次のとおりです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SQLite;
using System.Data.SqlServerCe;
using System.Data.Common;
namespace TestSQL
{
class Program
{
const int NUMBER_OF_TESTS = 1000;
private static string create_table;
private static string create_table_sqlce = "CREATE TABLE Test ( id integer not null identity primary key, textdata nvarchar(500));";
private static string create_table_sqlite = "CREATE TABLE Test ( id integer not null primary key, textdata nvarchar(500));";
private static string drop_table = "DROP TABLE Test";
private static string insert_data = "INSERT INTO Test (textdata) VALUES ('{0}');";
private static string read_data = "SELECT textdata FROM Test WHERE id = {0}";
private static string update_data = "UPDATE Test SET textdata = '{1}' WHERE id = {0}";
private static string delete_data = "DELETE FROM Test WHERE id = {0}";
static Action<DbConnection> ACreateTable = (a) => CreateTable(a);
static Action<DbConnection> ATestWrite = (a) => TestWrite(a, NUMBER_OF_TESTS);
static Action<DbConnection> ATestRead = (a) => TestRead(a, NUMBER_OF_TESTS);
static Action<DbConnection> ATestUpdate = (a) => TestUpdate(a, NUMBER_OF_TESTS);
static Action<DbConnection> ATestDelete = (a) => TestDelete(a, NUMBER_OF_TESTS);
static Action<DbConnection> ADropTable = (a) => DropTable(a);
static Func<Action<DbConnection>,DbConnection, TimeSpan> MeasureExecTime = (a,b) => { var start = DateTime.Now; a(b); var finish = DateTime.Now; return finish - start; };
static Action<string, TimeSpan> AMeasureAndOutput = (a, b) => Console.WriteLine(a, b.TotalMilliseconds);
static void Main(string[] args)
{
// opening databases
SQLiteConnection.CreateFile("sqlite.db");
SQLiteConnection sqliteconnect = new SQLiteConnection("Data Source=sqlite.db");
SqlCeConnection sqlceconnect = new SqlCeConnection("Data Source=sqlce.sdf");
sqlceconnect.Open();
sqliteconnect.Open();
Console.WriteLine("=Testing CRUD performance of embedded DBs=");
Console.WriteLine(" => Samplesize: {0}", NUMBER_OF_TESTS);
create_table = create_table_sqlite;
Console.WriteLine("==Testing SQLite==");
DoMeasures(sqliteconnect);
create_table = create_table_sqlce;
Console.WriteLine("==Testing SQL CE 4.0==");
DoMeasures(sqlceconnect);
Console.ReadKey();
}
static void DoMeasures(DbConnection con)
{
AMeasureAndOutput("Creating table: {0} ms", MeasureExecTime(ACreateTable, con));
AMeasureAndOutput("Writing data: {0} ms", MeasureExecTime(ATestWrite, con));
AMeasureAndOutput("Updating data: {0} ms", MeasureExecTime(ATestUpdate, con));
AMeasureAndOutput("Reading data: {0} ms", MeasureExecTime(ATestRead, con));
AMeasureAndOutput("Deleting data: {0} ms", MeasureExecTime(ATestDelete, con));
AMeasureAndOutput("Dropping table: {0} ms", MeasureExecTime(ADropTable, con));
}
static void CreateTable(DbConnection con)
{
var sqlcmd = con.CreateCommand();
sqlcmd.CommandText = create_table;
sqlcmd.ExecuteNonQuery();
}
static void TestWrite(DbConnection con, int num)
{
for (; num-- > 0; )
{
var sqlcmd = con.CreateCommand();
sqlcmd.CommandText = string.Format(insert_data,Guid.NewGuid().ToString());
sqlcmd.ExecuteNonQuery();
}
}
static void TestRead(DbConnection con, int num)
{
Random rnd = new Random(DateTime.Now.Millisecond);
for (var max = num; max-- > 0; )
{
var sqlcmd = con.CreateCommand();
sqlcmd.CommandText = string.Format(read_data, rnd.Next(1,num-1));
sqlcmd.ExecuteNonQuery();
}
}
static void TestUpdate(DbConnection con, int num)
{
Random rnd = new Random(DateTime.Now.Millisecond);
for (var max = num; max-- > 0; )
{
var sqlcmd = con.CreateCommand();
sqlcmd.CommandText = string.Format(update_data, rnd.Next(1, num - 1), Guid.NewGuid().ToString());
sqlcmd.ExecuteNonQuery();
}
}
static void TestDelete(DbConnection con, int num)
{
Random rnd = new Random(DateTime.Now.Millisecond);
var order = Enumerable.Range(1, num).ToArray<int>();
Action<int[], int, int> swap = (arr, a, b) => { int c = arr[a]; arr[a] = arr[b]; arr[b] = c; };
// shuffling the array
for (var max=num; max-- > 0; ) swap(order, rnd.Next(0, num - 1), rnd.Next(0, num - 1));
foreach(int index in order)
{
var sqlcmd = con.CreateCommand();
sqlcmd.CommandText = string.Format(delete_data, index);
sqlcmd.ExecuteNonQuery();
}
}
static void DropTable(DbConnection con)
{
var sqlcmd = con.CreateCommand();
sqlcmd.CommandText = drop_table;
sqlcmd.ExecuteNonQuery();
}
}
}
必要な免責事項:
- 自分のマシンで次の結果が得られました:2つのIntelXeon E5420CPUと8GBのRAMを搭載し、64ビットのWin7Enterpriseを実行しているDellPrecision WorkStation T7400 。
- 両方のDBのデフォルト設定を使用しました 接続文字列「DataSource=database_file_name」を使用。
- SQLCE4.0とSQLite/System.Data.SQLiteの両方の最新バージョンを使用しました(本日、2011年6月3日から)。
2つの異なるサンプルの結果は次のとおりです。
> =Testing CRUD performance of embedded DBs= > => Samplesize: 200 > ==Testing SQLite== > Creating table: 396.0396 ms > Writing data: 22189.2187 ms > Updating data: 23591.3589 ms > Reading data: 21.0021 ms > Deleting data: 20963.0961 ms > Dropping table: 85.0085 ms > ==Testing SQL CE 4.0== > Creating table: 16.0016 ms > Writing data: 25.0025 ms > Updating data: 56.0056 ms > Reading data: 28.0028 ms > Deleting data: 53.0053 ms > Dropping table: 11.0011 ms
...そしてより大きなサンプル:
=Testing CRUD performance of embedded DBs= => Samplesize: 1000 ==Testing SQLite== Creating table: 93.0093 ms Writing data: 116632.6621 ms Updating data: 104967.4957 ms Reading data: 134.0134 ms Deleting data: 107666.7656 ms Dropping table: 83.0083 ms ==Testing SQL CE 4.0== Creating table: 16.0016 ms Writing data: 128.0128 ms Updating data: 307.0307 ms Reading data: 164.0164 ms Deleting data: 306.0306 ms Dropping table: 13.0013 ms
したがって、ご覧のとおり、SQLiteではSQLCEと比較して書き込み操作(作成、更新、削除)に約1000倍の時間が必要です。これは、必ずしもこのデータベースの一般的なパフォーマンスの低下を反映しているわけではなく、次の原因による可能性があります。
- SQLiteに使用するデータプロバイダーは、System.Data.SQLite です。 、これはマネージコードとアンマネージコードの両方を含む混合アセンブリです(SQLiteは元々完全にCで記述されており、DLLはバインディングのみを提供します)。おそらく、P/Invokeとデータマーシャリングは操作時間のかなりの部分を消費します。
- ほとんどの場合、SQLCE 4.0はデフォルトですべてのデータをメモリにキャッシュしますが、SQLiteは、変更が発生するたびに、ほとんどのデータ変更をディスクストレージに直接フラッシュします。接続文字列を介して両方のデータベースに数百のパラメータを提供し、それらを適切に調整できます。
- 一連の単一クエリを使用してDBをテストしました。少なくともSQLCEは、ここでより適している特別な.Netクラスを介した一括操作をサポートしています。 SQLiteもそれらをサポートしている場合(申し訳ありませんが、私はここの専門家ではなく、私のクイック検索では何も期待できませんでした)、それらも比較するとよいでしょう。
- (同じ.netアダプターを使用した)x64マシン上のSQLiteで、データ接続が予期せず閉じられたり、データベースファイルが破損したりするなど、多くの問題が発生しました。データアダプタまたはライブラリ自体に安定性の問題があると思います。