none
Optimización de consultas RRS feed

  • Pregunta

  • Hola:

    Tengo un sp

    ALTER PROCEDURE [dbo].[seleccionar_cambio]
    	(
    	@idioma tinyint=1,
    	@m2 int,
    	@m3 int=0,
    	@cociente bit=0
    	)
    AS
    	set nocount on
    	declare @moneda int
    	select @moneda=moneda from comun.dbo.paises where p0=(select r1 from comun.dbo.regiones where r0=(select campo0 from comun.dbo.varios where v0=10))
    	if @cociente=0
    		select (select cotizacion from comun.dbo.monedas where m0=@m2) as cotizacion,(select simbolo+' ('+case @idioma when 1 then moneda_singular_espanol when 2 then moneda_singular_ingles when 3 then moneda_singular_frances when 4 then moneda_singular_portugues end+')' from comun.dbo.monedas where m0=@moneda) as moneda_empresa,
    		simbolo+' ('+case @idioma when 1 then moneda_singular_espanol when 2 then moneda_singular_ingles when 3 then moneda_singular_frances when 4 then moneda_singular_portugues end+')' as moneda_singular,simbolo+' ('+case @idioma when 1 then moneda_plural_espanol when 2 then moneda_plural_ingles when 3 then moneda_plural_frances when 4 then moneda_plural_portugues end+')' as moneda_plural,
    		null as moneda_plural3,null as cotizacion3,campo0 as fcambio from comun.dbo.varios cross join comun.dbo.monedas where v0=1393 and m0=@m2
    	else
    		select (select 1/cotizacion from comun.dbo.monedas where m0=@m2) as cotizacion,(select simbolo+' ('+case @idioma when 1 then moneda_singular_espanol when 2 then moneda_singular_ingles when 3 then moneda_singular_frances when 4 then moneda_singular_portugues end+')' from comun.dbo.monedas where m0=@m2) as moneda_empresa,simbolo+' ('+case @idioma when 1 then moneda_singular_espanol when 2 then moneda_singular_ingles when 3 then moneda_singular_frances when 4 then moneda_singular_portugues end+')' as moneda_singular,
    		simbolo+' ('+case @idioma when 1 then moneda_plural_espanol when 2 then moneda_plural_ingles when 3 then moneda_plural_frances when 4 then moneda_plural_portugues end+')' as moneda_plural,
    		case when @m3=@m2 or @m3=0 then null else (select simbolo+' ('+case @idioma when 1 then moneda_plural_espanol when 2 then moneda_plural_ingles when 3 then moneda_plural_frances when 4 then moneda_plural_portugues end+')' from comun.dbo.monedas where m0=@m3 ) end as moneda_plural3,
    		case when @m3=@m2 or @m3=0 then null else (select cotizacion from comun.dbo.monedas where m0=@m3)/(select cotizacion from comun.dbo.monedas where m0=@m2) end as cotizacion3,campo0 as fcambio from comun.dbo.varios cross join comun.dbo.monedas where v0=1393 and m0=@moneda
    

    Haciendo otra pregunta en este foro, me dijeron que las consultas se ven mal.

    ¿cómo las optimizariáis?

    Muchísimas gracias por la ayuda.

    domingo, 20 de octubre de 2019 13:54

