Ответ 1
На мой взгляд, неверно сравнивать встроенную базу данных (например, SQL CE) и серверную реляционную базу данных (как и все остальные, за исключением SQLite и Embedded версии Firebird).
Основное различие между ними заключается в том, что общедоступные серверные реляционные базы данных (например, MS SQL, MySQL, Firebird Classic и SuperServer и т.д.) устанавливаются как независимая служба и за пределами области вашего основного приложения. Именно поэтому они могут работать намного лучше из-за внутренней поддержки многоядерных и многопроцессорных архитектур, используя функции ОС, такие как предварительное кэширование, VSS и т.д., Для увеличения пропускной способности в случае интенсивной работы с базой данных и могут требовать столько памяти, сколько ваша ОС может обеспечить единую услугу/приложение. Это также означает, что показатели эффективности для них более или менее независимы от вашего приложения, но во многом зависят от вашего оборудования. В этом отношении я бы сказал, что серверные версии любой базы данных всегда больше производительности по сравнению со встроенными.
SQL CE (наряду с Firebird Embedded, SQLite, TurboSQL и некоторыми другими) - это встроенные механизмы БД, что означает, что полная база данных упакована в один (или максимально 2) DLL файлы, которые распространяются вместе с вашим приложением. Из-за очевидных ограничений по размеру (хотите ли вы распространять 30 МБ DLL вместе с вашим 2-3-мегабайтным приложением?), Они также запускаются непосредственно в контексте вашего приложения, а общая < мощная > память и производительность для операций доступа к данным разделяются с другими частями вашего приложения, что касается как доступной памяти, так и времени процессора, пропускной способности диска и т.д. Имея интенсивный поток вычислений, выполняющийся параллельно с потоком доступа к данным может привести к резкому снижению производительности вашей базы данных.
В связи с различными областями применения эти базы данных имеют различную палитру опций: server-db обеспечивает расширенное пользовательское и правильное управление, поддержку представлений и хранимых процедур, тогда как встроенная база данных обычно не имеет никакой поддержки для пользователей и управления правами и ограничена поддержка просмотров и хранимых процедур (последние теряют большинство своих преимуществ от работы на стороне сервера). Пропускная способность данных является обычным узким местом РСУБД, серверные версии обычно устанавливаются на чередующиеся тома RAID, тогда как встроенные БД часто ориентированы на память (стараются сохранить все фактические данные в памяти) и минимизировать операции доступа к хранилищу данных.
Таким образом, вероятно, было бы сравнение различных встроенных RDBMS для .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.
- Я использовал настройки по умолчанию для обеих БД со строкой подключения "Источник данных = имя_базы_файла".
- Я использовал последние версии 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-адаптера): из-за неожиданного закрытия подключения к повреждению файла базы данных. Я предполагаю, что есть некоторые проблемы с стабильностью либо с адаптером данных, либо с самой библиотекой.