Menurut pendapat saya, tidak benar untuk membandingkan basis data tertanam (seperti SQL CE) versus basis data relasional sisi server (seperti yang lainnya, kecuali untuk SQLite dan versi Tertanam dari Firebird).
Perbedaan utama di antara keduanya adalah basis data relasional sisi server tujuan umum (seperti MS SQL, MySQL, Firebird Classic dan SuperServer, dll.) diinstal sebagai layanan independen dan berjalan di luar cakupan aplikasi utama Anda . Itulah mengapa mereka dapat melakukan jauh lebih baik karena dukungan intrinsik untuk arsitektur multi-core dan multi-CPU, menggunakan fitur OS seperti pra-caching, VSS dll untuk meningkatkan throughput dalam kasus operasi database intensif dan dapat mengklaim memori sebanyak OS Anda dapat menyediakan satu layanan/aplikasi. Ini juga berarti bahwa indikator kinerja untuk mereka kurang lebih independen dari aplikasi Anda, tetapi sebagian besar bergantung pada perangkat keras Anda. Dalam hal ini saya akan mengatakan bahwa versi server dari basis data apa pun selalu memiliki kinerja yang lebih baik dibandingkan dengan yang disematkan.
SQL CE (bersama dengan Firebird Embedded, SQLite, TurboSQL dan beberapa lainnya) adalah mesin DB tertanam , artinya database lengkap dikemas ke dalam satu (atau maksimal 2) file DLL yang didistribusikan bersama dengan aplikasi Anda. Karena keterbatasan ukuran yang jelas (apakah Anda ingin mendistribusikan 30 MB DLL bersama dengan aplikasi Anda yang panjangnya 2-3 MB?) mereka juga berjalan langsung dalam konteks aplikasi Anda dan total memori dan kinerja untuk operasi akses data dibagikan dengan bagian lain dari aplikasi Anda -- yang berkaitan dengan memori yang tersedia, waktu CPU, throughput disk, dll. Memiliki utas komputasi intensif yang berjalan paralel dengan utas akses data Anda dapat menyebabkan penurunan kinerja database Anda secara dramatis.
Karena area aplikasi yang berbeda, basis data ini memiliki palet opsi yang berbeda:server-db menyediakan manajemen pengguna dan hak yang luas, dukungan untuk tampilan dan prosedur tersimpan, sedangkan basis data tertanam biasanya tidak memiliki dukungan untuk pengguna dan manajemen hak dan memiliki dukungan terbatas untuk tampilan dan prosedur tersimpan (yang terakhir kehilangan sebagian besar manfaatnya berjalan di sisi server). Throughput data adalah hambatan RDBMS yang biasa, versi server biasanya diinstal pada volume RAID bergaris, sedangkan DB tertanam sering kali berorientasi pada memori (coba untuk menyimpan semua data aktual dalam memori) dan meminimalkan operasi akses penyimpanan data.
Jadi, yang mungkin masuk akal adalah membandingkan RDBMS tertanam yang berbeda untuk .Net untuk kinerjanya, seperti MS SQL CE 4.0, SQLite, Firebird Embedded, TurboSQL . Saya tidak mengharapkan perbedaan drastis selama operasi non-puncak biasa, sedangkan beberapa database dapat memberikan dukungan yang lebih baik untuk BLOB besar karena integrasi yang lebih baik dengan OS.
-- memperbarui --
Saya harus menarik kembali kata-kata terakhir saya, karena implementasi cepat saya menunjukkan hasil yang sangat menarik.
Saya menulis aplikasi konsol pendek untuk menguji kedua penyedia data, berikut adalah kode sumber untuk Anda jika Anda ingin bereksperimen sendiri.
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();
}
}
}
Penafian yang diperlukan:
- Saya mendapatkan hasil ini di komputer saya:Dell Precision WorkStation T7400 dilengkapi dengan 2 CPU Intel Xeon E5420 dan RAM 8GB, menjalankan 64bit Win7 Enterprise .
- Saya menggunakan setelan default untuk kedua DB dengan string koneksi "Sumber Data=database_file_name".
- Saya menggunakan versi terbaru dari SQL CE 4.0 dan SQLite/System.Data.SQLite (mulai hari ini, 3 Juni 2011).
Berikut adalah hasil untuk dua sampel yang berbeda:
> =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
... dan sampel yang lebih besar:
=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
Jadi, seperti yang Anda lihat, setiap operasi penulisan (buat, perbarui, hapus) membutuhkan hampir 1000x lebih banyak waktu di SQLite dibandingkan dengan SQLCE. Ini tidak selalu mencerminkan kinerja buruk database ini secara umum dan mungkin disebabkan oleh hal-hal berikut:
- Penyedia data yang saya gunakan untuk SQLite adalah System.Data.SQLite , yaitu Majelis campuran yang berisi kode terkelola dan tidak terkelola (SQLite awalnya ditulis sepenuhnya dalam C dan DLL hanya menyediakan binding). Mungkin P/Invoke dan marshaling data menghabiskan sebagian besar waktu operasi.
- Kemungkinan besar SQLCE 4.0 menyimpan semua data dalam memori secara default, sedangkan SQLite mem-flush sebagian besar perubahan data langsung ke penyimpanan disk setiap kali perubahan terjadi. Seseorang dapat menyediakan ratusan parameter untuk kedua database melalui string koneksi dan menyetelnya dengan tepat.
- Saya menggunakan serangkaian kueri tunggal untuk menguji DB. Setidaknya SQLCE mendukung operasi massal melalui kelas .Net khusus yang akan lebih cocok di sini. Jika SQLite juga mendukungnya (maaf, saya bukan ahli di sini dan pencarian cepat saya tidak memberikan hasil yang menjanjikan) akan lebih baik untuk membandingkannya juga.
- Saya telah mengamati banyak masalah dengan SQLite pada mesin x64 (menggunakan adaptor .net yang sama):dari koneksi data yang ditutup secara tidak terduga hingga kerusakan file database. Saya kira ada beberapa masalah stabilitas baik dengan adaptor data atau dengan perpustakaan itu sendiri.