# Optimización de consultas

• ### 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

• Deleted
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/

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