Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Пул соединений повышает производительность приложений, используя повторное использование соединений с базами данных вместо создания новых для каждого запроса. Открытие соединения требует нескольких трудоёмких этапов:
- Драйвер устанавливает сетевой сокет.
- Драйвер завершает рукопожатие TLS.
- Драйвер аутентифицируется с сервером.
- Драйвер проверяет параметры соединения.
Пул соединений оставляет соединения открытыми и доступными для повторного использования, поэтому вашему приложению не нужно повторять эти шаги для каждого запроса.
Поведение по умолчанию
Пул соединений включен по умолчанию при создании первого соединения. Параметры по умолчанию:
| Setting | Значение по умолчанию | Описание |
|---|---|---|
max_size |
100 | Максимальное количество соединений для уникальной строки подключения. |
idle_timeout |
600 секунд (10 минут) | Количество секунд до закрытия холостых соединений. |
import mssql_python
# Pooling is automatically enabled with defaults
conn = mssql_python.connect(connection_string)
Настройка пула подключений
Настройте пул соединений перед созданием любых соединений:
import mssql_python
# Configure custom pool settings
mssql_python.pooling(max_size=50, idle_timeout=300)
# Now create connections
conn = mssql_python.connect(connection_string)
Parameters
Функция pooling() принимает следующие параметры:
| Parameter | Type | По умолчанию | Описание |
|---|---|---|---|
max_size |
int | 100 | Максимальное количество соединений в пуле для каждой строки подключения. |
idle_timeout |
int | 600 | Количество секунд, по истечении которых неактивные соединения удаляются из пула. |
enabled |
bool | True | Включите или отключите объединение. |
Отключить пул подключений
Чтобы отключить пул соединений, вызовите pooling() с enabled=False перед созданием соединений:
import mssql_python
mssql_python.pooling(enabled=False)
# Connections are now created and destroyed per use
conn = mssql_python.connect(connection_string)
Замечание
Задайте конфигурацию пула перед установкой любых соединений. Вызов pooling() после создания соединений не имеет эффекта.
Как работает объединение ресурсов
Изоляция соединительных строк
Каждая уникальная строка подключения имеет собственный независимый пул. Пулы не используют общие соединения для разных строк подключения:
# These use separate pools
conn1 = mssql_python.connect("Server=<server1>;Database=<database1>;...")
conn2 = mssql_python.connect("Server=<server2>;Database=<database2>;...")
Изоляция учётных записей
Для большинства методов аутентификации на основе токенов драйвер разделяет пулы по идентификатору Microsoft Entra, который открывает соединение, так что соединение, аутентифицированное как один принципал, не передаётся звонящему через другой. Исключением является первая строка следующей таблицы, в которой ключом служит только строка подключения.
Ключ пула зависит от метода аутентификации:
| Authentication | Ключ пула |
|---|---|
SQL-аутентификацию, доверенные соединения, сервисные принципы, интегрированная аутентификация Windows и ActiveDirectoryInteractive на Windows |
Только связная строка |
| Манажируемая идентичность | Строка соединения, плюс идентификатор клиента или идентификатор, присваиваемый системой |
| Аутентификация по коду устройства и интерактивная аутентификация на платформах, отличных от Windows | Строка подключения, а также учётная запись, под которой выполнен вход |
DefaultAzureCredential, настраиваемый token_provider, и исходные токены доступа |
Строка соединения, плюс хэш токена |
Поскольку хэш токена является частью ключа для последней группы, каждый отдельный токен получает свой собственный пул. Долгоживущий учетный код, возвращающий кэшированный токен, продолжает повторно использовать один из пулов. Драйвер отложенно освобождает неиспользуемые пулы идентификаторов по мере выполнения последующих операций с пулом, а не в фоновом потоке.
Драйвер получает токены только тогда, когда нужно открыть новое соединение, поэтому пул-хит не получает токен.
Драйвер обновляет соединения из пула, если срок действия их токена истекает менее чем через 5 минут, перед тем как выдать соединение, чтобы долгоживущие пулы не возвращали соединения, которые скоро перестанут работать.
Жизненный цикл соединения
Установление (получение соединения):
- Пул удаляет соединения с истекшим временем простоя.
- Пул пытается повторно использовать существующее соединение:
- Проверяет, активно ли соединение.
- Сбрасывает состояние соединения.
- Если обе проверки успешны, соединение возвращается.
- Если нет доступного для повторного использования соединения и размер пула меньше
max_size, драйвер создаёт новое соединение. - Если пул полностью загружен и нет корректных соединений, драйвер выдает ошибку.
Релиз (восстановление соединения):
- Если драйвер может подтвердить, что физическое соединение уже чистое, он пропускает избыточную очистку. В противном случае он откатывает открытые транзакции и включает автокоммит. Подключения с изменённым состоянием сессии всё равно требуют сброса перед повторным использованием. Если очистка не удаётся, драйвер закрывает соединение, вместо того чтобы возвращать его в пул.
- Если в пуле есть место, соединение сохраняется для повторного использования.
- Если пул находится в состоянии
max_size, драйвер немедленно закрывает соединение.
Проверки состояния соединения
Драйвер выполняет проверку состояния соединения перед повторным использованием пулового соединения.
- Проверка активности: Проверяет, что сетевое соединение по-прежнему активно.
- Сброс: Сбрасывает состояние сеанса (уровень изоляции, настройки) для последующего повторного использования.
Если одна из проверок не работает, пул отбрасывает соединение и создаёт новое.
С провайдером по умолчанию msodbcsql18 драйвер применяет временный нативный тайм-аут операции подключения во время пуловой валидации. Он использует положительный тайм-аут входа из connect(timeout=...) или attrs_before[SQL_ATTR_LOGIN_TIMEOUT]. Явный атрибут имеет приоритет. Если тайм-аут для входа равен нулю или не указан, временный тайм-аут составляет 15 секунд.
После неудачной проверки драйвер пытается выполнить повторный вход вместо того, чтобы проверять каждое оставшееся простаивающее соединение с новым тайм-аутом. Валидация может включать несколько нативных операций, очистка увеличивает время, а альтернативный вход имеет собственный тайм-аут. Временный тайм-аут — это не полная валидация или connect() дедлайн. Получение токена Microsoft Entra ID также происходит вне тайм-аута входа. Если резервный вход в систему не работает, ошибка доходит до вызывающей стороны.
Драйвер всё равно выполняет цикл запроса-ответа с сервером перед повторным использованием соединения, даже если пропускает избыточную очистку. После успешного получения драйвер восстанавливает предыдущий тайм-аут физического соединения и применяет запрошенный режим автокоммита.
Эти ограничения валидации не распространяются на провайдера с опт-ином mssql-odbc, чей тайм-аут операции подключения не является общим сроком для атрибутов соединения. Для получения дополнительной информации смотрите разделы Ограничения нативного провайдера и Тайм-аут соединения.
Автоматическая очистка
-
Тайм-аут на холостом ходу: драйвер закрывает соединения, которые не используются дольше значения
idle_timeout. -
Выход из процесса:
atexitОбработчик закрывает все объединённые соединения при завершении процесса Python.
Лучшие практики
Подобрайте подходящий размер бассейна
Подберите размер пула в соответствии с уровнем параллелизма вашего приложения.
# For a web application with 20 concurrent requests
mssql_python.pooling(max_size=25) # Slightly more than expected concurrency
Используйте менеджеры контекста
Менеджеры контекста гарантируют корректный возврат соединений в пул.
with mssql_python.connect(connection_string) as conn:
cursor = conn.cursor()
cursor.execute("SELECT TOP 5 Name, ListPrice FROM Production.Product")
rows = cursor.fetchall()
# Connection returned to pool
Поддерживайте последовательные строки соединения
Разные параметры в строках соединения создают отдельные пулы.
# These create THREE separate pools (inefficient)
conn1 = mssql_python.connect("Server=<server>;Database=<database>;Encrypt=yes;")
conn2 = mssql_python.connect("SERVER=<server>;DATABASE=<database>;ENCRYPT=yes;") # Different case
conn3 = mssql_python.connect("Server=<server>;Database=<database>;Encrypt=yes;", timeout=30) # Extra parameter
# Use a constant connection string instead
CONNECTION_STRING = "Server=<server>;Database=<database>;Encrypt=yes;"
conn1 = mssql_python.connect(CONNECTION_STRING)
conn2 = mssql_python.connect(CONNECTION_STRING) # Same pool
Рассмотрите ограничения соединения Azure SQL
База данных SQL Azure обеспечивает ограничения соединения в зависимости от уровня сервиса. Следующие значения являются приблизительными; Проверьте связанные документы для актуальных лимитов:
| Уровень служб | Максимальное число одновременных подключений |
|---|---|
| Basic | 30 |
| Стандарт S0-S2 | 60-120 |
| Стандартные версии S3 и более поздние | 200 |
| Premium | 500 |
Укажите значение max_size в пределах, указанных ниже.
# For Azure SQL Standard S2 (120 limit)
mssql_python.pooling(max_size=100) # Leave headroom
Настройте тайм-аут в режиме ожидания под свою нагрузку
-
При частых соединениях: используйте большее значение
idle_timeout, чтобы соединения оставались активными. -
Нерегулярные подключения: используйте меньшее значение
idle_timeout, чтобы освободить ресурсы.
# High-frequency API: keep connections warm
mssql_python.pooling(idle_timeout=1800) # 30 minutes
# Batch job running every hour: release between runs
mssql_python.pooling(idle_timeout=60) # 1 minute
Limitations
Текущая реализация имеет некоторые ограничения по сравнению с другими драйверами:
| Функция | Status |
|---|---|
ClearPool() / ClearAllPools() |
Недоступно. |
| Статистика/мониторинг пула | Недоступно. |
| Переопределение пула для каждого соединения | Недоступно. |
| Минимальный размер бассейна | Не настраиваемая. |
Пример: шаблон веб-приложения
Следующий пример Flask показывает, как соединения прозрачно объединяются между запросами:
import mssql_python
from flask import Flask, g
app = Flask(__name__)
# Configure pooling at startup
mssql_python.pooling(max_size=20, idle_timeout=300)
def get_db():
if 'db' not in g:
g.db = mssql_python.connect(app.config['DATABASE_URL'])
return g.db
@app.teardown_appcontext
def close_db(error):
db = g.pop('db', None)
if db is not None:
db.close() # Returns to pool
@app.route('/products')
def list_products():
conn = get_db()
cursor = conn.cursor()
cursor.execute("SELECT TOP 5 Name, ListPrice FROM Production.Product")
return cursor.fetchall()
Распознайте истощение бассейна
Когда все соединения в пуле используются и вы запрашиваете новое соединение, вы можете наблюдать следующие симптомы:
- Соединения зависают или перерываются, пока ждут бесплатного соединения.
- Пропускная способность приложений внезапно падает под нагрузкой.
- Использование памяти растёт, когда драйвер создаёт соединения, которые не может использовать повторно.
Распространенные причины:
- Соединения не возвращаются в пул. Всегда закрывайте контакты после завершения или используйте менеджеры контекста. Если соединение не закрыто, оно остаётся занятым.
- Размер бассейна слишком мал для нагрузки. Если у вас 50 одновременных запросов, но
max_size=20, 30 запросов будут ожидать. - Длительные запросы удерживают соединения. Разбивайте длительные операции или используйте выделенные соединения для пакетной работы.
Как исправить:
# 1. Always use context managers to guarantee return
with mssql_python.connect(connection_string) as conn:
cursor = conn.cursor()
cursor.execute("SELECT ...")
rows = cursor.fetchall()
# Connection returned to pool here, even if an exception occurs
# 2. Size the pool to match your concurrency
mssql_python.pooling(max_size=50) # Match or slightly exceed expected concurrent connections
# 3. Reduce idle timeout if connections go stale
mssql_python.pooling(idle_timeout=120)