Exportar grandes resultados SQL sin agotar al cliente
Limita memoria, diagnostica ASYNC_NETWORK_IO y separa extracción SQL y descargas lentas con un contrato claro de consistencia y finalización.
Una consulta con millones de filas no termina para el usuario cuando SQL Server encuentra la primera. Todavía hay que transferir, decodificar, formatear, escribir y entregar los datos. Un plan rápido puede coexistir con una exportación lenta y una aplicación sin memoria.
Medir todo el recorrido
Registra tiempo hasta primera fila, fin de lectura, fin de escritura, filas, bytes y memoria máxima. Así separas cálculo del servidor, transferencia y formato. Cronometrar solo el primer Read no mide la exportación completa.
Durante una ejecución lenta, esta consulta de lectura observa las solicitudes activas con los permisos de diagnóstico adecuados.
SELECT
r.session_id, r.request_id,
r.status, r.wait_type, r.wait_time,
r.total_elapsed_time, r.cpu_time,
r.logical_reads, r.reads, r.row_count,
s.program_name, s.host_name
FROM sys.dm_exec_requests AS r
JOIN sys.dm_exec_sessions AS s ON s.session_id = r.session_id
WHERE s.is_user_process = 1
AND r.session_id <> @@SPID
ORDER BY r.total_elapsed_time DESC;
ASYNC_NETWORK_IO repetido indica espera relacionada con consumo de resultados o progreso de red. No identifica automáticamente una red defectuosa. Un cliente que comprime, registra o realiza una llamada HTTP por fila puede consumir despacio. Compara CPU cliente, rendimiento de escritura y evidencia de red.
Reduce datos innecesarios en origen. Selecciona columnas requeridas y lleva filtros o agregaciones válidas a SQL. Exportar una descripción enorme para descartarla después desperdicia transferencia y decodificación. Conserva la semántica: sustituir detalle por totales no es la misma exportación.
Limitar memoria sin ocultar al consumidor lento
Un lector hacia delante evita construir una colección con todo el resultado. Para columnas grandes binarias o de texto, SequentialAccess y las API de streams de SqlClient permiten consumo incremental. Respeta el orden de columnas y termina un valor transmitido antes de avanzar según ese patrón de acceso.
La E/S asíncrona no limita memoria por sí sola. Una tarea por fila, conservando todas las tareas o filas, puede crecer con el conjunto. Usa un canal acotado o lotes limitados entre extracción y transformación, con un número fijo de trabajadores.
Cuando la salida se ralentiza, el buffer debe dejar de crecer. Esa contrapresión mantiene abiertos lector y conexión. Según consulta y aislamiento, una ejecución larga puede prolongar bloqueos, retener versiones u ocupar una concesión de memoria. Cargar todo primero libera antes el lector, pero traslada la presión al cliente.
Para descargas lentas, un trabajo de fondo puede escribir un archivo temporal en almacenamiento controlado y cerrar el lector antes de entregarlo. Publica el archivo final solo tras éxito, con filas, tamaño y preferiblemente checksum. Un archivo interrumpido no debe parecer completo.
Definir consistencia y finalización
Decide qué momento representan los datos. Varios fragmentos independientes bajo read committed no forman automáticamente una instantánea coherente. Las filas pueden cambiar entre fragmentos. Una transacción snapshot larga ofrece otro contrato, pero puede retener versiones. Documenta la decisión y mide su coste.
Usa orden estable si el archivo debe ser determinista o reanudable. ORDER BY puede añadir trabajo y debe incluirse en las pruebas. Un límite superior de clave no demuestra que los valores permanezcan iguales durante la extracción.
Propaga cancelación y libera lector, comando y conexión propia en todos los caminos. Termina explícitamente la transacción del trabajo. Prueba desconexión a mitad, disco lleno, fallo de conversión después de muchas filas y repetición de la misma solicitud.
Distingue finalmente trabajo completado de descarga exitosa. Puede existir un archivo válido aunque se pierda la conexión del usuario. Reutilizarlo suele ser más seguro y barato que volver a consultar la base. Una exportación fiable tiene recursos acotados y señal explícita de completitud, no simplemente un bucle que deja de recibir filas.
Referencias técnicas: Microsoft Learn: ASYNC_NETWORK_IO · Microsoft Learn: SqlClient streaming.