Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
O pooling de ligações melhora o desempenho das aplicações ao reutilizar ligações à base de dados em vez de criar novas para cada pedido. Abrir uma ligação envolve vários passos demorados:
- O controlador cria um socket de rede.
- O driver completa o aperto de mão TLS.
- O driver autentica-se com o servidor.
- O driver valida os parâmetros da ligação.
O pooling de ligações mantém as ligações abertas e disponíveis para reutilização, por isso a sua aplicação não precisa de repetir estes passos para cada pedido.
Comportamento padrão
O agrupamento de ligações está ativado por defeito quando cria a sua primeira ligação. As configurações padrão são:
| Setting | Valor predefinido | Descrição |
|---|---|---|
max_size |
100 | Número máximo de ligações por cada cadeia de ligação única. |
idle_timeout |
600 segundos (10 minutos) | Número de segundos antes de as ligações inativas serem fechadas. |
import mssql_python
# Pooling is automatically enabled with defaults
conn = mssql_python.connect(connection_string)
Configurar o agrupamento de conexões
Configure o pooling antes de criar qualquer ligação:
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
A pooling() função aceita os seguintes parâmetros:
| Parâmetro | Tipo | Default | Descrição |
|---|---|---|---|
max_size |
int | 100 | Número máximo de ligações agrupadas por cadeia de ligação. |
idle_timeout |
int | 600 | Segundos antes de as conexões inativas serem removidas do pool. |
enabled |
bool | Verdade | Ativar ou desativar o pooling. |
Desativar o agrupamento de ligações
Para desativar o agrupamento, chame pooling() com enabled=False antes de criar conexões:
import mssql_python
mssql_python.pooling(enabled=False)
# Connections are now created and destroyed per use
conn = mssql_python.connect(connection_string)
Note
Defina a configuração de agrupamento antes de estabelecer qualquer conexão. Chamar pooling() depois de criar ligações não tem efeito.
Como funciona o agrupamento
Isolamento da corda de ligação
Cada cadeia de ligação única mantém o seu próprio pool independente. Os pools não partilham ligações entre diferentes cadeias de ligações:
# These use separate pools
conn1 = mssql_python.connect("Server=<server1>;Database=<database1>;...")
conn2 = mssql_python.connect("Server=<server2>;Database=<database2>;...")
Isolamento da identidade
Para a maioria dos métodos de autenticação baseados em tokens, o controlador separa os pools em função da identidade Microsoft Entra que abre a ligação, para que uma ligação autenticada como uma identidade principal não seja atribuída a um autor da chamada que utilize uma identidade principal diferente. A exceção é a primeira linha da tabela seguinte, onde a chave é apenas a cadeia de ligação.
A chave do pool depende do método de autenticação:
| Authentication | Chave do conjunto |
|---|---|
Autenticação SQL, ligações confiáveis, princípios de serviço, autenticação integrada no Windows e ActiveDirectoryInteractive no Windows |
Apenas cadeia de ligação |
| Identidade gerenciada | String de ligação, mais o ID do cliente ou a identidade atribuída pelo sistema |
| Autenticação por código de dispositivo e autenticação interativa em plataformas diferentes do Windows | String de ligação, mais a conta com sessão de entrada |
DefaultAzureCredential, um(a) token_provider personalizado(a), e tokens de acesso em bruto |
String de ligação, mais um hash do token |
Como o hash do token faz parte da chave para o último grupo, cada token distinto recebe o seu próprio pool. Uma credencial de longa duração que devolve um token em cache continua a reutilizar um pool. O controlador recupera de forma diferida os conjuntos de identidades inativos à medida que são executadas operações posteriores sobre o conjunto, em vez de o fazer através de uma thread em segundo plano.
O condutor só adquire tokens quando precisa de abrir uma nova ligação, por isso um hit de pool não adquire um.
O driver atualiza as ligações agrupadas cujo token está dentro de 5 minutos após o vencimento antes da ligação ser entregue, para que pools de longa duração não devolvam ligações prestes a falhar.
Ciclo de vida da ligação
Obter (estabelecer uma ligação):
- O conjunto remove ligações expiradas por inatividade.
- A piscina tenta reutilizar uma ligação existente:
- Verifica se a ligação está ativa.
- Reinicia o estado da ligação.
- Se ambos os testes tiverem sucesso, a ligação retorna.
- Se não existir nenhuma ligação reutilizável e o pool estiver abaixo de
max_size, o driver cria uma nova ligação. - Se o pool estiver com capacidade máxima e sem ligações válidas, o driver gera um erro.
Libertar (devolver uma conexão):
- Se a piscina tiver capacidade, armazena a ligação para reutilização.
- Se o pool estiver em
max_size, o controlador fecha a conexão imediatamente.
Verificações do estado da ligação
O controlador efetua verificações do estado da ligação antes de voltar a utilizar uma ligação do conjunto.
- Verificação de atividade: Garante que a ligação à rede continua válida.
- Verificação de reset: Reinicia o estado da sessão (nível de isolamento, definições) para uma reutilização limpa.
Se algum dos testes falhar, o pool descarta a ligação e cria uma nova.
Limpeza automática
-
Tempo de espera de inatividade: O driver fecha ligações que não são utilizadas por mais tempo do que o
idle_timeoutvalor. -
Saída do processo: Um
atexitprocessador fecha todas as ligações agrupadas quando o processo Python termina.
Melhores práticas
Dimensione a sua piscina de forma adequada
Ajuste o tamanho do seu grupo com a concorrência da sua aplicação.
# For a web application with 20 concurrent requests
mssql_python.pooling(max_size=25) # Slightly more than expected concurrency
Utilizar gestores de contexto
Os gestores de contexto garantem que as ligações sejam corretamente devolvidas ao pool.
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
Mantenha as cadeias de ligação consistentes
Parâmetros diferentes nas cadeias de ligação criam pools separados.
# 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
Considere os limites de ligação do SQL do Azure
Base de Dados SQL do Azure impõe limites de ligação com base no nível de serviço. Os valores seguintes são aproximados; Consulte a documentação ligada para os limites atuais:
| Escalão de serviço | Máximo de conexões simultâneas |
|---|---|
| Básico | 30 |
| Padrão S0-S2 | 60-120 |
| Standard S3 e versões posteriores | 200 |
| Premium | 500 |
Reduza o valor max_size abaixo destes limites.
# For Azure SQL Standard S2 (120 limit)
mssql_python.pooling(max_size=100) # Leave headroom
Ajuste o tempo limite de inatividade da sua carga de trabalho
-
Ligações frequentes: Use um valor mais longo
idle_timeoutpara manter as ligações quentes. -
Ligações esporádicas: Use um valor mais
idle_timeoutcurto para libertar recursos.
# 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
A implementação atual tem algumas limitações em comparação com outros drivers:
| Feature | Situação |
|---|---|
ClearPool() / ClearAllPools() |
Não disponível. |
| Estatísticas e monitorização do pool | Não disponível. |
| Override por pool de ligação | Não disponível. |
| Tamanho mínimo da piscina | Não é configurável. |
Exemplo: padrão de aplicação web
O exemplo seguinte do Flask mostra como as ligações são agrupadas de forma transparente entre pedidos:
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()
Reconhecer o cansaço na piscina
Quando todas as ligações da piscina estão em uso e solicita uma nova ligação, observa sintomas como:
- As ligações ficam suspensas ou apagam enquanto se espera por uma ligação gratuita.
- A taxa de processamento da aplicação cai subitamente sob carga.
- O consumo de memória aumenta à medida que o driver cria ligações que não consegue reutilizar.
Causas comuns:
- As ligações não são devolvidas ao pool. Fecha sempre as ligações quando terminares, ou usa gestores de contexto. Uma ligação que não está fechada mantém-se verificada.
- A piscina é demasiado pequena para a carga de trabalho. Se tiver 50 solicitações simultâneas, mas se
max_size=20, 30 solicitações ficam em espera. - Consultas de longa duração mantêm ligações. Divida as operações longas em partes ou use ligações dedicadas para processamento em lote.
Como corrigir:
# 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)