На мой взгляд, некорректно сравнивать встроенную базу данных (например, SQL CE) с реляционной базой данных на стороне сервера (как и все остальные, кроме SQLite и встроенной версии Firebird).
Основное различие между ними состоит в том, что реляционные базы данных общего назначения на стороне сервера (такие как MS SQL, MySQL, Firebird Classic и SuperServer и т. Д.) Устанавливаются как независимая служба и запускаются выходит за рамки вашего основного приложения . Вот почему они могут работать намного лучше благодаря встроенной поддержке многоядерных и многопроцессорных архитектур, используя функции ОС, такие как предварительное кэширование, VSS и т. Д., Для увеличения пропускной способности в случае интенсивной работы базы данных и могут требовать столько же памяти, сколько ваша ОС может обеспечить один сервис / приложение. Это также означает, что показатели производительности для них более или менее независимы от вашего приложения, но во многом зависят от вашего оборудования. В этом отношении я бы сказал, что серверные версии любой базы данных всегда более производительны, чем встроенные.
SQL CE (наряду с Firebird Embedded, SQLite, TurboSQL и некоторыми другими) являются встроенными механизмами БД , что означает, что вся база данных упакована в один (или максимально 2) DLL-файл, который распространяется вместе с вашей заявкой. Из-за очевидных ограничений по размеру (хотите ли вы распределить 30 МБ DLL вместе с вашим приложением длиной 2-3 МБ?), Они также запускаются непосредственно в контексте вашего приложения и всего память и производительность для операций доступа к данным совместно используются с другими частями вашего приложения - что касается как доступной памяти, времени ЦП, пропускной способности диска и т. д. Наличие потоков с интенсивными вычислениями, работающих параллельно с вашим потоком доступа к данным, может привести к резкое снижение производительности вашей базы данных.
Из-за различных областей применения эти базы данных имеют разную палитру опций: server-db обеспечивает расширенное управление пользователями и правами, поддержку представлений и хранимых процедур, в то время как встроенная база данных, как правило, не имеет никакой поддержки пользователей и управления правами и имеет ограниченную поддержка представлений и хранимых процедур (последние теряют большинство преимуществ работы на стороне сервера). Пропускная способность данных является обычным узким местом СУБД, версии серверов обычно устанавливаются на чередующиеся тома RAID, тогда как встроенные БД часто ориентированы на память (стараются сохранить все фактические данные в памяти) и сводят к минимуму операции доступа к хранилищу данных.
Итак, возможно, имеет смысл сравнить различные встроенные СУБД для .Net по их производительности, такие как MS SQL CE 4.0, SQLite, Firebird Embedded, TurboSQL . Я не ожидал бы резких различий во время обычной непиковой работы, в то время как некоторые базы данных могут обеспечить лучшую поддержку больших 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();
}
}
}
Необходимый отказ от ответственности:
- Я получил эти результаты на своем компьютере: Dell Precision WorkStation T7400, оснащенный 2 процессорами Intel Xeon E5420 и 8 ГБ оперативной памяти, работающий с 64-разрядной ОС Win7 Enterprise .
- Я использовал настройки по умолчанию для обеих БД со строкой соединения "Data Source = database_file_name".
- Я использовал последние версии SQL CE 4.0 и SQLite / System.Data.SQLite (с сегодняшнего дня, 3 июня 2011 г.).
Вот результаты для двух разных образцов:
> =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
Итак, как вы можете видеть, любые операции записи (создание, обновление, удаление) требуют почти в 1000 раз больше времени в SQLite по сравнению с SQLCE. Это не обязательно отражает общую плохую производительность этой базы данных и может быть связано со следующим:
- Поставщик данных, который я использую для SQLite, - это System.Data.SQLite , представляющий собой смешанную сборку, содержащую как управляемый, так и неуправляемый код (SQLite изначально написан полностью на C, а DLL обеспечивает только привязки) , Вероятно, P / Invoke и маршалинг данных пожирают хорошую часть рабочего времени.
- Скорее всего, SQLCE 4.0 кэширует все данные в памяти по умолчанию, тогда как SQLite сбрасывает большинство изменений данных непосредственно в дисковое хранилище каждый раз, когда происходит изменение. Можно указать сотни параметров для обеих баз данных через строку подключения и настроить их соответствующим образом.
- Я использовал серию отдельных запросов для проверки БД. По крайней мере, SQLCE поддерживает массовые операции через специальные классы .Net, которые здесь лучше подходят. Если SQLite также их поддерживает (извините, я здесь не эксперт, и мой быстрый поиск ничего не дал), было бы неплохо сравнить их.
- Я наблюдал много проблем с SQLite на машинах x64 (используя тот же адаптер .net): от неожиданного закрытия подключения к данным до повреждения файла базы данных. Я предполагаю, что есть некоторые проблемы со стабильностью либо с адаптером данных, либо с самой библиотекой.