locked
SQL SERVER 2008. Consulta de multiples base de datos. lentitud RRS feed

  • Pregunta

  • buenas tardes. tengo una cuestion que no se si tiene solucion, a ver si me podeís ayudar.

    tengo 3 bases de datos: bd1, bd2, bd3

    hago un use de la base de datos bd1 (USE BD1)

    y a continuacion hago la siguiente select: SELECT * FROM bd2.dbo.mitabla
    u otra  por ejemplo SELECT * FROM bd1.dbo.mitabla A join bd2.dbo.mitabla B on A.pk = B.pk (por ejemplo)

    me gustaría saber porque es mas lenta esta consulta (SELECT * FROM bd1.dbo.mitabla) cuando estoy haciendo uso de bd1
    lo mismo ocurre con la otra consulta del ejemplo.

    se puede optimizar de alguna forma, para que la velocidad sea igual si estoy usando la base de datos en la que consulta como si no¿??¿

    muchas gracias, por cierto, las vistas tampoco me solucionan nada.
    martes, 1 de septiembre de 2009 16:26

Respuestas

  • Hola.

    Asegúrate de que las bases de datos no están en autoclose. De ser así, cuando no hay conexiones la base de datos pasa a estar cerrada, desaparece el log. Cuando se intenta conectar, entonces, la base de datos ha de recuperarse, y tarda un poco. Para cambiarlo, tendrías que entrar en las propiedades, a través del Management Studio y poner el parámetro "AutoClose" a "False".


    Alberto López Grande.
    miércoles, 2 de septiembre de 2009 18:37
    Moderador

