Создание соединений с базой данных - сделать это один раз или для каждого запроса?

101

В данный момент я создаю соединение с базой данных при первой загрузке моей веб-страницы. Затем я обрабатываю страницу и выполняю любые запросы в соответствии с этим. Это лучший способ сделать это, или я должен создавать соединение с базой данных каждый раз, когда я запускаю запрос?

PS Для меня имеет больше смысла создать 1 соединение и использовать его, но я не знаю, может ли это вызвать какие-либо другие проблемы.

Я использую C # (ASP.NET) с MSSQL.

webnoob
источник

Ответы:

124

Если вы создаете по одному на запрос / транзакцию, гораздо проще управлять «закрытием» соединений.

Я понимаю, почему здравый смысл требует, чтобы вы открывали его и использовали его повсеместно, но у вас будут проблемы с разорванными соединениями и многопоточностью. Таким образом, ваш следующий шаг будет состоять в том, чтобы открыть пул, скажем, 50 соединений, и держать их все открытыми, передавая их различным процессам. И тогда вы поймете, что это именно то, что .NET Framework делает для вас уже .

Если вы открываете соединение, когда вам это нужно, и удаляете его по окончании, это на самом деле не закрывает соединение, а просто возвращает его в пул соединений для повторного использования.

прецизионный самописец
источник
Просто читал эту статью, когда вы ее опубликовали :) Спасибо.
webnoob
2
Веб-страница, на которую вы ссылаетесь, относится к SQL Server. Обеспечивает ли .NET также автоматический пул при подключении к другим базам данных, например - Oracle, Sqlite, MySql?
Briddums
@briddums - я думаю, что это зависит от разъема. .Net, например, не предоставляет соединитель MySql. Он написан и поддерживается MySql. И хотя это работает, по моему опыту, более ранняя реализация была далека от ошибок.
ZweiBlumen
1
@briddums: зависит от сборки провайдера. Я уверен, что и реализация Oracle от Microsoft, и собственная Oracle поддерживают пул соединений, потому что я их использовал. Я слышал, что есть MySql, и я ожидаю, что провайдеры в Spring.NET будут поддерживать пул, но вам лучше искать или спрашивать поставщика напрямую, чем спрашивать меня.
pdr
1
Следует известно , что открытие, выполнение запроса и утилизации соединения, даже в цикле, в равной степени , как быстро, а иногда и быстрее , чем открытие его один раз и цикл запроса. Всегда просто распоряжайся. Это более безопасно и быстро. Не беспокойтесь о получении соединения из пула - это так тривиально.
smdrager
38

Рекомендуется создавать одно соединение для каждого запроса, а в случае отображения данных рекомендуется, чтобы запрос вводил все необходимые данные за один раз.

Исходная информация:

В .NET при вызове SqlConnection.Open()по умолчанию всегда прозрачно используется пул соединений (см. «Использование пула соединений с SQL Server» в MSDN). Таким образом, вы можете просто получить новое соединение, используя Open(), и позвонить, Close()когда вы закончите, и .NET будет делать правильные вещи.

Обратите внимание, что без пула соединений одно соединение на запрос было бы очень плохой идеей, поскольку создание реальных соединений с базой данных может быть очень дорогостоящим (аутентификация, сетевые издержки и т. Д.), А количество одновременно открытых соединений обычно очень ограничено.

Одед
источник
7
@webnoob - Так как .NET использует пул соединений, нет. Причина в том, что соединения могут закрываться, перераспределяться и т. Д., Поэтому повторное использование соединения не является хорошей практикой.
Одед
11
-1 Ответ довольно обманчивый. Создание соединения по запросу - очень плохая идея. Вероятно, вы имеете в виду «получить новое соединение для каждого запроса из пула соединений», но это не то же самое, что создание соединения.
Слеське
1
@ Sleske - Чем это отличается от ответа pdr?
Одед
3
@Oded: Ах, я вижу. В .NET при вызове SqlConnection.Open()всегда будет прозрачно использоваться пул соединений. Таким образом, разницы между «открыть соединение» и «получить соединение из пула» не существует. Мое недоразумение. Я позволил себе отредактировать небольшое объяснение вопроса и вернул голосование.
Слеське
2
@ eaglei22 - так и должно быть (см. docs.microsoft.com/en-us/dotnet/framework/data/adonet/… ). Как правило, вы хотите вернуть соединение с пулом как можно скорее, хотя, если вы выполняете несколько запросов в последовательности, может быть лучше повторно использовать соединение, как вы предлагаете. Вам нужно будет проверить и посмотреть, какой подход лучше для вас (я не знаю, какие критерии вы используете - проверьте оба пути и посмотрите, как они влияют на выбранные вами показатели).
Одед
0

Помните, что все это в контексте экосистемы .Net.

Разработчики иногда хотят «оптимизировать» свой код, чтобы повторно использовать свои объекты подключения. Учитывая контекст этого вопроса, это почти всегда ошибка.

ADO.Net имеет функцию, которая называется Пул подключений . Когда вы создаете и открываете новый объект соединения, вы действительно запрашиваете соединение из пула. Когда вы закрываете соединение, вы возвращаете его в пул.

Важно понимать объекты, которые мы используем непосредственно в коде: SqlConnection, MySqlConnection, OleDbConnectio и т. Д. - это всего лишь обертки вокруг реального базового соединения, управляемого ADO.Net, а реальные соединения ADO.Net намного «тяжелее» и дороже. с точки зрения производительности. Именно эти базовые объекты имеют такие проблемы, как аутентификация, сетевой транзит, шифрование, и эти вещи намного перевешивают небольшой объем памяти в объекте, который вы фактически видите в своем собственном коде.

Когда вы пытаетесь повторно использовать объект соединения, вы лишаете ADO.Net возможности эффективно управлять важными связями. Вы получаете эффективность в маленькой вещи за счет гораздо большей вещи.

Повторное использование соединения через приложение или запрос http также может вынудить вас случайно сериализовать что-то, что в противном случае могло бы работать параллельно, и стало бы узким местом в производительности. Я видел это в реальных приложениях.

В случае примера с веб-страницей, где вы, по крайней мере, сохраняете небольшое соединение только на время одного http-запроса / ответа, вы можете получить еще большую эффективность, оценивая, какие запросы выполняются в вашем конвейере запросов, и пытаясь получить они сводятся к как можно меньшему количеству отдельных запросов к базе данных (подсказка: вы можете отправить более одного запроса в одной строке SQL и использовать DataReader.NextResult()или проверять разные таблицы DataSetдля перемещения между ними).

Другими словами, вместо того, чтобы думать с точки зрения повторного использования одного соединения для приложения или запроса HTTP по сравнению с одним соединением на запрос, думайте с точки зрения одного соединения для каждого вызова в базу данных ... каждый цикл туда и обратно. Затем попытайтесь свести к минимуму количество подключений путем минимизации количества этих поездок. Таким образом, вы можете удовлетворить обе цели.


Но это только один вид оптимизации. Есть также оптимизация времени программиста и получение эффективного повторного использования кода. Разработчики не хотят снова и снова писать один и тот же шаблонный код, чтобы получить открытый и готовый к использованию объект подключения. Это не только утомительно, но и позволяет вносить ошибки в программу.

Но даже здесь, как правило, лучше иметь одно соединение на запрос (или в оба конца). Есть и другие шаблоны, которые вы можете использовать, чтобы избежать переписывания того же стандартного кода. Вот один пример, который мне нравится, но есть много других.

Джоэл Коухорн
источник
Я опаздываю на эту вечеринку, но я думаю, что этот ответ охватывает некоторые важные моменты :)
Джоэл Коухорн