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 sin límites son las causas más comunes de la lentitud de los puntos de conexión. Consulta Consulta solo lo que necesites. - Utiliza parámetros con valores de tabla para inserciones masivas. 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 agrupamiento en el pool con fines de depuración, configura ConnectionPooling=0.
Linux y macOS: El pooling de conexiones no es una opción DSN en estas plataformas. Actívelo en el administrador de controladores configurando Pooling=Yes en la sección [ODBC] de odbcinst.ini, y establezca un valor positivo para CPTimeout en la estrofa del controlador. 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 inactivas en el grupo 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 de la primera consulta en una carga de trabajo agrupada en un pool, ten en cuenta este comportamiento, o desactiva MARS con MultipleActiveResultSets=false si no lo necesitas. Consulte la nota sobre MARS y el agrupamiento en Agrupamiento de conexiones.
No se soportan conexiones PDO persistentes
PDO_SQLSRV rechaza PDO::ATTR_PERSISTENT. Si se configura en el compilador, se produce un error:
SQLSTATE[IMSSP]: An unsupported attribute was designated on the PDO object.
Utiliza la agrupación de conexiones ODBC para reutilizar conexiones entre peticiones. Es el mecanismo nativo del controlador, funciona tanto para PDO_SQLSRV como para SQLSRV, y retira las conexiones inactivas en CPTimeout (lo que también garantiza la actualización correcta del token de Microsoft Entra).
Reutilice la conexión dentro de una petición
Incluso con el agrupamiento, abrir una nueva conexión PDO o SQLSRV implica un viaje de ida y vuelta por ODBC para recuperar y validar un identificador del grupo. Abre una conexión una vez por petición y pásala a todas las funciones que la necesiten.
Tip
Basta con un contenedor de inyección de dependencias o un descriptor de acceso diferido. La idea es evitar new PDO(...) en medio de un controlador de solicitudes.
Consulta solo lo que necesites
Las idas y vueltas de red y la materialización de los conjuntos de resultados dominan la latencia de las consultas en la mayoría de las cargas de trabajo con 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, incluidas las de tipo varchar(max) y varbinary(max), que eclipsan 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");
Recupera solo las filas que necesites.
Traslada el filtrado 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 muestra unos cientos de filas de entre millones, no devuelvas todas las filas y dejes que el cliente se encargue de ordenarlas. Utiliza la paginación del lado 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
- Utiliza
fetch(PDO::FETCH_ASSOC)en un bucle para la iteración 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. Prioriza la claridad; solo cambia cuando un perfilador indique que la sobrecarga de fetch es significativa.
Preferir SET NOCOUNT ON en procedimientos almacenados y lotes
Cada instrucción INSERT, UPDATE y DELETE devuelve un token DONE_IN_PROC con el número de filas afectadas, que PHP normalmente descarta. El token no añade un viaje de ida y vuelta, pero cada uno sigue costando bytes en la red y una pequeña cantidad de trabajo del controlador. En un procedimiento o lote con varias instrucciones que ejecuta cientos de instrucciones 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: instrucció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"]]);
}
Envuelve el bucle en una transacción para que todas las inserciones se confirmen como una sola unidad y el registro no tenga que vaciarse después de 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. Vincúlalo 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 invocas `bcp` desde PHP con shell_exec() o proc_open(), no interpoles nunca datos 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 tareas relacionadas que se ejecutan juntas, agrupa las instrucciones en un solo lote y procesa todos los 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, 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, establece MultipleActiveResultSets=false en la 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. Es preferible procesar un conjunto de resultados por completo antes de comenzar con otro. Utiliza MARS para desbloquear patrones de cursor verdaderamente anidados.
Optimizar las instrucciones 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.
Da prioridad a las preparaciones nativas
PDO_SQLSRV puede preparar sentencias en dos modos.
Las sentencias preparadas nativas envían el texto SQL al servidor una sola vez y reutilizan la instrucción analizada en cada ejecución, enviando solo los valores de los parámetros en cada execute()
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
Prepara una vez, ejecuta muchas veces. Cada llamada a prepare() cuesta una asignación de un controlador ODBC y un análisis sintáctico en el servidor. En un bucle crítico, mantén activo el objeto $stmt y llama a 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 marcadores de posición en el momento de la preparación. Para tamaños dinámicos de la lista IN, construye la cadena de marcadores de posición a partir de un recuento entero validado o pasa la lista como un parámetro con valor de tabla.
Caution
Nunca interpoles entradas sin procesar del usuario en el texto SQL (incluido el recuento de marcadores de posición). Convierte el recuento con (int) antes de construir la cadena de marcadores de posición, y pasa siempre los valores reales a través de execute() como parámetros.
Gestionar los cursores y la memoria
El tipo de cursor predeterminado es PDO::CURSOR_FWDONLY, un firehose de avance único. Envía las filas a PHP de una en una y no hace almacenamiento en búfer, por lo que un conjunto de resultados grande queda limitado por la memoria del búfer de fila en lugar de por el número 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) carga todo el conjunto de resultados en la memoria de PHP por adelantado. Este enfoque te permite invocar rowCount(), retroceder y reutilizar la instrucció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 el límite máximo devuelve false en lugar de agotar la memoria de PHP. Puedes elevar el límite hasta acercarlo al límite de memoria de PHP, pero al hacerlo sustituyes un false return por un Allowed memory size exhausted error fatal real si una consulta rebasa el nuevo límite. Optimízalo 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 los datos en búfer en el servidor en lugar de hacerlo en el cliente, por lo que no consumen memoria de PHP. Sin embargo, retienen recursos del lado del servidor mientras dura el cursor y son más lentos por fila que los de avance único.
Usa el modo predeterminado de solo reenvío para lecturas en streaming. Utiliza el modo con búfer del lado del cliente para conjuntos de resultados pequeños cuando 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).
Transmitir valores binarios y de caracteres de gran tamaño
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, utiliza SendStreamParamsAtExec=false en SQLSRV para enviar datos de flujo en bloques después de sqlsrv_execute(). 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 que tardan mucho en completarse retienen las conexiones del grupo y agotan los recursos de otras solicitudes.
Tiempo de espera de la instrucción
Establece un límite de tiempo por instrucción para que una consulta descontrolada no retenga una conexión del grupo 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 en 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 una tarea por lotes en segundo plano, varios minutos pueden ser un tiempo razonable. 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 a Azure SQL Managed Instance para que los arranques en frío y las conmutaciones por error de los grupos de disponibilidad no bloqueen el cliente indefinidamente. Valores de 30 a 90 segundos funcionan bien para la mayoría de cargas de trabajo en la nube. Para obtener más información sobre el dimensionamiento de LoginTimeout con respecto a ConnectRetryCount * ConnectRetryInterval y los modos de fallo resultantes, véase Tiempo de espera de la conexión. Para la referencia de opciones, consulta Opciones de conexión.
Dirige las cargas de trabajo de solo lectura a una réplica
Para consultas de solo lectura en una base de datos de un grupo de disponibilidad Always On, Azure SQL Managed Instance o Azure SQL Database con escalabilidad horizontal de lectura o réplica geográfica, 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, quitando carga a la réplica principal. Combínelo con MultiSubnetFailover=true para obtener la conexión más rápida a los oyentes de grupos de disponibilidad con varias subredes.
Observar el rendimiento del servidor
La temporización del lado del cliente solo indica cuánto tardó 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.
Información sobre el rendimiento de las consultas de Azure SQL
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
Un número elevado de lecturas lógicas casi siempre significa que falta un índice o que este es 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 seguimiento a nivel de controlador
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 |
LoginTimeout cubre los arranques en frío y la 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 |
Recupere solo las filas que necesite |
| 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 | Las inserciones masivas utilizan parámetros de tipo tabla, no bucles por cada fila | Insertar datos de forma eficiente |
| Statements |
PDO::ATTR_EMULATE_PREPARES se establece en false |
Dé preferencia a las preparaciones nativas |
| Statements | La aplicación reutiliza sentencias preparadas en distintas ejecuciones | Reutilizar declaraciones preparadas |
| Cursors | La aplicación utiliza el cursor predeterminado de avance único, a menos que sea necesario el almacenamiento en búfer | Gestionar los cursores y la memoria |
| Memory | Los valores binarios y de caracteres de gran tamaño se procesan en flujo, no se materializan | Transmitir valores binarios y de caracteres de gran tamaño |
| Tiempos de expiración | El tiempo de espera de la instrucción se establece en todas las consultas dirigidas al usuario | Tiempo de espera de la instrucción |
| Routing | Las cargas de trabajo de solo lectura establecen ApplicationIntent=ReadOnly cuando existe una réplica |
Dirigir cargas de trabajo de solo lectura |
| Observability | Almacén de consultas está habilitada y revisada regularmente | Almacén de consultas |
Contenido relacionado
- Agrupación de conexiones (Microsoft Drivers for PHP for SQL Server)
- Opciones de conexión
- Tipos de cursor (controlador PDO_SQLSRV)
- Tipos de cursor (controlador SQLSRV)
- Utiliza parámetros con valores de tabla (PHP)
- Solucionar problemas de los controladores de Microsoft para PHP para SQL Server
- Supervise el rendimiento utilizando el Almacén de Consultas