none
Como podría evitar en indice que me sugiere mas abajo (Volumen 2500 registros) RRS feed

  • Pregunta

  • Tengo esta consulta que esta mas abajo, en un rango de fechas promedio de 1 mes tarda 6 a 7 segundos en responder la consulta. Me di cuenta al tener sub Select ocurre eso, tengo eso para contar la ordenes anteriores de los pacientes, nada mas .  Como podría mejorar la consulta sin utilizar el indice ??

    Al colocar ese indice me saca en 1 segundo o milisegundos..

    Indice a crear

    CREATE NONCLUSTERED INDEX IDX_OrdenesAnteriores
    ON [dbo].[OrdenAnalisis] ([IdPaciente],[IdOrdenAnalisis])

       Query             

    Select p.Nombre, p.apellido
                    oa.NroUrgencia ,
                    ( select    count(ord.IdPaciente)
                      from      dbo.OrdenAnalisis ord
                      where     ord.IdPaciente = oa.IdPaciente
                                and ord.IdOrdenAnalisis != oa.IdOrdenAnalisis
                    ) as OrdenesAnteriores            

            from   

    dbo.OrdenAnalisis as oa
                    join dbo.Paciente as p on oa.IdPaciente = p.IdPaciente
                    join dbo.TipoPaciente as tp on tp.IdTipoPaciente = oa.IdTipoPaciente
                    join dbo.Medicos as m on m.IdMedico = oa.IdMedico
                    join dbo.TipoEdad as te on oa.IdTipoEdad = te.IdTipoEdad
                    join dbo.EstadoOrden as eo on eo.IdEstadoOrden = oa.IdEstadoOrden
                    join dbo.Categorias as c on c.IdCategoria = p.IdCategoria
                    left join dbo.Personal as per on oa.IdPersonal = per.IdPersonal
                    left join dbo.Usuarios as uc on oa.IdUsuarioCreador = uc.IdUsuario

    where oa.fecha '01/11/2019' and '28/11/2019'

    jueves, 28 de noviembre de 2019 19:00

Todas las respuestas

  • Hola Bader Molinas:

    Prueba el operador APPLY

    Select p.Nombre, p.apellido
                    oa.NroUrgencia ,
                    OrdenesAnteriores.Cuenta
            from   
    			 		 dbo.OrdenAnalisis as oa
                    join dbo.Paciente as p on oa.IdPaciente = p.IdPaciente
                    join dbo.TipoPaciente as tp on tp.IdTipoPaciente = oa.IdTipoPaciente
                    join dbo.Medicos as m on m.IdMedico = oa.IdMedico
                    join dbo.TipoEdad as te on oa.IdTipoEdad = te.IdTipoEdad
                    join dbo.EstadoOrden as eo on eo.IdEstadoOrden = oa.IdEstadoOrden
                    join dbo.Categorias as c on c.IdCategoria = p.IdCategoria
                    left join dbo.Personal as per on oa.IdPersonal = per.IdPersonal
                    left join dbo.Usuarios as uc on oa.IdUsuarioCreador = uc.IdUsuario
    				OUTER APPLY (
    
    				select    count(ord.IdPaciente) as cuenta
                      from      dbo.OrdenAnalisis ord
                      where     ord.IdPaciente = oa.IdPaciente
                                and ord.IdOrdenAnalisis != oa.IdOrdenAnalisis
    				) as OrdenesAnteriores
    
    where oa.fecha '01/11/2019' and '28/11/2019'

    El juego esta en que el conjunto interior (definido en el operador apply, tiene como restricciones, el conjunto exterior oa. Es casi igual que lo que habías presentado, pero cuando el motor realice la consulta no va a operar linea por linea para poder hallar la cuenta, sino que lo hará sin tener en cuenta lo que ocurre para montar la consulta, y cuando la tenga hara lo mismo que en un left join. Fusionará tu conjunto de datos de la izquierda con todo lo que resuelva para el OrdenesAnteriores.

    Ya comentas

    Nota adicional. Si el conjunto se llama ordenes anteriores, quizá la cuenta interior, debería tambien tener una restricción de fecha anterior a 20191101. Lo cual puede mejorar también el resultado
    jueves, 28 de noviembre de 2019 19:09
  • La razón por la que es lento es la existencia de la subconsulta dentro de la lista de selección. Si hay 2500 registros en los resultados, entonces esa subconsulta se ejecuta 2500 veces. Lógicamente, es conveniente acelerarla lo más posible, porque cualquier mejora que se logre en el tiempo de resolución de esa subconsulta queda multiplicada por 2500.

    Y el índice la mejora mucho porque cubre la consulta (es un "covering index"). Esto se debe a que incluye los dos campos que intervienen en la consulta (IdPaciente y OrdenAnalisis). De esta manera, la consulta se puede resolver a toda velocidad con solo consultar el índice y sin saltar a la tabla principal, con lo que la diferencia es espectacular (y además al ser dos datos pequeños cabe mucha información en pocas páginas del índice -- si le pides el "set statistics io on" verás que el número de páginas accedidas es muy pequeño).

    La alternativa a ese índice pasaría por eliminar la subconsulta. Eso implica meter OrdenAnalisis en la lista de Joins y luego aplicar un "group by" más un "having". Quedará un poco complicadillo (hay que dedicarle una buena "pensada"), pero debería funcionar razonablemente rápido.

    jueves, 28 de noviembre de 2019 19:20
  • Buenas   Javi Fernández F , realice la prueba y es mas lento aun. Tarda promedio 8 a 9 segundos, tengo algunos group  by tambien y por el volumen de datos. Creo que lo mas conveniente es usar el Indice porque la diferencia es demasiada.. en mili segundo obtengo los resultados.
    jueves, 28 de noviembre de 2019 19:28
  •     Realice varias pruebas y no logro buenos resultados sin el indice.. Es tal cual como decís que la mejora con el indice es espectacular porque utilizo 2 int en el where y solo para contar registros anteriores. 

        Muchas gracias por la aclaración...

    Saludos 

    jueves, 28 de noviembre de 2019 19:31