16/10/2016
En el mundo del desarrollo de software, el objetivo final es siempre producir aplicaciones eficientes, fáciles de mantener y, sobre todo, altamente escalables. Una aplicación escalable es aquella capaz de servir a un gran número de usuarios concurrentes sin degradar su rendimiento. Una de las tareas más comunes y críticas en este aspecto es la recuperación y manipulación de datos desde una base de datos. Si has trabajado con tecnologías como ASP clásico y ADO (ActiveX Data Objects), seguramente te has enfrentado al reto de optimizar estas operaciones. Hoy vamos a desglosar una de las herramientas más potentes y a menudo subutilizadas de ADO: el método GetRows del objeto RecordSet.

Probablemente estés familiarizado con la forma tradicional de recorrer un conjunto de registros, pero ¿es la más eficiente? La respuesta corta es no. Acompáñanos a explorar por qué el bucle clásico puede ser un cuello de botella y cómo GetRows no solo lo soluciona, sino que te da un control más preciso sobre los datos que extraes.
- El Método Tradicional: Un Bucle Ineficiente y Costoso
- La Solución Elegante: GetRows al Rescate
- Controlando el Flujo: Cómo Limitar las Filas Recuperadas
- Poniéndolo en Práctica: Código Optimizado
- Tabla Comparativa: Bucle `MoveNext` vs. Método `GetRows`
- Preguntas Frecuentes (FAQ)
- ¿Es `GetRows` siempre la mejor opción?
- ¿Qué sucede si el RecordSet está vacío y llamo a GetRows?
- ¿El orden de las columnas en el array es el mismo que en mi consulta SQL?
- Después de llamar a GetRows(100), ¿puedo volver a llamar a GetRows para obtener las siguientes 100 filas?
- Conclusión: Un Pequeño Cambio para una Gran Mejora
El Método Tradicional: Un Bucle Ineficiente y Costoso
Cuando necesitamos mostrar datos de una base de datos, es muy común encontrar un código similar al siguiente. Se establece una conexión, se ejecuta una consulta SQL y se recorre el objeto RecordSet resultante fila por fila para procesar o mostrar la información.
<% Set oConnection = Server.CreateObject("ADODB.Connection") oConnection.Open(sConnectionString) sSQL = "SELECT Nombre, Apellido, Telefono FROM tblClientes" Set oRecordSet = oConnection.Execute(sSQL) While Not oRecordSet.EOF Response.Write(oRecordSet("Apellido") & ", " & oRecordSet("Nombre") & " - " & oRecordSet("Telefono") & "<br>") oRecordSet.MoveNext Wend Set oRecordSet = Nothing oConnection.Close Set oConnection = Nothing %>A primera vista, este código parece lógico y funcional. Y lo es. Sin embargo, su principal problema radica en el rendimiento y el consumo de recursos. El bucle While Not oRecordSet.EOF es el culpable. Cada vez que se ejecuta oRecordSet.MoveNext y se accede a los campos de una fila, se está interactuando con el objeto RecordSet, que a su vez mantiene una conexión o comunicación con el servidor de la base de datos (aunque sea a través de una caché local).
Aunque ADO es inteligente y cachea un número de registros para no tener que ir a la base de datos en cada llamada a MoveNext, el proceso sigue siendo inherentemente secuencial y costoso. Imagina que tu consulta devuelve 10,000 filas. El bucle implica miles de pequeñas operaciones y mantiene la conexión a la base de datos abierta durante todo el proceso, consumiendo recursos valiosos tanto en el servidor web como en el servidor de base de datos. Esto, simplemente, no es escalable.
La Solución Elegante: GetRows al Rescate
Aquí es donde el método GetRows cambia las reglas del juego. En lugar de recorrer el RecordSet fila por fila, GetRows extrae todos los registros (o un subconjunto de ellos) en una única operación y los vuelca en un array bidimensional de VBScript. Esto es increíblemente eficiente.
La sintaxis básica es muy simple:
arrResultados = oRecordSet.GetRows()Con esta única línea, toda la información del RecordSet se transfiere a la memoria del servidor web dentro de la variable arrResultados. La gran ventaja es que, inmediatamente después de esta llamada, ya no necesitas el objeto RecordSet ni la conexión a la base de datos. Puedes cerrarlos de inmediato, liberando esos recursos críticos para que otros procesos los utilicen. La manipulación posterior de los datos se realiza sobre el array en memoria, lo cual es órdenes de magnitud más rápido.
Controlando el Flujo: Cómo Limitar las Filas Recuperadas
El verdadero poder y la respuesta a nuestra pregunta principal radican en la capacidad de GetRows para aceptar un parámetro opcional que especifica el número exacto de filas que se deben recuperar. Esto es fundamental para manejar grandes volúmenes de datos, implementar paginación o simplemente cuando solo necesitas los primeros 'N' resultados.
Para limitar el número de filas, simplemente pasa un número como argumento al método. Por ejemplo, si solo queremos obtener las primeras 100 filas del RecordSet:
' Obtenemos únicamente las primeras 100 filas arrResultados = oRecordSet.GetRows(100)Esta funcionalidad es extremadamente útil. Ya no necesitas recurrir a cláusulas como TOP en SQL o LIMIT en otros dialectos si tu lógica de aplicación requiere un número variable de filas. Puedes ejecutar una consulta más genérica y decidir en tu código cuántos registros procesar, dándote una flexibilidad enorme sin sacrificar el rendimiento.
Poniéndolo en Práctica: Código Optimizado
Veamos cómo se transforma nuestro script original al implementar el método GetRows. El cambio es sutil en cantidad de líneas, pero gigantesco en términos de eficiencia.
<% Set oConnection = Server.CreateObject("ADODB.Connection") oConnection.Open(sConnectionString) sSQL = "SELECT Nombre, Apellido, Telefono FROM tblClientes" Set oRecordSet = oConnection.Execute(sSQL) Dim arrResultados If Not oRecordSet.EOF Then ' Obtenemos todos los registros en una sola operación arrResultados = oRecordSet.GetRows() End If ' ¡Importante! Cerramos la conexión lo antes posible Set oRecordSet = Nothing oConnection.Close Set oConnection = Nothing ' Ahora trabajamos con el array en memoria, que es mucho más rápido If IsArray(arrResultados) Then ' Obtenemos el número total de filas recuperadas ' UBound(arr, 2) devuelve el índice de la última fila Dim iTotalFilas iTotalFilas = UBound(arrResultados, 2) ' Recorremos el array para mostrar los datos Dim i For i = 0 To iTotalFilas ' OJO: El array es [columna, fila] Response.Write(arrResultados(1, i) & ", " & arrResultados(0, i) & " - " & arrResultados(2, i) & "<br>") Next End If %>Nota un detalle crucial: el array devuelto por GetRows tiene sus dimensiones invertidas respecto a lo que uno podría esperar. La primera dimensión corresponde a las columnas y la segunda a las filas. Por lo tanto, para acceder a un dato, se utiliza arrResultados(indice_columna, indice_fila). El índice de las columnas corresponde al orden en tu sentencia SELECT (0 para Nombre, 1 para Apellido, etc.).
Tabla Comparativa: Bucle `MoveNext` vs. Método `GetRows`
Para dejar las diferencias aún más claras, aquí tienes una tabla comparativa:
| Característica | Bucle (While Not EOF) | Método GetRows |
|---|---|---|
| Rendimiento | Bajo, especialmente con muchos registros. Múltiples interacciones. | Muy alto. Una única operación para transferir todos los datos. |
| Uso de Conexión a BD | La conexión permanece abierta durante todo el bucle. | La conexión puede cerrarse inmediatamente después de la llamada a GetRows. |
| Uso de Memoria (Servidor Web) | Bajo, ya que procesa los datos de forma secuencial. | Alto, ya que todo el conjunto de resultados se carga en un array en memoria. |
| Flexibilidad | Limitada a un recorrido secuencial hacia adelante. | Total. Una vez en el array, puedes acceder a cualquier fila/columna en cualquier orden. |
| Escalabilidad | Pobre. El rendimiento se degrada rápidamente con más usuarios y datos. | Excelente. Minimiza la carga sobre la base de datos, permitiendo servir a más usuarios. |
Preguntas Frecuentes (FAQ)
¿Es `GetRows` siempre la mejor opción?
Para operaciones de lectura de datos, en el 99% de los casos, sí. La única consideración importante es el uso de memoria. Si estás intentando cargar una tabla con millones de filas y muchas columnas, podrías agotar la memoria de tu servidor web. En esos casos extremos, es crucial limitar el número de filas con GetRows(numero_de_filas) o procesar los datos en lotes.
¿Qué sucede si el RecordSet está vacío y llamo a GetRows?
No se producirá un error en la llamada a GetRows. Sin embargo, la variable resultante no será un array inicializado. Por eso es una buena práctica comprobar si el RecordSet contiene filas con If Not oRecordSet.EOF antes de llamar al método, y luego verificar si la variable es un array con IsArray() antes de intentar recorrerla.
¿El orden de las columnas en el array es el mismo que en mi consulta SQL?
Sí, absolutamente. El primer índice del array (la dimensión de la columna) se corresponde directamente con el orden de los campos en tu sentencia SELECT, comenzando desde el índice 0. SELECT CampoA, CampoB resultará en arr(0, fila) para CampoA y arr(1, fila) para CampoB.
Después de llamar a GetRows(100), ¿puedo volver a llamar a GetRows para obtener las siguientes 100 filas?
Sí. El método GetRows avanza el puntero del cursor en el RecordSet. Después de leer las primeras 100 filas, el puntero estará en la fila 101. Una segunda llamada a GetRows(100) recuperará las filas de la 101 a la 200. Este es un patrón muy eficaz para procesar grandes conjuntos de datos en lotes manejables.
Conclusión: Un Pequeño Cambio para una Gran Mejora
Adoptar el método GetRows en tus proyectos de ADO no es solo una buena práctica; es un paso fundamental hacia la creación de aplicaciones más rápidas, robustas y escalables. Al minimizar las interacciones con la base de datos y liberar las conexiones rápidamente, reduces drásticamente los cuellos de botella. La capacidad de limitar las filas recuperadas te otorga un control granular que el bucle tradicional simplemente no puede ofrecer. La próxima vez que te encuentres escribiendo un bucle While Not EOF, detente y considera el poder y la eficiencia que GetRows puede aportar a tu código.
Si quieres conocer otros artículos parecidos a Optimiza ADO: Limita filas con GetRows puedes visitar la categoría Juegos.