Todas las respuestas

  • ¿cómo las optimizariáis?

    Comience por analizar el plan de ejecución.

    Para colaborar necesitamos información como las estructuras de las tablas utilizadas en la consulta, los índices que existen en las tablas, cuál es el propósito de la consulta. Y el plan de ejecución real, salvado como un archivo XML.

    ---

    Mientras tanto, considere la posibilidad de sustituir

       ALTER PROCEDURE [dbo].[seleccionar_cambio]
           (
           ...
           )
       AS

    por

       ALTER PROCEDURE [dbo].[seleccionar_cambio]
           (
           ...
           ) with recompile
       AS


    José Diz     Belo Horizonte, MG - Brasil     [query performance tuning: Porto SQL]


    Este conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita.

    domingo, 20 de octubre de 2019 14:45
  • Hola Volar.2016:

    ALTER PROCEDURE [dbo].[seleccionar_cambio] ( @idioma tinyint=1, @m2 int, @m3 int=0, @cociente bit=0 ) AS set nocount on declare @moneda int select @moneda=moneda from comun.dbo.paises where p0=(select r1 from comun.dbo.regiones where r0=(select campo0 from comun.dbo.varios where v0=10))

    Este código, al menos la parte de Select @moneda se parece bastante a algo de este estilo

    /* ESTO PARECE LO MISMO SIN UTILIZAR SUBCONSULTAS */
    SELECT @moneda = PAS.MONDEDA FROM COMUN.DBO.PAISES PAS 
        INNER JOIN COMUN.DBO.REGIONES REG ON REG.R1 = PAS.P0
        INNER JOIN COMUN.DBO.VARIOS V ON V.CAMPO0 = REG.R0
        WHERE V.V0 = 10;

    La pregunta: para que, utilizar subconsultas, de subconsultas, si se pueden relacionar los registros directamente. Esa manera de operar no es lo más óptimo.

    Es cierto que el optimizador de consultas, probablemente realice lo mismo que yo te expongo, y no cambie absolutamente nada en la ejecución del mismo.

    Continuo:

    SELECT
    (
        SELECT cotizacion
        FROM comun.dbo.monedas
        WHERE m0 = @m2
    ) AS cotizacion, 
    (
        SELECT simbolo + ' (' + CASE @idioma
                                    WHEN 1
                                    THEN moneda_singular_espanol
                                    WHEN 2
                                    THEN moneda_singular_ingles
                                    WHEN 3
                                    THEN moneda_singular_frances
                                    WHEN 4
                                    THEN moneda_singular_portugues
                                END + ')'
        FROM comun.dbo.monedas
        WHERE m0 = @moneda
    ) AS moneda_empresa, 
    simbolo + ' (' + CASE @idioma
                         WHEN 1
                         THEN moneda_singular_espanol
                         WHEN 2
                         THEN moneda_singular_ingles
                         WHEN 3
                         THEN moneda_singular_frances
                         WHEN 4
                         THEN moneda_singular_portugues
                     END + ')' AS moneda_singular, 
    simbolo + ' (' + CASE @idioma
                         WHEN 1
                         THEN moneda_plural_espanol
                         WHEN 2
                         THEN moneda_plural_ingles
                         WHEN 3
                         THEN moneda_plural_frances
                         WHEN 4
                         THEN moneda_plural_portugues
                     END + ')' AS moneda_plural, 
    NULL AS moneda_plural3, 
    NULL AS cotizacion3, 
    campo0 AS fcambio
    FROM comun.dbo.varios
         CROSS JOIN comun.dbo.monedas
    WHERE v0 = 1393
          AND m0 = @m2;
    SELECT @moneda = moneda
    FROM comun.dbo.paises
    WHERE p0 =
    (
        SELECT r1
        FROM comun.dbo.regiones
        WHERE r0 =
        (
            SELECT campo0
            FROM comun.dbo.varios
            WHERE v0 = 10
        )
    );

    Es la parte del IF antes del ese, pero un poco más formateada.

    La pregunta: Para que utilizas cross join con común.dbo.monedas si luego lo restringes a la fila que te viene como parámetro.

    Y por el mismo motivo, para que utilizas subconsultas en la propia select contra el mismo conjunto si se puede relacionar en el from. 

    Eso no es muy óptimo.

    Desconzco lo que tienes en las tablas, pero si solo quieres una fila de esos valores, y tienes varios, es más fácil y rápido, crear una variable de tabla, insertarle esos registros específicos, por lo que recibes como parámetros y luego hacer la select contra esa variable de tabla.

    SELECT
    (
        SELECT 1 / cotizacion
        FROM comun.dbo.monedas
        WHERE m0 = @m2
    ) AS cotizacion, 
    (
        SELECT simbolo + ' (' + CASE @idioma
                                    WHEN 1
                                    THEN moneda_singular_espanol
                                    WHEN 2
                                    THEN moneda_singular_ingles
                                    WHEN 3
                                    THEN moneda_singular_frances
                                    WHEN 4
                                    THEN moneda_singular_portugues
                                END + ')'
        FROM comun.dbo.monedas
        WHERE m0 = @m2
    ) AS moneda_empresa, 
    simbolo + ' (' + CASE @idioma
                         WHEN 1
                         THEN moneda_singular_espanol
                         WHEN 2
                         THEN moneda_singular_ingles
                         WHEN 3
                         THEN moneda_singular_frances
                         WHEN 4
                         THEN moneda_singular_portugues
                     END + ')' AS moneda_singular, 
    simbolo + ' (' + CASE @idioma
                         WHEN 1
                         THEN moneda_plural_espanol
                         WHEN 2
                         THEN moneda_plural_ingles
                         WHEN 3
                         THEN moneda_plural_frances
                         WHEN 4
                         THEN moneda_plural_portugues
                     END + ')' AS moneda_plural,
    CASE
        WHEN @m3 = @m2
             OR @m3 = 0
        THEN NULL
        ELSE
    (
        SELECT simbolo + ' (' + CASE @idioma
                                    WHEN 1
                                    THEN moneda_plural_espanol
                                    WHEN 2
                                    THEN moneda_plural_ingles
                                    WHEN 3
                                    THEN moneda_plural_frances
                                    WHEN 4
                                    THEN moneda_plural_portugues
                                END + ')'
        FROM comun.dbo.monedas
        WHERE m0 = @m3
    )
    END AS moneda_plural3,
    CASE
        WHEN @m3 = @m2
             OR @m3 = 0
        THEN NULL
        ELSE
    (
        SELECT cotizacion
        FROM comun.dbo.monedas
        WHERE m0 = @m3
    ) /
    (
        SELECT cotizacion
        FROM comun.dbo.monedas
        WHERE m0 = @m2
    )
    END AS cotizacion3, 
    campo0 AS fcambio
    FROM comun.dbo.varios
         CROSS JOIN comun.dbo.monedas
    WHERE v0 = 1393
          AND m0 = @moneda;

    Ocurre exactamente lo mismo, con esta otra parte de la select.

    Utilizas subconsultas contra los mismos conjuntos, y eso no es eficiente, y además es muy raro, que cross join, que es un tipo de relación que se usa muy pero que muy poco, en este procedure se use tantas veces y no haya ningún inner join, ni left, ni right, ni full, ni unión, ni cualquier otro tipo de unión entre conjuntos.

    Mira un poco este artículo, haber si ves algo que te encaje

    https://javifer2.wordpress.com/2019/09/16/combinaciones-entre-tablas-inner-left-right-full/

    https://javifer2.blogspot.com/search/label/cross%20join

    Si aún no lo ves claro, o yo simplemente, estoy bastante equivocado, pega un ejemplo de la salida de tu query, y unas pocas filas de la tabla varios, y las que correspondan para monedas, y buscamos una solución más óptima.

    domingo, 20 de octubre de 2019 19:47