Я провел некоторое время, читая различные лучшие практики для баз данных и конкретно для SQLite. В процессе чтения я обнаружил, что делаю много вещей, которые не должен делать, и при попытке исправить эти проблемы я запутался в некоторых тонкостях использования SQLite с его реализацией ADO.
Моя путаница связана с подготовленными операторами и пулом соединений.
Читая http://msdn.microsoft.com/en-us/library/ms971481.aspx, я обнаружил, что соединения должны открываться только для транзакции. Как только транзакция завершена, соединение должно быть закрыто. У меня нет четкого понимания, почему так происходит, но я исходил из предположения, что автор(ы) знают лучше меня. Я понимаю, что когда соединение закрыто, это не означает, что оно действительно закрыто. Это просто означает, что оно было возвращено в пул.
Теперь, чтобы улучшить мои запросы и вставки, я прочитал об использовании подготовленных операторов. https://stackoverflow.com/questions/1703203/in-sqlite-do-prepared-statements-really-improve-performance и http://petesbloggerama.blogspot.com/2007/02/sqlite-adonet-prepared-statements.html оба указали, что при выполнении запроса, который будет выполняться несколько раз, подготовленные операторы - это то, что нужно. Я также читал, что подготовленный оператор специфичен для соединения и что после закрытия соединения подготовленный оператор теряется.
Меня смущает следующее. Если я открываю и закрываю соединение (что может означать, а может и не означать, что соединение закрывается из-за пула потоков), то насколько полезен мне подготовленный отчет? Я могу понять, что если у меня есть 1000 объектов, которые нужно сохранить в одной транзакции, то подготовленный отчет может сильно помочь. Однако я не думаю, что получу пользу от сохранения одного объекта в транзакции, поскольку после закрытия соединения подготовленный отчет, сгенерированный на основе первого объекта, будет потерян. Верно ли это утверждение?
Мое замешательство усугубляется тем, что я полагаю, что подготовленный отчет связан с областью видимости моего объекта SQLiteCommand.
Если я создаю SQLiteCommand, представляющий запрос, который я буду выполнять часто, нужно ли мне держать этот SQLiteCommand в памяти, чтобы подготовленный оператор оставался активным?
Если я создаю новую команду SQLiteCommand с тем же оператором SQLite, распознается ли, что новая команда SQLiteCommand такая же, как и предыдущая, и, следовательно, имеет подготовленный оператор, который можно использовать?
Если я держу команду SQLiteCommand в памяти и изменяю ее параметры и соединение по мере открытия и закрытия соединения для различных транзакций, то, по сути, я сохраняю подготовленный оператор между различными соединениями?
Скорее всего, я слишком много думаю, но я надеюсь, что вы поможете мне лучше понять, как эти вещи взаимодействуют, чтобы я мог извлечь из них максимальную пользу.
Важно помнить, что и пул соединений, и подготовленные (скомпилированные) операторы - это всего лишь инструменты, которые имеют свои ограничения, и ни один подход не может быть одинаково подходящим для всех возможных ситуаций. Исходя из этого, давайте вспомним, когда может понадобиться использование пула соединений и подготовленных операторов.
Возможные причины для использования пула соединений
Пул соединений полезен, когда соединения дороги, например:
Возможные причины для использования подготовленных заявлений
Подготовленные утверждения просто предназначены для повышения производительности повторно используемых запросов за счет сокращения времени разбора.
**SQLite: Что лучше выбрать?
Ответ зависит от требований вашего приложения. Лично я не уверен, что пул соединений SQLite - это обязательно хороший выбор. Если ваше приложение однопоточное, возможно, лучше использовать одно постоянное соединение с БД SQLite, что может быть намного быстрее, чем объединение соединений, и позволит вам использовать подготовленные операторы. Это отличается от SQL Server, где объединение соединений в пул является вполне разумным выбором по умолчанию.
Если производительность имеет значение, вам определенно следует профилировать приложение, чтобы понять, выгодно ли объединение соединений SQLite для вашего сценария.
Специфические вопросы
Большинство ответов связано с текущим провайдером System.Data.SQLite
источник.
Если я открываю и закрываю свое соединение (что может означать или не означать. соединение закрывается из-за пула потоков), то насколько сильно пользы я действительно получаю от подготовленного оператора?
Как правило, вы должны рассматривать соединение, выходящее из пула, как новое, т.е. вы не должны ожидать, что получите какую-либо пользу от ранее подготовленных утверждений. Отчет будет "заново подготовлен", если только вы не сохраните команду и соединение.
Однако я не думаю, что получу выгоду от сохранения одного объекта в транзакции. объекта в транзакции, потому что как только я закрываю соединение. подготовленный отчет, который был сгенерирован из первого объекта, теперь > потерян. потерян. Верно ли это утверждение?
Это верное утверждение.
Если я создаю команду SQLiteCommand, представляющую запрос, который я буду > выполнять > часто, нужно ли мне хранить эту команду SQLiteCommand в памяти? выполнять часто, нужно ли мне держать этот SQLiteCommand в памяти для того, чтобы подготовленный запрос оставался активным?
Да, вам нужно хранить его. В SQLiteCommand
хранится ссылка на подготовленный оператор.
Если я создам новую команду SQLiteCommand с тем же оператором SQLite, будет ли она > распознана. распознается, что новый SQLiteCommand такой же, как предыдущий и поэтому имеет подготовленный оператор, который можно использовать?
Я не думаю, что это поддерживается.
Если я держу SQLiteCommand в памяти и меняю его параметры и соединение по мере того, как я открываю и закрываю соединение для различных транзакций, то я, по сути, сохраняю подготовленный оператор. между различными соединениями?
Если вы измените соединение SQLiteCommand
'а, оператор будет "заново подготовлен".
Я не уловил, в чем именно заключается основная проблема, но если проблема в том, как вставить большое количество операторов вставки в одну транзакцию за столь короткое время.
Вот класс-помощник, который я нашел ранее, который может вам помочь:
Вы можете использовать его следующим образом:
SQLiteBulkInsertHelper ContactBlk = new SQLiteBulkInsertHelper("<SQLiteConnection>","<Table Name>");
ContactBlk.AllowBulkInsert = true;
ContactBlk.AddParameter("<Column Name>", /*Column Data Type*/System.Data.DbType.Int64);
ContactBlk.AddParameter("<Column Name>", /*Column Data Type*/System.Data.DbType.String);
ContactBlk.Insert(new object[] {<First Column Value>,<Second Column Value>});
ContactBlk.Flush();
Попробуйте, если вы видите в нем решение своей проблемы.