ADO.NET :: ¿Trabaja el objeto DataReader realmente en un ambiente conectado?
Artículo :: Programación :: ADO.NET
¿Trabaja el objeto DataReader realmente en un ambiente conectado?
Leía el otro día el comentario de mi compi Pablo Álvarez Doval en su blog acerca de si los DataReader utilizaban o no cursores, cuando me acordé de la explicación que he dado en varias ocasiones, y en concreto en las cabañas que hice en el lanzamiento de Visual Studio 2005, acerca de si los DataReader están realmente conectados o no.
Por esa razón, voy a aprovechar en esta ocasión, para hablar de ese tema que tan bien viene después de los comentarios de Pablo (como siempre, se aceptan críticas, opiniones, demostración y demás berenjenas de la huerta).
Todos sabemos que los DataReader son usados en .NET para trabajar con datos estando conectados a la fuente de datos, ahora bien, la pregunta es sencilla. ¿Cómo trabaja exactamente los objetos DataReader?, ¿trabajan realmente en un ambiente conectado?.
Para tratar de responder a esta pregunta, podemos basarnos perfectamente en el comentario de Pablo, porque ahí mismo, nos da en buena parte la clave de como funciona un DataReader al trabajar en este caso, con SQL Server.
Comenzaré comentando la prueba que he realizado, y finalmente las conclusiones.
Para este ejemplo, he creado un simple formulario Windows al que he insertado un control TextBox, un control Button y un control Label.
El código que he escrito es el siguiente:
Imports System.Data.SqlClient Public Class Form1 Private conexion As SqlConnection Private comando As SqlCommand Private filas As Integer = 0 Private lector As SqlDataReader Private Function ObtenerConexion() As String Return «Data Source=.SQLEXPRESS;Initial Catalog=AdventureWorks;Integrated Security=True» End Function Private Function ObtenerSQL() As String Return «SELECT * FROM Person.Contact» End Function Private Sub Form1_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Leave conexion.Close() comando.Dispose() End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load conexion = New SqlConnection(ObtenerConexion) comando = New SqlCommand(ObtenerSQL, conexion) conexion.Open() lector = comando.ExecuteReader() End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Try lector.Read() Me.TextBox1.Text = lector(«FirstName») & » « & lector(«LastName») filas += 1 Me.Label1.Text = filas & » fila (s) de datos» Catch ex As Exception ‘ NADA Me.Label1.Text = ex.Message End Try End Sub End Class ‘ Form1 |
Como podemos apreciar en el código, hemos utilizado como base de datos, la base de datos de ejemplo de Microsoft AdventureWorks en Microsoft SQL Server 2005 Express Edition. También me he provisto de la ventana de Servicios, la cuál usaré para detener el servicio de SQL Server 2005 Express Edition para estudiar los comportamientos de la recogida de datos.
Seguimos… 🙂
Si ejecutamos este pequeño ejemplo, accederemos a los datos de la base de datos AdventureWorks e iremos navegando por ellos uno detrás del otro… hacia adelante… forward-only, read-only como bien indicaba Pablo en su comentario.
Sin embargo, este funcionamiento se basa en un buffer. La pregunta en este punto, es si el buffer está en el lado de SQL Server o en el lado de los objetos de ADO.NET… buena pregunta ¿verdad?.
El caso es que en este punto, la primera prueba (sencilla) es ejecutar nuestro ejemplo y ver el comportamiento de nuestro programa a la hora de pulsar el botón una vez tras otra. Parece que funciona… ¡bien!. Sigamos un poco más…
A continuación, ejecutaremos nuestra demo, haremos clic en el botón de nuestra demo, observaremos que lee el primer registro y acudiendo al Servicio de SQL Server (SQL EXPRESS), pulsaremos sobre el botón detener servicio. Pulsaremos nuevamente el botón y veremos que lee el siguiente registro. Pulsaremos el botón una y otra vez hasta que veamos que no lee más registro, mostrando una información de error en la etiqueta o control Label.
Si prestamos atención al error, el mensaje es un error de transporte de canalización de datos.
En mi caso el error se produce al leer el tercer registro, detener el servicio y querer leer el cuarto registro.
Así que he pensado que si hay un buffer por medio que recupera en este ejemplo tres registros, es lógico pensar que leerá los datos hasta el tercer registro incluido, y cuando quiera leer el cuarto, meterá el cuarto en mi aplicación y leerá el siguiente bloque para meter en el buffer que serán aproximadamente otros tres registros, así que si leo el cuarto registro y detengo el servicio, la lectura de registro finalizará en el séptimo.
Tenemos que tener en cuenta, que el buffer rellena datos y que estas pruebas pueden oscilar dependiendo de diferentes factores muy generales, así que tomemos estos datos como ajustables y dependientes de la máquina, por lo que son datos aproximativos.
En resumidas cuentas, la lectura se realiza como se indica en las siguientes imágenes:
Observando esta secuencia, podemos ver que en primer lugar, se rellena un buffer con datos, los registros 1, 2 y 3.
La aplicación va leyendo estos datos, así hasta llegar al tercer registro. Al leer el cuarto, el cuarto registro que no está en el buffer, el DataReader se va a por ese registro a la fuente de datos, lo recupera y rellena el buffer con otros tantos registros hasta llenar el buffer.
Este ciclo se repite n veces hasta completar la lectura de los datos solicitados.
Es decir, el proceso de lectura con DataReader no es un proceso de lectura conectado puro, y por lo tanto, no realiza una lectura contra la base de datos cada vez que lee el siguiente registro, sino que se nutre de un buffer para recuperar registros, algo completamente lógico, ya que sino, el torpedeo y lectura constante a la fuente de datos, mermaría el rendimiento de la misma, por muy pequeño que sea dicho rendimiento, algo que no vamos a entrar a discutir ahora y que dependería de múltiples factores (red, hardware, software, dimensionamiento, etc etc etc).
El quiz de la primera pregunta queda resuelto en tanto en cuanto, hemos visto que aunque un DataReader trabaja de forma conectada, no lo hace de forma continua y sólo bajo demanda, bajo la demanda del buffer de relleno, pero aún en mi opinión, queda otra duda pendiente… ¿dónde está ese buffer?. ¿Está en SQL Server o en ADO.NET?.
En el gráfico no lo he pintado, porque el buffer… ¡no sabemos realmente dónde está!. Así que eso mismo, es lo que demostraremos a continuación.
Para resolver esta segunda cuestión, nada mejor que trabajar en red con un SQL Server distribuido… el mismo SQL Server 2005 Express por ejemplo.
Pondremos esa fuente de datos en un servidor, y ejecutaremos nuestra aplicación de demo en otro PC. Así, al PC que sirve los datos (SQL Server), le quitaremos la conexión de red cuando la aplicación comience a leer los datos del buffer. De este modo, demostraremos si el buffer está en el servidor de SQL Server o por el contrario en la parte local, es decir, en ADO.NET, al cuál accedería DataReader.
Ejecutaremos nuevamente nuestra aplicación cambiando la cadena de conexión para apuntar a otro servidor, leeremos el primer registro, y quitaremos del PC dónde tenemos SQL Server el cable de red. ¿Que ocurre?.
Lo que ocurre es que el buffer que teníamos siguepermitiéndonos leer los datos. Lo mismo ocurre con el dibujo anterior, si llego al tercer registro y quito el cable de red, al intentar leer el cuarto registro de SQL Server dará un error. Si por el contrario, leemos los datos hasta llegar al cuarto registro y en ese momento quito el cable de red, la aplicación leerá el quinto, sexto y séptimo registro, pero al intentar leer el octavo, acudirá al servidor y devolverá un error.
La conclusión de todo esto en mi opinión, es la siguiente:
1) Los objetos DataReader no son puramente conectados como tal en cuanto a la petición bajo demanda. Si son conectados, pero trabajan con un buffer en local (no en el servidor) que recupera del servidor para trabajar con datos más rápidamente.
2) El buffer con el que trabaja DataRader, no está en el servidor de bases de datos, sino en el propio sitio local.
Espero que estas afirmaciones no creen ampollas a nadie y sí que invito a que los que quieran, hagan sus pruebas y comenten sus resultados, pues aún y cuando estoy terminado este pequeño artículo, tengo un par de dudas sobre algunos comportamientos que seguiré investigando.
22 Responsesso far
Después de leer el comentario de mi compi Pablo Álvarez Doval en su blog acerca de si los DataReader
Este tema es muy interesante Jorge
Gracias por arrojar un poco más de luz al tema!!!
Magistral titan! 🙂
Yo tuve conclusiones similares en entorno web , hay un buffer local .
Seria interesante comentar tambien que existe la nueva cache de datos en ado.net 2.0 y el metodo executepagereader del objeto command que puede ser muy interesante para algunos además del famoso MARS MultipleActive Recordsets que nos va a permitir tener varios datareaders sobre la misma conexion cosa que no se podia antes con la version 1 😉 Lo comentaré en mi blog con mas tiempo.
Me lo preguntan a menudo en los cursos.
Un abrazo
Sergio
Hola Jorge,
Estupenda demostración de como se solventan las dusdas existenciales en esto de la programción!!! Siempre una propia experiencia en tu código vale más que todas las eplicaciones del mundo, aunque tb va bien tenerlas por si alguien me las quiere dar… jejeje
Me gusaría seguir con la propuesta de Sergio y mis dudas tb son en un ambiente web y concretamente con la tecnología Reporting Services. ¿Se utilizan DataReaders en las consultas de los informes?¿Se almacenan en una chache las consultas realizadas para liberar de realizar la misma una y otra vez?¿Donde puedo alguna pistilla de como funciona por dentro realmente esta tecnología?
En fin, enhorabuena por un excelente artículo.
Saludos
Muy buena demostración, definitivamente me he visto envuelto en las mismas preguntas, además de que he observado de que en muchos tutoriales y ejemplos que te topas en internet en realidad utilizan el modo conectado de tal forma que simulan la misma actividad del modelo desconectado, es decir:
.Abren la conexion,
traen datos y cierran la conexion.
.Abren la conexion,
envian transacciones al servidor
y cierran la conexion.
Lo anterior es lo mismo que usar un DataAdapter que se conecta y desconecta en cada operación, solo que la diferencia es que el DA. lo hace con un conjunto de instrucciones a la vez.
Hola en la actualidad estoy creando una aplicación para la carga masiva de datos. He creado un dataAdapter, su dataset, su conexión y hasta aquí todo perfecto, pero al realizar la inserción en la BD. Tarda a mi entender demasiado, 25000 registros más de media hora. Es esto normal o debo de utilizar otras herramientas.
Agradecería que alguien me pudiera orientar un poco.
Gracias.
Después de leer el comentario de mi compi Pablo Álvarez Doval en su blog acerca de si los DataReader
Buen aporte a la comunidad .NET, gracias por aclarar la duda.
Siempre conectado, adios.
Hola es un pacer saludarlos, yo soy nuevo en programacion de vb net y tengo mucha necesidad de aprender la programacion.
Tengo varias aplicaciones desarrolladas en vb 6.00 y tengo proyectos para vb net
la pregunta especifica es la siguiente
1) Tengo una tabla de sql server y necesito hacer un pantalla para poder llamar los registro o consultarlos bajo una campo especifco y si el registro existe pues mostrar los demas campos en pantalla
la estructura es la siguiente
nombre de tabla cliente
campos
id_cliente nvarchar(20)
nombre_cliente nvarchar(50)
tel_cliente nvarchar (15)
saldo_cliente decimal (18,2)
necesito saber como utilizar el SqlConnection, sqlcommand, dataset, SqlDataAdapter
para realizar la insert, update, delete de los registro.
Ademas para la conexion es necesario declarar un modulo e invocarlo desde una forma (poner ejemplo) o es necesario estarlo declarando en cada formulario
os agradece mucho si podeis ayudarme
mi direccion de correo es la siguiente
ramcdema@yahoo.com
Je crois que ce n’est pas votre premier Web-travaillent! 😉
Yo creo que la verdadera cuestión es: ¿Mantiene l conexión activa? y ¿Está creando en el servidor el curso completo de la consulta solicitada y va suministrando cachitos a cachitos al buffer de cache del cliente?
😉
Excelente comentario
La verdad me despejastes la duda si realmente este objeto trabajaba de forma conectada y la forma en que lo explicastes es bien razonable.
Exitos
Excelente artículo. He realizado algunas pruebas que aun no termino claro, y si va conforme a tu comentario. 😉
Este artículo me parece bastante interesante, actualmente estoy iniciando en el manejo de bases de datos con tecnología .NET y realmente me parece un buen recurso esta evaluación. La utilización de objetos y su eficiencia es bastante importante. Gracias y saludos.
Hola, muchas gracias por la explicación.
Es muy interesante y de igual forma importante el poder comprender e interpretar el funcionamiento y comportamiento del DataReader. Pude comprender que el Buffer es capaz de almacenar determinados datos si cumple ciertas condiciones y es esto lo que ayuda al DataReader a trabajar de cierta manera en un ambiente desconectado. Por consiguiente el DataReader no sólo trabaja en un ambiente conectado sino que también gracias al Buffer lo puede hacer de manera desconectada. De ante mano muchas gracias por el comentario.
Hasta pronto.
Muchas gracias por la explicacion me es de mucha ayuda ya que necesito saber cuanto mas se pueda acerca de datareader ya que muy pronto hare una aplicacion muy complicada
Gracias
Debo decir que luego de haber leído el tema al que nos dirigen en el primer parrafo, me esperaba todo menos que el buffer se encontrara de lado de la aplicación. Realmente debo felicitarte dado a que has podido explicar este tema de forma clara y precisa, gracias por apoyar a la comunidad de desarrolladores.
Bendiciones en Jesús y María.
Yo pienso que este es un gran aporte para la tecnologia .NET ya que en muchas aplicaciones se ve la necesidad de ahorrar recursos y con un ambiente desconectado la necesidad de recursos sera menor gracias por el aporte y lo tomare en cuenta para crear mis siguientes aplicaciones en .NET
Antes que nada permiteme presentarme mi nombre es Juan Perez ingeniero en sistemas de la ciudad de Guatemala. La verdad este articulo me es de mucha ayuda por que por medio de el mismo pude comprender perfectamente como trabaja realmente el objeto DataReader.
Saludos y Bendiciones en Jesús y María.
bueno gracias por tu aporte acerca de los
datareaders no sabia como trabajaban internamente
en los bufer de almacenamiento de la memoria y me prodrias explicar tambien acerca delos dataset¿Trabaja el objeto Dataset realmente en un ambiente desconectado ? como trabajan internamente
saludos :):)
iooioioiii
DataReader proporciona una secuencia de datos sin búfer que permite a la lógica de los procedimientos procesar eficazmente y de forma secuencial los resultados procedentes de un origen de datos. DataReader es la mejor opción cuando se trata de recuperar grandes cantidades de datos, ya que éstos no se almacenan en la memoria caché.