Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este artigo aborda como escrever código PHP rápido contra SQL Server, Banco de Dados SQL do Azure, Instância Gerenciada de SQL do Azure, Azure Synapse Analytics e banco de dados SQL no Microsoft Fabric. A orientação se aplica tanto ao SQLSRV quanto ao PDO_SQLSRV, que envolvem o mesmo Microsoft ODBC Driver subjacente para SQL Server.
Comece pelas mudanças de maior impacto
Se você só puder fazer três mudanças, faça estas alterações:
- Ative o pooling de conexão. Estabelecer uma nova conexão TLS com o SQL Server leva dezenas a centenas de milissegundos, dependendo do caminho da rede e da negociação do TLS. Reutilizar conexões agrupadas elimina esse custo por requisição. Veja Gerenciar conexões de forma eficiente.
- Busque apenas as colunas e linhas que você precisa.
SELECT *e consultas ilimitadas são as causas mais comuns de endpoints lentos. Veja Consultar apenas o que você precisa. - Use parâmetros de tabela para inserções em massa. Para centenas de linhas ou mais, parâmetros de tabela (TVPs) são tipicamente muito mais rápidos do que as instruções linha por
INSERTlinha e escalam linearmente com a contagem de linhas. Veja Inserir dados de forma eficiente.
Gerencie conexões de forma eficiente
O estabelecimento de conexão é a operação mais cara que o motorista realiza. Quase toda investigação de desempenho do PHP termina com uma correção de gerenciamento de conexão.
Habilitar o pool de conexões
O pooling reutiliza conexões ODBC entre requisições PHP em vez de desmontá-las no final da requisição. O objeto de conexão é descartado quando seu script termina, mas o handle ODBC subjacente permanece ativo no pool do gerenciador de drivers ODBC e é reutilizado pela próxima solicitação que pede a mesma cadeia de conexão.
Windows: O pooling de conexões está ativado por padrão. Para confirmar, deixe essa ConnectionPooling opção fora do seu DSN. Para desabilitar o pooling para depuração, defina ConnectionPooling=0.
Linux e macOS: O pooling de conexões não é uma opção DSN nessas plataformas. Ative-o no gerenciador de drivers definindo Pooling=Yes a [ODBC] seção de odbcinst.ini, e defina um positivo CPTimeout sob a estrofe do driver. Por exemplo:
[ODBC]
Pooling=Yes
[ODBC Driver 18 for SQL Server]
Description=Microsoft ODBC Driver 18 for SQL Server
Driver=/opt/microsoft/msodbcsql18/lib64/libmsodbcsql-18.<version>.so.1.1
CPTimeout=120
Encontre o caminho real da biblioteca com odbcinst -q -d -n "ODBC Driver 18 for SQL Server" ou ls /opt/microsoft/msodbcsql18/lib64/. O nome do arquivo incorpora a versão instalada do driver ODBC e muda a cada lançamento.
CPTimeout (em segundos) controla quanto tempo as conexões ociosas ficam na piscina antes de serem fechadas. Defina alto o suficiente para que a maioria dos pedidos encontre uma conexão em pool, mas baixo o suficiente para que conexões obsoletas com um servidor com falha sejam aposentadas razoavelmente rápido. 60 a 300 segundos funcionam bem para a maioria das cargas de trabalho web.
Para mais detalhes, consulte pool de conexões.
Entenda o custo da primeira consulta
O MARS (conjunto de resultados ativos múltiplos) está habilitado por padrão. Quando o MARS e o pooling de conexões estão ativos, o driver reinicia a conexão em pool na primeira consulta, e esse reset ignora qualquer tempo de espera da consulta que você tenha definido para essa primeira consulta. Consultas posteriores na mesma conexão normalmente respeitam o timeout. Se você definir tempos de espera agressivos na primeira consulta em uma carga de trabalho agrupada, leve em conta esse comportamento ou desative o MARS se MultipleActiveResultSets=false não precisar. Veja a nota MARS e pooling em Conexão pooling.
Conexões PDO persistentes não são suportadas
PDO_SQLSRV rejeita PDO::ATTR_PERSISTENT. Definindo nos arremessos do construtor:
SQLSTATE[IMSSP]: An unsupported attribute was designated on the PDO object.
Use o pooling de conexões ODBC para reutilização entre requisições. É o mecanismo nativo do driver, funciona tanto para PDO_SQLSRV quanto para SQLSRV, e desativa conexões ociosas (CPTimeouto que também mantém Microsoft Entra atualização de token honesta).
Reutilize a conexão dentro de uma solicitação
Mesmo com pooling, abrir uma nova conexão PDO ou SQLSRV implica uma ida e volta ODBC para buscar e validar um handle em pool. Abra uma conexão por requisição e passe para todas as funções que precisem.
Dica
Um contêiner de injeção de dependência ou um acessor preguiçoso já é suficiente. O objetivo é evitar new PDO(...) no meio de um gerenciador de requisições.
Consulte apenas o que você precisa
Viagens de rede e materialização de conjuntos de resultados dominam a latência de consulta na maioria das cargas de trabalho PHP. As correções são as mesmas que se aplicam a todas as camadas de acesso a banco de dados.
Selecione apenas as colunas que você usa
SELECT * puxa todas as colunas, incluindo varchar(max) e varbinary(max) que superam os dados que você realmente consome. Diga as colunas:
<?php
// Slow: fetches all columns, including a 2 MB LOB column
$stmt = $conn->query("SELECT * FROM dbo.Products");
// Fast: fetches only the two columns the caller uses
$stmt = $conn->query("SELECT ProductID, Name FROM dbo.Products");
Busque apenas as fileiras que você precisa
Faça filtragem push para o SQL Server. Nunca faça uma tabela inteira para PHP só para filtrar um foreach loop.
<?php
// Slow: transfers every row to PHP, then filters
$rows = $conn->query("SELECT * FROM dbo.Orders")->fetchAll(PDO::FETCH_ASSOC);
$recent = array_filter($rows, fn($r) => $r["OrderDate"] > "2026-01-01");
// Fast: filters on the server
$stmt = $conn->prepare("SELECT OrderID, CustomerID, Total FROM dbo.Orders WHERE OrderDate > ?");
$stmt->execute(["2026-01-01"]);
$recent = $stmt->fetchAll(PDO::FETCH_ASSOC);
Paginar grandes conjuntos de resultados
Para uma visualização de lista que mostra algumas centenas de linhas entre milhões, não devolva todas as linhas e deixe o cliente organizar tudo. Use paginação do lado do servidor com OFFSET ... FETCH:
<?php
function fetchPage(PDO $conn, int $page, int $pageSize): array {
$stmt = $conn->prepare(
"SELECT OrderID, CustomerID, Total
FROM dbo.Orders
ORDER BY OrderID
OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"
);
// With native prepares, execute([...]) binds values as strings.
// OFFSET and FETCH NEXT require integer bindings; bind explicitly.
$stmt->bindValue(1, ($page - 1) * $pageSize, PDO::PARAM_INT);
$stmt->bindValue(2, $pageSize, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Escolha o método certo de busca
- Use
fetch(PDO::FETCH_ASSOC)em loop para iteração em streaming quando não precisar de todas as linhas na memória ao mesmo tempo. -
fetchAll(PDO::FETCH_ASSOC)Use quando o chamador realmente precisar de todo o conjunto (por exemplo, renderizando uma resposta JSON completa). - Use
fetchColumn()quando você só se importa com um único escalar (umCOUNT,SUM, ouMAX). - Use
PDO::FETCH_KEY_PAIRouPDO::FETCH_UNIQUEconstrua dicionários de consulta sem uma segunda passagem.
Modos numéricos de busca (PDO::FETCH_NUM) são marginalmente mais rápidos que modos associativos porque pulam a construção do mapa de nomes de coluna. Prefiro clareza; Só trocar quando um perfilador sinalizar o overhead de busca como significativo.
Preferência SET NOCOUNT ON em procedimentos armazenados e lotes
Cada INSERTinstrução , UPDATE, and DELETE retorna um DONE_IN_PROC token com a contagem de linhas afetada, que o PHP normalmente descarta. O token não adiciona uma viagem de ida e volta, mas cada um ainda custa bytes no fio e uma pequena quantidade de trabalho do driver. Em um procedimento ou lote de múltiplas instruções que executa centenas de extratos por chamada, a economia se acumula. Desligue:
CREATE OR ALTER PROCEDURE dbo.ProcessOrder
@OrderID INT
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Inventory SET Stock = Stock - 1 WHERE ProductID IN (SELECT ProductID FROM dbo.OrderLines WHERE OrderID = @OrderID);
UPDATE dbo.Orders SET Status = 'Processed' WHERE OrderID = @OrderID;
END;
Inserir dados de forma eficiente
Escolha o método certo de inserção com base em quantas fileiras você está movendo. A escolha errada pode ser 100 vezes mais lenta.
Menos de cerca de 100 linhas: declaração preparada em um loop
Para pequenos lotes, execute uma única instrução preparada em um ciclo:
<?php
$stmt = $conn->prepare("INSERT INTO dbo.Products (Name, Price) VALUES (?, ?)");
foreach ($products as $p) {
$stmt->execute([$p["name"], $p["price"]]);
}
Envolva o loop em uma transação para que todos os inserts sejam comprometidos como uma unidade única e o log não precise ser esvaziado após cada linha:
<?php
$conn->beginTransaction();
try {
$stmt = $conn->prepare("INSERT INTO dbo.Products (Name, Price) VALUES (?, ?)");
foreach ($products as $p) {
$stmt->execute([$p["name"], $p["price"]]);
}
$conn->commit();
} catch (PDOException $e) {
$conn->rollBack();
throw $e;
}
Centenas a milhões de linhas: parâmetros com valores de tabela
Parâmetros de tabela (TVPs) enviam todo o lote para o SQL Server em uma única ida e volta e permitem que o SQL Server processe o conjunto como uma única instrução. Para lotes de centenas de linhas ou mais, os TVPs são tipicamente muito mais rápidos que um loop de declaração preparada e escalam linearmente com a contagem de linhas.
Primeiro, crie um tipo de tabela no servidor:
CREATE TYPE dbo.ProductTableType AS TABLE (
Name NVARCHAR(100),
Price DECIMAL(10, 2)
);
PDO_SQLSRV passa o TVP como um array associativo cuja chave é o nome do tipo e cujo valor é o conjunto de linhas. Vincule-o com PDO::PARAM_LOB:
<?php
$rows = [];
foreach ($products as $p) {
$rows[] = [$p["name"], $p["price"]];
}
$tvpInput = ["ProductTableType" => $rows];
$stmt = $conn->prepare(
"INSERT INTO dbo.Products (Name, Price) SELECT Name, Price FROM ?"
);
$stmt->bindParam(1, $tvpInput, PDO::PARAM_LOB);
$stmt->execute();
Para um esquema não padrão, passe o esquema como o próximo elemento do array: ["ProductTableType" => $rows, "Sales"]. Para exemplos de sintaxe procedural SQLSRV e procedimentos armazenados, veja Usar parâmetros de valores de tabela.
Milhões de linhas: bcp ou BULK INSERT
Para operações realmente em massa (cargas de data warehouse, migrações iniciais), use BCP ou BULK INSERT em vez de PHP. Escreva seus dados em um arquivo delimitado ou de formato nativo, depois execute o bcp ou BULK INSERT a partir de um job agendado, etapa ETL ou script de administração.
Caution
Se você pagar para BCP a partir do PHP com shell_exec() ou proc_open(), nunca interpole entradas não confiáveis na linha de comando. Use escapeshellarg() em todos os argumentos, e prefira executar a carga fora de banda em vez de em um caminho de requisição web.
Reduzir viagens de ida e volta
Cada ida e volta de rede entre PHP e SQL Server tem um custo fixo. Quando você envia cinco extratos em um lote, paga esse custo uma vez em vez de cinco vezes.
Combine instruções relacionadas em um único lote
Para trabalhos relacionados que rodam juntos, coloque as instruções em um único lote e consuma todos os conjuntos de resultados:
<?php
$sql = "
SELECT * FROM dbo.Customers WHERE CustomerID = ?;
SELECT * FROM dbo.Orders WHERE CustomerID = ?;
SELECT * FROM dbo.Addresses WHERE CustomerID = ?;
";
$stmt = $conn->prepare($sql);
$stmt->execute([$id, $id, $id]);
$customer = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->nextRowset();
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->nextRowset();
$addresses = $stmt->fetchAll(PDO::FETCH_ASSOC);
Para SQLSRV, use sqlsrv_next_result para avançar entre conjuntos de resultados.
Ative múltiplos conjuntos de resultados ativos quando precisar
Múltiplos Conjuntos de Resultados Ativos (MARS) permitem que uma única conexão tenha múltiplas instruções ativas. Sem o MARS, você não pode emitir uma nova consulta em uma conexão que ainda tem um conjunto de resultados aberto. Ambos os drivers ativam o MARS por padrão. Para desligá-lo, coloque MultipleActiveResultSets=false sua cadeia de conexão. Veja Desabilitar Múltiplos Conjuntos de Resultados Ativos (MARS).
O MARS é conveniente, mas não gratuito. Cada conjunto de resultados ativo consome recursos do lado do servidor. Prefira consumir um conjunto de resultados completo antes de começar outro. Use o MARS para desbloquear padrões de cursor genuinamente aninhados.
Ajuste declarações preparadas
Instruções preparadas salvam o driver de re-parsar SQL no servidor, e permitem que você vincule com segurança entradas não confiáveis como parâmetros.
Prefira preparações nativas
PDO_SQLSRV pode preparar instruções em dois modos.
O Native Prepara envia o texto SQL para o servidor uma vez e reutiliza a instrução analisada para cada execução, enviando apenas os valores dos parâmetros em cada execute().
Os prepares emulados mantêm o texto SQL no cliente e reconstruem uma string SQL completa com parâmetros interpolados em cada execução.
Configure PDO::ATTR_EMULATE_PREPARES => false para que o driver use preparações nativas. Preparações nativas permitem que o SQL Server armazene em cache e reutilize o plano de consulta, e evitam re-analisar o texto SQL em cada execução.
<?php
$conn = new PDO($dsn, null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
Reutilizar declarações preparadas
Prepare uma vez, execute muitas. Cada prepare() chamada custa uma alocação de handle ODBC e uma análise do lado do servidor. Em um circuito quente, mantenha o $stmt objeto vivo e chame execute() dentro do loop:
<?php
// Fast: one prepare, many executes.
$stmt = $conn->prepare("UPDATE dbo.Inventory SET Stock = Stock - ? WHERE ProductID = ?");
foreach ($orderLines as $line) {
$stmt->execute([$line["qty"], $line["productId"]]);
}
// Slow: re-prepares the same SQL on every iteration.
foreach ($orderLines as $line) {
$stmt = $conn->prepare("UPDATE dbo.Inventory SET Stock = Stock - ? WHERE ProductID = ?");
$stmt->execute([$line["qty"], $line["productId"]]);
}
Cuidado com TOP (?) e IN (?, ?, ...)
TOPrequer parênteses ao redor de um marcador de parâmetro, SELECT TOP (?) ..., para que o SQL Server possa analisar a contagem de linhas como um parâmetro.
IN (?, ?, ?, ?) requer uma contagem temporária fixa no momento de preparar. Para tamanhos dinâmicos IN de lista, construa a cadeia provisória a partir de uma contagem de inteiros validada, ou passe a lista como um parâmetro com valor em tabela.
Caution
Nunca interpole a entrada bruta do usuário no texto SQL (incluindo a contagem de placeholder). Faça a contagem com (int) antes de construir a string provisória e sempre passe os valores execute() reais como parâmetros.
Gerencie cursores e memória
O tipo padrão de cursor é PDO::CURSOR_FWDONLY, uma mangueira de incêndio apenas para frente. Ele transmite linhas para PHP uma de cada vez e não faz buffer, então um grande conjunto de resultados é limitado pela memória de buffer de linha em vez da contagem total de linhas. Geralmente é isso que você quer.
Use cursores com buffer apenas quando precisar recuar ou contar linhas
PDO::SQLSRV_CURSOR_BUFFERED (um cursor estático bufferizado no lado do cliente) recupera todo o conjunto de resultados para a memória PHP inicialmente. Essa abordagem permite que você chame, rowCount()procure para trás e reutilize a afirmação. Por padrão, o buffer é limitado a 10.240 KB (10 MB) via PDO::SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE, e uma consulta cujo conjunto de resultados excede os retornos false do limite, em vez de sobrecarregar memória PHP. Você pode elevar o limite em direção ao limite de memória do PHP, mas ao fazer isso troca o false retorno por um erro fatal real Allowed memory size exhausted quando uma consulta ultrapassa o novo limite. Afine deliberadamente.
Veja Tipos de cursor (PDO_SQLSRV).
Cursores roláveis do lado do servidor (PDO::SQLSRV_CURSOR_STATIC, PDO::SQLSRV_CURSOR_DYNAMIC, PDO::SQLSRV_CURSOR_KEYSET) armazenam buffer no servidor em vez do cliente, para que eles não consomam memória PHP. No entanto, eles armazenam recursos do lado do servidor durante toda a duração do cursor e são mais lentos por linha do que apenas forward.
Use o modo padrão de somente para frente para leituras em streaming. Use o lado do cliente com buffer para conjuntos de resultados pequenos quando precisar rowCount() ou rolagem para trás. Evite cursores roláveis do lado do servidor, a menos que você esteja fazendo algo específico.
<?php
// Fast, low memory: default forward-only, one row at a time
$stmt = $conn->prepare("SELECT OrderID, Total FROM dbo.Orders");
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// ...
}
// Buffered: only when you need rowCount() or seeking
$stmt = $conn->prepare("SELECT * FROM dbo.SmallLookup", [
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED,
]);
$stmt->execute();
$rowCount = $stmt->rowCount();
Para uma análise completa, veja Tipos de cursor (PDO_SQLSRV) e Tipos de cursor (SQLSRV).
Fluxar valores binários grandes e de caracteres
Para varbinary(max), varchar(max), nvarchar(max), xml e outros tipos grandes, use fluxos PHP em vez de materializar o valor inteiro na memória:
<?php
$stmt = $conn->prepare("SELECT Name, PhotoBlob FROM dbo.Products WHERE ProductID = ?");
$stmt->execute([$id]);
$stmt->bindColumn("PhotoBlob", $photo, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);
// $photo is a stream resource; write it directly to disk without loading it all
$outFile = fopen("/tmp/photo.bin", "wb");
stream_copy_to_stream($photo, $outFile);
fclose($outFile);
Para inserir ou atualizar com valores grandes, use SendStreamParamsAtExec=false no SQLSRV para enviar dados de fluxo em blocos após sqlsrv_execute(). Para detalhes, veja Enviar dados como um fluxo.
Definir tempos limite apropriados
Timeouts são tanto configurações de desempenho quanto de confiabilidade. Perguntas longas mantêm conexões na piscina e impedem outras solicitações.
Tempo limite da instrução
Defina um limite de tempo por sentença para que uma consulta descontrolada não retenha uma conexão de pool indefinidamente. Para PDO_SQLSRV:
<?php
$stmt = $conn->prepare("SELECT ... FROM dbo.HugeTable ...");
$stmt->setAttribute(PDO::SQLSRV_ATTR_QUERY_TIMEOUT, 30); // seconds
$stmt->execute();
Para SQLSRV, passe "QueryTimeout" => 30 o array de opções para sqlsrv_query ou sqlsrv_prepare.
Defina um valor que combine com sua carga de trabalho. Para uma requisição web síncrona, de 15 a 30 segundos é o normal. Para um trabalho em lote de fundo, alguns minutos podem ser razoáveis. Nunca defina o timeout para zero (ilimitado) em uma requisição web.
Tempo limite do logon
LoginTimeoutna cadeia de conexão controla quanto tempo o driver espera para estabelecer uma conexão. Defina um valor explícito ao conectar ao Banco de Dados SQL do Azure ou Instância Gerenciada de SQL do Azure para que cold starts e failovers em grupos de failover não travem o cliente indefinidamente. Valores de 30 a 90 segundos funcionam bem para a maioria das cargas de trabalho em nuvem. Para detalhes sobre dimensionamento LoginTimeout contra ConnectRetryCount * ConnectRetryInterval e os modos de falha resultantes, veja Tempo de espera da conexão. Para a referência de opções, veja Opções de conexão.
Rotear cargas de trabalho somente leitura para uma réplica
Para consultas somente leitura em um banco de dados em um grupo de disponibilidade Always On, Instância Gerenciada de SQL do Azure, ou Banco de Dados SQL do Azure com escala de leitura ou geo-réplica, adicione ApplicationIntent=ReadOnly à sua cadeia de conexão:
<?php
$dsn = "sqlsrv:Server=<listener>;Database=<database>;" .
"Encrypt=true;ApplicationIntent=ReadOnly";
O roteamento somente leitura envia a conexão para uma réplica secundária sincronizada, descarregando o trabalho do primário. Combine com MultiSubnetFailover=true para a conexão mais rápida com ouvintes de grupos de disponibilidade multi-sub-rede.
Observe o desempenho do servidor
O tempo do lado do cliente só indica quanto tempo uma consulta levou de ponta a ponta. Para descobrir por que estava lento, use os diagnósticos integrados do SQL Server.
Repositório de Consultas
A Repositório de Consultas captura planos de execução, estatísticas de execução e estatísticas de espera para cada consulta no banco de dados. Ele está ativado por padrão no Banco de Dados SQL do Azure, Instância Gerenciada de SQL do Azure e SQL Database no Fabric. No SQL Server, ative-o por banco de dados:
ALTER DATABASE <database_name> SET QUERY_STORE = ON;
Depois, use os relatórios Repositório de Consultas do SQL Server Management Studio para encontrar suas consultas mais lentas e frequentemente executadas. Veja Monitorar desempenho com a Repositório de Consultas.
SQL do Azure Query Performance Insight
Para o Banco de Dados SQL do Azure, o Query Performance Insight do portal Azure mostra automaticamente as consultas que mais consomem recursos sem qualquer configuração. Para obter mais informações, confira Análise de Desempenho de Consultas para o Banco de Dados SQL do Azure.
SET STATISTICS para investigação única
Para uma única consulta que você deseja perfilar, execute-a no SQL Server Management Studio com estatísticas ativadas:
SET STATISTICS TIME ON;
SET STATISTICS IO ON;
-- your query here
Leituras lógicas altas quase sempre significam um índice ausente ou inutilizável. Alto tempo de CPU com leituras lógicas baixas geralmente significa um plano ruim (sniffing de parâmetros, uma conversão implícita que impede o uso do índice ou uma função escalar que impede o paralelismo).
Eventos Estendidos para rastreamento em nível de motorista
Para ver exatamente o que o driver envia para o SQL Server (incluindo os valores reais dos parâmetros que ele interpola), capture uma sessão de Eventos Estendidos usando os rpc_completed eventos andsql_batch_completed.
Lista de verificação de desempenho
Use esta lista de verificação como uma revisão pré-implantação de qualquer aplicativo PHP que se conecte ao SQL Server:
| Area | Verificação | Reference |
|---|---|---|
| Connection | O pooling de conexões é habilitado e configurado para a plataforma | Gerencie conexões de forma eficiente |
| Connection | O aplicativo reutiliza conexões dentro de uma requisição e não abre conexões por consulta | Reutilize a conexão dentro de uma solicitação |
| Connection |
LoginTimeoutcobre cold starts e failover para SQL do Azure |
Tempo de encerramento do login |
| Consulta | Consultas selecionam apenas as colunas necessárias, não SELECT * |
Selecione apenas as colunas que você usa |
| Consulta | Filtragem acontece em SQL, não em PHP com array_filter |
Busque apenas as fileiras que você precisa |
| Consulta | Grandes conjuntos de resultados são paginados com OFFSET ... FETCH |
Paginar grandes conjuntos de resultados |
| Consulta | Conjunto de procedimentos armazenados SET NOCOUNT ON |
Prefiro SET NOCOUNT ON |
| Inserções | Inserções em massa usam parâmetros de valor de tabela, não loops por linha | Inserir dados de forma eficiente |
| Statements |
PDO::ATTR_EMULATE_PREPARES é definido como false. |
Prefira preparações nativas |
| Statements | A aplicação reutiliza instruções preparadas entre execuções | Reutilizar declarações preparadas |
| Cursors | O aplicativo usa o cursor padrão apenas para frente, a menos que seja necessário buffering | Gerencie cursores e memória |
| Memory | Grandes valores binários e de caracteres são transmitidos em stream, não materializados | Fluxar valores binários grandes e de caracteres |
| Tempo de espera | O timeout da instrução é definido em todas as consultas voltadas para o usuário | Tempo limite da extração |
| Routing | Cargas de trabalho somente leitura definidas ApplicationIntent=ReadOnly onde existe uma réplica |
Cargas de trabalho somente leitura de rotas |
| Observability | A Repositório de Consultas é ativada e revisada regularmente | Repositório de Consultas |