Todas las respuestas

  • Hola.

    Creo que no se debe al "USE". Es cierto que existe cierto retardo cuando se hace referencia al nombre con tres partes, ya que es necesario realizar una serie de verificaciones de permisos, pero eso, en una consulta individual es imperceptible. Se nota (y prácticamente nada) en el volumen global de un servidor con consultas que tengan esa filosofía en la carga.

    Me inclino a pensar que la diferencia de rendimiento se debe a que la primera consulta que lanzas es más lenta que la segunda (independientemente de a lo que llames "primera" o "segunda") y eso es debido a que la segunda ejecución encuentra los datos en cache. Escribí sobre ello hace un tiempo (http://www.configuracionesintegrales.com/miguele/iimasrapido.asp?articulo=306).

    En casos de consultas más complejas, podría ser también que en función de la base de datos el plan de ejecución sea diferente, pero para una consulta tan simple, eso tampoco va a suceder.

    Haz la prueba, ejecuta ambas consultas en distinto orden. Si obtienes siempre resultados dispares en una de ellas, nos dices.


    Alberto López Grande.
    martes, 1 de septiembre de 2009 16:35
    Moderador
  • lo de la cache no es seguro. te comento  yo tengo un dataset en la aplicacion con un conjunto de registros, cuando me muevo por estos registros, lanzo una consulta tan simple como "SELECT * FROM bd2.dbo.mitabla" pero estoy en bd1 posicionado, entonces cada vez que me muevo de registro por el grid, se relentiza , creo que debe ser por algo de las comprobaciones de permisos que me comentas, no hay forma de acelerar esto??
    martes, 1 de septiembre de 2009 17:16
  • Hola.

    Con el debido respeto, si hay una aplicación de por medio, entonces lo que es seguro es que es la aplicación la que está causando el efecto y no el servidor de bases de datos. Es posible que estés ejecutando muchas consultas, generando bloqueos, el tipo de cursor no sea el adecuado o muchas otras cosas. Si lo que quieres es aislar la problemática de la base de datos de la problemática de la aplicación, ejecuta las consultas directamente con Management Studio, una consulta debajo de la otra, con el "use" entre medias si quieres. Así puedes comparar.

    Una vez hecho esto, te sugiero que utilices Profiler para capturar todas las sentencias que se están lanzando a SQL Server desde tu aplicación, con el fin determinar si el comportamiento de tu aplicación es el que tú buscas o no. Ello te permitirá determinar lo que está ocurriendo para que se dé ese efecto que comentas.

    Alberto López Grande.
    martes, 1 de septiembre de 2009 19:23
    Moderador
  • hola, muchas gracias por tu ayuda, pero lo que me sugieres es exactamente lo que he hecho antes de preguntar aquí, te comento. ejecutando las mismas consultas desde el management studio, si estoi conectado a una base de datos BD1 por ejemplo y la consulta la ejecuto sobre BD2 me va mas lento que si estoy conectado a BD2 y hago la consulta sobre ella misma. si pongo un use entre dos consultas, por ejemplo, la misma copiada y pegada muchas veces, si el use es siempre de la misma base de datos no hay problema, pero si vas alternando use de una base de datos y otra, como es el caso que yo necesito, tardaba lo mismo que si no hago un use antes de cada consulta, y dejo siempre conectada una de ellas [que es bastante].

    la problematica es, imaginate que tienes una aplicacion de gestion donde cada año natural es una base de datos donde estan todos los documentos del año, tras varios años trabajando con la aplicacion tienes varias bases de datos con documentos. si quiero consultar los documentos por fecha por ejemplo y las fechas comprenden varios años, la aplicacion busca en las bases de datos correspodientes para mostrar el listado con la cabecera por ejemplo de la factura, dichas facturas pueden tener por ejemplo unos descuentos y estos quiero mostrarlos en el mismo formulario, entonces conforme te mueves por el grid de las cabeceras de facturas, como cada factura puede estar en una base de datos distinta, debo de consultar sus descuentos en la base de datos correspondiente para mostrar los descuentos. este proceso es el que tarda demasiado.
    miércoles, 2 de septiembre de 2009 14:17
  • Hola.

    No logro entender lo que te ocurre. ¿Puedes pasarnos dos scripts indicando "Así va lento" y "Así va más rápido"?

    Si estamos comparando la consulta:

    use bd2
    go
    SELECT * FROM bd2.dbo.mitabla
    go

    Y la consulta:

    use bd1
    go
    SELECT * FROM bd2.dbo.mitabla
    go

    Dado que la consulta es la misma, han de tener el mismo rendimiento (y tardar lo mismo), independientemente de en qué base datos estés. Así que debemos estar hablando de cosas diferentes.


    Alberto López Grande.
    miércoles, 2 de septiembre de 2009 14:29
    Moderador
  • es exactamente lo que has puesto, pero primero ejecuto el use y a continuacio la select (lanzar solo la select) en los dos casos, y en cada uno de ellos teniendo en uso la base de datos donde esta la tabla a la que hacemos la select y en el otro otra base de datos cualquiera.
    miércoles, 2 de septiembre de 2009 14:38
  • Hola.

    ¿Podrías hacer la siguiente prueba?
    1. En Management Studio, ejecutas "set statistics io on" y lo borras.
    2. Pulsas Ctrl + M, para que se muestre el plan de ejecución, y Ctrl + D, para que los datos salgan a grid.
    3. Copias lo que te he pasado (cambiando las tablas por sus nombres correctos), pero dejando los "use".
    4. Lo ejecutas TODO A LA VEZ.
    5. No pasas TODO lo que salga en la pestaña "Messages".
    6. En la pestaña "Execution Plan", encima de cada gráfico aparece el coste estimado de la consulta dentro del batch, como un tanto por ciento. Nos pasas el tanto por ciento de cada una de las dos consultas.
    Con esos datos creo que sería suficiente para saber lo que está ocurriendo.


    Alberto López Grande.
    miércoles, 2 de septiembre de 2009 15:33
    Moderador
  • buenas, parece que vamos avanzando.


    antes de mostrarte lo que he ejecutado decirte que despues de ejecutar el  "set statistics io on" y ejecutar la aplicacion que lanza las consultas que te comentaba, todo ha ido rapido, como debería de ir. a continuacion ejecute el script que me pedias y los resultado estan a continuacion. si no es mucha moletia, me podrías explicar en que consiste  la instruccion set statistics io on" o decirme donde viene explicada. muchas gracias.

    he ejecutado el siguiente codigo

        use ALBASYS00
        go
        SELECT A.Orden, A.Descuento, B.Descuento NombreDto
        FROM ALBAGES0000.dbo.DesctosPieFacturasCompra A
        LEFT JOIN ALBADB00.dbo.DescuentosPieCompra B on A.IdDescuento = B.IdDescuento
        WHERE A.CodigoAlmacen = 0
        AND A.Puesto        = 1
        AND A.Documento     = 310
        AND A.AfectaCosto   = 'T'
        ORDER By A.Orden
       
        use ALBAGES0000
        go
        SELECT A.Orden, A.Descuento, B.Descuento NombreDto
        FROM ALBAGES0000.dbo.DesctosPieFacturasCompra A
        LEFT JOIN ALBADB00.dbo.DescuentosPieCompra B on A.IdDescuento = B.IdDescuento
        WHERE A.CodigoAlmacen = 0
        AND A.Puesto        = 1
        AND A.Documento     = 310
        AND A.AfectaCosto   = 'T'
        ORDER By A.Orden

    el resultado en messages es:

    (3 filas afectadas)
    Tabla 'DescuentosPieCompra'. Recuento de exámenes 0, lecturas lógicas 6, lecturas físicas 0, lecturas anticipadas 0, lecturas lógicas de LOB 0, lecturas físicas de LOB 0, lecturas anticipadas de LOB 0.
    Tabla 'DesctosPieFacturasCompra'. Recuento de exámenes 1, lecturas lógicas 2, lecturas físicas 0, lecturas anticipadas 0, lecturas lógicas de LOB 0, lecturas físicas de LOB 0, lecturas anticipadas de LOB 0.

    (1 filas afectadas)

    (3 filas afectadas)
    Tabla 'DescuentosPieCompra'. Recuento de exámenes 0, lecturas lógicas 6, lecturas físicas 0, lecturas anticipadas 0, lecturas lógicas de LOB 0, lecturas físicas de LOB 0, lecturas anticipadas de LOB 0.
    Tabla 'DesctosPieFacturasCompra'. Recuento de exámenes 1, lecturas lógicas 2, lecturas físicas 0, lecturas anticipadas 0, lecturas lógicas de LOB 0, lecturas físicas de LOB 0, lecturas anticipadas de LOB 0.


    miércoles, 2 de septiembre de 2009 16:31
  • Hola.

    Por una parte, aunque no indicas lo del porcentaje de coste de cada consulta, no es necesario, ya que sólamente con ver que se hacen exactamente el mismo número de lecturas en cada consulta ya puedo concluir que el rendimiento ha de ser el mismo, con lo que como te indicaba, el rendimiento de ambas consultas no depende de la base de datos desde la que se lance.

    Por otra parte, "set statistics io on" lo que hace es mostrar las lecturas lógicas y físicas que implica la consulta, y sin duda no es la solución del problema, sino un mecanismo de diagnóstico y evaluación del rendimiento. Más información en http://msdn.microsoft.com/es-es/library/ms184361.aspx.



    Alberto López Grande.
    miércoles, 2 de septiembre de 2009 17:00
    Moderador
  • Hola, muchas gracias por tu ayuda, ya hemos visto cual es el problema, que ya hemos comprobado y re-comprobado que ocurre de esta forma. no se si será un bug de la versión o que es así.

    si con la aplicacion abierta, se abre el management studio y se crean conexiones a las dos bases de datos a las que se conecta la apliacion, tanto en la aplicacion como en el management studio corren rapidas las consultas, en cuanto dejamos de hacer use de una de las bases de datos que intervienen en el select, las consultas se vuelven lentas.

    en definitiva, parece que para que una select que se haga desde cualquier conexion, solo iran bien las consultas que se hagan sobre bases de datos que estan usadas en alguna de las conexiones que exitan simultaneamente. entiendo que puede ser porque al una base de datos no estar usada por nadie en un momento dado, si se quiere acceder a ella desde una conexion sin usarla, el sistema deberá de hacer algun tipo de comprobaciones. ¿puede ser?.
    miércoles, 2 de septiembre de 2009 17:27
  • Hola.

    Asegúrate de que las bases de datos no están en autoclose. De ser así, cuando no hay conexiones la base de datos pasa a estar cerrada, desaparece el log. Cuando se intenta conectar, entonces, la base de datos ha de recuperarse, y tarda un poco. Para cambiarlo, tendrías que entrar en las propiedades, a través del Management Studio y poner el parámetro "AutoClose" a "False".


    Alberto López Grande.
    miércoles, 2 de septiembre de 2009 18:37
    Moderador
  • buenos dias.

    PERFECTO.  Esta es la respuesta correcta 100%. ¿Me podrías decir la instruccion sql para hacerlo desde código?, y otra pregunta, ¿Hay algun inconveniente por dejar las bases de datos abiertas?, lentitud, memoria, etc, en definitiva que es mejor
    autoclose = true o false.

    muchisimas gracias por todo.
    jueves, 3 de septiembre de 2009 7:29
  • Hola.

    Para hacerlo desde un script:
    USE [master]
    GO
    ALTER DATABASE [MiBaseDeDatos] SET AUTO_CLOSE OFF 
    GO
    En cuando a los inconvenientes, ninguno. De hecho, es más que posible que en futuras versiones ya no exista el parámetro.


    Alberto López Grande.
    jueves, 3 de septiembre de 2009 7:48
    Moderador
  • PERFECTO. muchisimas gracias por tu ayuda.
    jueves, 3 de septiembre de 2009 8:04