Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Este artículo explica cómo escribir código PHP rápido contra SQL Server, Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics y base de datos SQL en Microsoft Fabric. La guía se aplica tanto a SQLSRV como a PDO_SQLSRV, que envuelve el mismo controlador Microsoft ODBC subyacente para SQL Server.
Empieza con los cambios de mayor impacto
Si solo puedes hacer tres cambios, haz estos cambios:
- Activa la agrupación de conexiones. Establecer una nueva conexión TLS a SQL Server lleva decenas a cientos de milisegundos, dependiendo de la ruta de red y la negociación TLS. Reutilizar conexiones agrupadas elimina ese coste por solicitud. Consulta Gestionar conexiones de forma eficiente.
- Busca solo las columnas y filas que necesites.
SELECT *y las consultas no acotadas son las causas más comunes de los puntos finales lentos. Consulta solo lo que necesites. - Utiliza parámetros de tabla para insertos a granel. Para cientos de filas o más, los parámetros de valores de tabla (TVP) suelen ser mucho más rápidos que las sentencias
INSERTfila por fila y escalan linealmente con el recuento de filas. Consulta Insertar datos de manera eficiente.
Gestionar las conexiones de forma eficiente
El establecimiento de conexión es la operación más costosa que realiza el conductor. Casi todas las investigaciones de rendimiento de PHP terminan con una solución de gestión de conexión.
Habilitación de la agrupación de conexiones
El pooling reutiliza conexiones ODBC entre las solicitudes PHP en lugar de desmontarlas al final de la petición. El objeto de conexión se descarta cuando termina tu script, pero el handle ODBC subyacente permanece activo en el pool del gestor de controladores ODBC y se reutiliza en la siguiente petición que pide la misma cadena de conexión.
Windows: El pooling de conexiones está activado por defecto. Para confirmarlo, deja la ConnectionPooling opción fuera de tu DSN. Para desactivar el pooling para depuración, configura ConnectionPooling=0.
Linux y macOS: El pooling de conexiones no es una opción DSN en estas plataformas. Actívalo en el gestor de drivers configurando Pooling=Yes la [ODBC] sección de odbcinst.ini, y pon un positivo CPTimeout bajo la estrofa del driver. Por ejemplo:
[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
Encuentra el camino real de la biblioteca con odbcinst -q -d -n "ODBC Driver 18 for SQL Server" o ls /opt/microsoft/msodbcsql18/lib64/. El nombre del archivo incorpora la versión instalada del controlador ODBC y cambia con cada versión.
CPTimeout (en segundos) controla cuánto tiempo permanecen las conexiones en reposo en la piscina antes de cerrarse. Ponlo lo suficientemente alto para que la mayoría de las solicitudes encuentren una conexión agrupada, pero lo suficientemente bajo para que las conexiones obsoletas a un servidor fallado se retiren razonablemente rápido. De 60 a 300 segundos funciona bien para la mayoría de las cargas de trabajo web.
Para más detalles, véase Agrupación de conexiones.
Entiende el coste de la primera consulta
Conjuntos de resultados activos múltiples (MARS) está habilitado de forma predeterminada. Cuando MARS y el pooling de conexiones están activos, el controlador reinicia la conexión agrupada en la primera consulta, y ese reinicio ignora cualquier tiempo de espera que hayas configurado para esa primera consulta. Las consultas posteriores en la misma conexión normalmente respetan el tiempo de espera. Si configuras tiempos de espera agresivos en la primera consulta en una carga de trabajo agrupada, ten en cuenta este comportamiento o desactiva MARS si MultipleActiveResultSets=false no lo necesitas. Consulta la nota MARS y pooling en Connection pooling.
No se soportan conexiones PDO persistentes
PDO_SQLSRV rechaza PDO::ATTR_PERSISTENT. Configurándolo en los lanzamientos constructores:
SQLSTATE[IMSSP]: An unsupported attribute was designated on the PDO object.
Utiliza pooling de conexiones ODBC para la reutilización entre peticiones. Es el mecanismo nativo del controlador, funciona tanto para PDO_SQLSRV como para SQLSRV, y elimina las conexiones inactivas activadas CPTimeout (lo que también mantiene Microsoft Entra actualización de tokens honesta).
Reutilizar la conexión dentro de una solicitud
Incluso con pooling, abrir una nueva conexión PDO o SQLSRV implica un viaje de ida y vuelta ODBC para obtener y validar un handle pooled. Abre una conexión una vez por petición y pásala a todas las funciones que la necesiten.
Tip
Un contenedor de inyección de dependencia o un accesorio perezoso es suficiente. La idea es evitar new PDO(...) estar en medio de un gestor de peticiones.
Consulta solo lo que necesites
Los viajes de ida y vuelta de red y la materialización de conjuntos de resultados dominan la latencia de consulta para la mayoría de las cargas de trabajo PHP. Las correcciones son las mismas que se aplican a todas las capas de acceso a bases de datos.
Selecciona solo las columnas que utilices
SELECT * Extrae todas las columnas, incluyendo varchar(max) y varbinary(max) columnas que superan con creces los datos que realmente consumes. Nombra las columnas:
<?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");
Consigue solo las filas que necesites
Push filtering a SQL Server. Nunca recuperes una tabla completa en PHP solo para filtrar en un foreach bucle.
<?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 una vista de lista que muestre unos cientos de filas de millones, no devuelvas todas las filas y deja que el cliente lo ordene. Utiliza la paginación del servidor con 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);
}
Elige el método adecuado de buscar
- Úsalo
fetch(PDO::FETCH_ASSOC)en bucle para iteraciones en streaming cuando no necesites todas las filas en memoria a la vez. - Úsalo
fetchAll(PDO::FETCH_ASSOC)cuando el llamador realmente necesita todo el conjunto (por ejemplo, generando una respuesta JSON completa). - Úsalo
fetchColumn()cuando solo te importa un único escalar (unCOUNT,SUM, oMAX). - Usa
PDO::FETCH_KEY_PAIRoPDO::FETCH_UNIQUEpara construir diccionarios de búsqueda sin necesidad de una segunda pasada.
Los modos numéricos de obtención (PDO::FETCH_NUM) son ligeramente más rápidos que los modos asociativos porque saltan la construcción del mapa de nombres de columna. Prefiero claridad; Solo cambia cuando un perfilador marque la sobrecarga de obtención como significativa.
Preferir SET NOCOUNT ON en procedimientos almacenados y lotes
Cada INSERTinstrucción , UPDATE, y DELETE devuelve un DONE_IN_PROC token con el recuento de filas afectado, que PHP normalmente descarta. El token no añade un viaje de ida y vuelta, pero cada uno sigue costando bytes en el cable y una pequeña cantidad de trabajo de driver. En un procedimiento o lote de varias declaraciones que ejecuta cientos de estados por llamada, el ahorro se acumula. Apágalo:
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;
Insertar datos de forma eficiente
Elige el método de inserción adecuado según cuántas filas vayas a mover. La elección equivocada puede ser 100 veces más lenta.
Menos de unas 100 filas: declaración preparada en un bucle
Para lotes pequeños, ejecuta una única sentencia preparada en un bucle:
<?php
$stmt = $conn->prepare("INSERT INTO dbo.Products (Name, Price) VALUES (?, ?)");
foreach ($products as $p) {
$stmt->execute([$p["name"], $p["price"]]);
}
Envuelven el bucle en una transacción para que todas las inserciones se comprometan como una sola unidad y el log no tenga que vaciar tras cada fila:
<?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;
}
Cientos a millones de filas: parámetros con valores de tabla
Los parámetros de valor en tabla (TVP) envían todo el lote a SQL Server en un solo viaje de ida y vuelta y permiten que SQL Server procese el conjunto como una sola sentencia. Para lotes de cientos de filas o más, los TVP suelen ser mucho más rápidos que un bucle de enunciado preparado y escalan linealmente con el número de filas.
Primero, crea un tipo de tabla en el servidor:
CREATE TYPE dbo.ProductTableType AS TABLE (
Name NVARCHAR(100),
Price DECIMAL(10, 2)
);
PDO_SQLSRV pasa el TVP como un array asociativo cuya clave es el nombre del tipo y cuyo valor es el conjunto de filas. Enáclala con: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 un esquema no predeterminado, pasa el esquema como el siguiente elemento del array: ["ProductTableType" => $rows, "Sales"]. Para ejemplos de sintaxis procedural SQLSRV y procedimientos almacenados, véase Usar parámetros con valores de tabla.
Millones de filas: bcp o BULK INSERT
Para operaciones realmente masivas (cargas de almacenes de datos, migraciones iniciales), usa bcp o BULK INSERT en lugar de PHP. Escribe tus datos en un archivo delimitado o de formato nativo, luego ejecuta bcp o BULK INSERT desde un trabajo programado, un paso ETL o un script de administración.
Caution
Si pagas a BCP desde PHP con shell_exec() o proc_open(), nunca interpoles entradas no confiables en la línea de comandos. Úsalo escapeshellarg() en todos los argumentos, y prefiero ejecutar la carga fuera de banda en lugar de en una ruta de petición web.
Reducir los viajes de ida y vuelta
Cada ida y vuelta de red entre PHP y SQL Server tiene un coste fijo. Cuando envías cinco extractos en un solo lote, pagas ese coste una vez en vez de cinco.
Combina sentencias relacionadas en un solo lote
Para trabajos relacionados que se ejecutan juntos, junta las sentencias en un solo lote y consume cada conjunto 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, usa sqlsrv_next_result para avanzar entre conjuntos de resultados.
Activa múltiples conjuntos de resultados activos cuando lo necesites
Múltiples Conjuntos de Resultados Activos (MARS) permite que una sola conexión tenga múltiples sentencias activas. Sin MARS, no puedes emitir una consulta nueva en una conexión que aún tenga un conjunto de resultados abierto. Ambos controladores activan MARS por defecto. Para desactivarlo, pon MultipleActiveResultSets=false tu cadena de conexión. Véase Desactivar conjuntos de resultados activos múltiples (MARS).
MARS es conveniente pero no gratis. Cada conjunto de resultados activo consume recursos del lado del servidor. Prefiero consumir un conjunto de resultados completo antes de empezar otro. Usa MARS para desbloquear patrones de cursor realmente anidados.
Sintonizar declaraciones preparadas
Las sentencias preparadas evitan que el controlador tenga que volver a analizar SQL en el servidor y te permiten vincular de forma segura entradas no confiables como parámetros.
Prefiero preparados nativos
PDO_SQLSRV puede preparar sentencias en dos modos.
Los preparativos nativos envían el texto SQL al servidor una vez y reutilizan la sentencia analizada para cada ejecución, enviando solo los valores de los parámetros en cada execute()archivo .
Las preparaciones emuladas mantienen el texto SQL en el cliente y reconstruyen una cadena SQL completa con parámetros interpolados en cada ejecución.
Configura PDO::ATTR_EMULATE_PREPARES => false para que el controlador use preparaciones nativas. Los sistemas nativos permiten que SQL Server almacene en caché y reutilice el plan de consulta, y evitan volver a analizar el texto SQL en cada ejecución.
<?php
$conn = new PDO($dsn, null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
Reutilizar declaraciones preparadas
Prepárate una vez, ejecuta muchos. Cada prepare() llamada cuesta una asignación de handle ODBC y un análisis del lado del servidor. En un bucle caliente, mantén el $stmt objeto vivo y llama execute() dentro del bucle:
<?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 con TOP (?) y IN (?, ?, ...)
TOPrequiere paréntesis alrededor de un marcador de parámetro, SELECT TOP (?) ..., para que SQL Server pueda analizar el conteo de filas como un parámetro.
IN (?, ?, ?, ?) Requiere un recuento fijo de marcador en el momento de preparar. Para tamaños dinámicos IN de lista, se puede construir la cadena provisional a partir de un recuento entero validado, o pasar la lista como un parámetro con valor en tabla.
Caution
Nunca interpoles la entrada bruta del usuario en el texto SQL (incluyendo el conteo de marcadores). Lanza el conteo con (int) antes de construir la cadena de marcador y siempre pasa los valores execute() reales como parámetros.
Gestionar los cursores y la memoria
El tipo de cursor por defecto es PDO::CURSOR_FWDONLY, una manguera de incendios solo hacia adelante. Transmite filas a PHP una a una y no almacena en búfer, por lo que un gran conjunto de resultados está limitado por la memoria de filas en lugar del recuento total de filas. Eso es normalmente lo que quieres.
Usa cursores con búfer solo cuando necesites retroceder o contar filas
PDO::SQLSRV_CURSOR_BUFFERED (un cursor estático con búfer en el lado del cliente) recupera todo el conjunto de resultados en memoria PHP de entrada. Este enfoque te permite llamar rowCount(), buscar hacia atrás y reutilizar la afirmación. Por defecto, el búfer está limitado a 10.240 KB (10 MB) mediante PDO::SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE, y una consulta cuyo conjunto de resultados supera los retornos false del límite en lugar de saturar memoria PHP. Puedes elevar el límite hacia el límite de memoria de PHP, pero hacerlo intercambia un false retorno por un error fatal real Allowed memory size exhausted cuando una consulta supera el nuevo límite. Afina deliberadamente.
Véase Tipos de cursor (PDO_SQLSRV).
Los cursores desplazables del lado del servidor (PDO::SQLSRV_CURSOR_STATIC, PDO::SQLSRV_CURSOR_DYNAMIC, PDO::SQLSRV_CURSOR_KEYSET) almacenan en búfer el servidor en lugar del cliente, para que no consuman memoria PHP. Sin embargo, almacenan recursos del lado del servidor durante toda la duración del cursor y son más lentos por fila que los que solo se redirigen.
Usa el modo predeterminado de solo reenvío para lecturas en streaming. Usa el lado del cliente con búfer para conjuntos de resultados pequeños cuando lo necesites rowCount() o desplazamiento hacia atrás. Evita los cursores desplazables del lado del servidor a menos que estés haciendo 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 un desglose completo, véase Tipos de cursor (PDO_SQLSRV) y Tipos de cursor (SQLSRV).
Fluir valores binarios grandes y de caracteres
Para varbinary(max), varchar(max),nvarchar(max), xml y otros tipos grandes, usa flujos PHP en lugar de materializar el valor completo en memoria:
<?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 insertar o actualizar con valores grandes, úsase SendStreamParamsAtExec=false en SQLSRV para enviar datos de flujo en bloques después sqlsrv_execute()de . Para más detalles, véase Enviar datos como un flujo.
Establecimiento de tiempos de espera adecuados
Los tiempos de espera son tanto ajustes de rendimiento como de fiabilidad. Las consultas largas mantienen conexiones en la piscina y privan otras solicitudes.
Tiempo de espera de la instrucción
Establece un límite de tiempo por sentencia para que una consulta descontrolada no retenga una conexión al 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, pasa "QueryTimeout" => 30 el array de opciones a sqlsrv_query o sqlsrv_prepare.
Establece un valor que coincida con tu carga de trabajo. Para una solicitud web síncrona, entre 15 y 30 segundos es lo habitual. Para un trabajo en lote de antecedentes, varios minutos pueden ser razonables. Nunca pongas el tiempo de espera a cero (ilimitado) en una solicitud web.
Tiempo de espera de inicio de sesión
LoginTimeouten la cadena de conexión se controla cuánto tiempo espera el controlador para establecer una conexión. Establece un valor explícito al conectarte a Azure SQL Database o Azure SQL Managed Instance para que los arranques en frío y los failovers en grupos de conmutación no bloqueen al cliente indefinidamente. Valores de 30 a 90 segundos funcionan bien para la mayoría de cargas de trabajo en la nube. Para detalles sobre el tamaño LoginTimeout y ConnectRetryCount * ConnectRetryInterval los modos de fallo resultantes, véase Tiempo de espera de conexión. Para la referencia de opciones, consulta Opciones de conexión.
Enrutar cargas de solo lectura a una réplica
Para consultas de solo lectura contra una base de datos en un grupo de disponibilidad Always On, Azure SQL Managed Instance o Azure SQL Database con escala de lectura o geo-réplica, añade ApplicationIntent=ReadOnly a tu cadena de conexión:
<?php
$dsn = "sqlsrv:Server=<listener>;Database=<database>;" .
"Encrypt=true;ApplicationIntent=ReadOnly";
El enrutamiento de solo lectura envía la conexión a una réplica secundaria sincronizada, descargando el trabajo desde el primario. Combina con MultiSubnetFailover=true para obtener la conexión más rápida a los oyentes de grupos de disponibilidad multi-subred.
Observar el rendimiento del servidor
El tiempo del cliente solo te indica cuánto tiempo duró una consulta de principio a fin. Para saber por qué era lento, utiliza los diagnósticos integrados de SQL Server.
Almacén de consultas (Almacén de Consultas)
Almacén de consultas captura planes de ejecución, estadísticas de ejecución y estadísticas de espera para cada consulta en la base de datos. Está activado por defecto en Azure SQL Database, Azure SQL Managed Instance y SQL Database en Fabric. En SQL Server, habilita la función por base de datos:
ALTER DATABASE <database_name> SET QUERY_STORE = ON;
Luego utiliza los informes Almacén de consultas de SQL Server Management Studio para encontrar tus consultas más lentas y con más frecuencia. Consulta Monitorización del rendimiento con la Almacén de consultas.
Azure SQL Query Performance Insight
Para Azure SQL Database, el Query Performance Insight del portal Azure muestra automáticamente las consultas que más recursos consumen sin ninguna configuración. Para más información, consulte Información de rendimiento de consultas para Azure SQL Database.
SET STATISTICS para una investigación puntual
Para una sola consulta que quieras perfilar, ejecutala en SQL Server Management Studio con las estadísticas activadas:
SET STATISTICS TIME ON;
SET STATISTICS IO ON;
-- your query here
Lecturas lógicas altas casi siempre significan un índice ausente o inutilizable. Un tiempo de CPU alto con lecturas lógicas bajas suele significar un mal plan (detección de parámetros, una conversión implícita que impide el uso del índice, o una función escalar que impide el paralelismo).
Eventos extendidos para el trazado a nivel de conductor
Para ver exactamente qué envía el controlador a SQL Server (incluyendo los valores reales de los parámetros que interpola), captura una sesión de Eventos Extendidos usando los rpc_completed eventos y sql_batch_completed .
Lista de comprobación de rendimiento
Utiliza esta lista de comprobación como revisión previa al despliegue de cualquier aplicación PHP que se conecte a SQL Server:
| Área | Check | Reference |
|---|---|---|
| Connection | El pooling de conexiones está habilitado y configurado para la plataforma | Gestionar las conexiones de forma eficiente |
| Connection | La aplicación reutiliza conexiones dentro de una solicitud y no abre conexiones por consulta | Reutilizar la conexión dentro de una solicitud |
| Connection |
LoginTimeoutcubre arranques en frío y conmutación por error para Azure SQL |
Tiempo de espera para iniciar sesión |
| Query | Las consultas seleccionan solo las columnas necesarias, no SELECT * |
Selecciona solo las columnas que utilices |
| Query | El filtrado ocurre en SQL, no en PHP con array_filter |
Consigue solo las filas que necesites |
| Query | Los grandes conjuntos de resultados se paginan con OFFSET ... FETCH |
Paginar conjuntos de resultados grandes |
| Query | Conjunto de procedimientos almacenados SET NOCOUNT ON |
Prefiere SET NOCOUNT ON |
| Inserciones | Los insertos a granel utilizan parámetros con valores de tabla, no bucles por fila | Insertar datos de forma eficiente |
| Statements |
PDO::ATTR_EMULATE_PREPARES se establece en false. |
Prefiero preparados nativos |
| Statements | La aplicación reutiliza sentencias preparadas a través de las ejecuciones | Reutilizar declaraciones preparadas |
| Cursors | La aplicación utiliza el cursor predeterminado solo hacia adelante a menos que sea necesario hacer búfer | Gestionar los cursores y la memoria |
| Memory | Los valores binarios grandes y de caracteres se transmiten, no se materializan | Fluir valores binarios grandes y de caracteres |
| Tiempos de expiración | El tiempo de espera de las sentencias se establece en todas las consultas orientadas al usuario | Tiempo de espera de la instrucción |
| Routing | Cargas de solo lectura establecidas ApplicationIntent=ReadOnly donde existe una réplica |
Cargas de trabajo de solo lectura de rutas |
| Observability | Almacén de consultas está habilitada y revisada regularmente | Almacén de consultas |