Código eficiente vs código ineficiente

Código eficiente vs código ineficiente.
Frecuentemente los directivos de las empresas piden reportes de: gastos, ventas y compras, donde quieren que los datos se muestren en columnas, ya sea por meses o por años. Lo que hacemos incialmente los principiantes es utilizar subconsultas dentro del código de una consulta general; donde cada subconsulta traiga el dato que resulta para el año o mes indicado. Con esta forma de hacer el Query obtenemos el resultado que nos piden y hasta nos sentimos contentos por el tiempo invertido y la gran cantidad de lineas escritas en SQL.

Sin embargo hoy me di cuenta de que por esa via hacemos trabajar mucho mas al SQL Server y esa es la causa de que la consulta tarde más en mostrar el resultado. (sugiero que lean el siguiente artículo: h_tps://www.sqlshack.com/es/planes-de-ejecucion-de-consultas-sql-server-viendo-los-planes/).

Podria decirse que la primera via no es la mas eficiente y debe existir otra via, donde para transponer columnas en un reporte sea mas rapida.

Por esa razon prove a escribir el mismo Query (me refiero a iguales campos y resultados) pero esta vez usando la Funcion PIVOT del SQL Server. La que habia estudiado hace unas a atrás.
Que creen, los resultados fueron asombrosos porque en la segunda via (Consulta con PIVOT) escribí la mitad del codigo y el tiempo ejecución de la consulta fue muchisimo menor. Es por eso que a continuacion les muestro las consultas comparadas.

Ejemplo 1. Se muestra un Query en SQL poco eficiente.
– Muestra el total vendido (con IVA incluido) por clientes y por año, se tienen en cuenta las notas de créditos
– El reporte está basado en las transacciones registradas en el libro mayor (OJDT y JDT1)
– Se utilizan subconsultas para mostrar los totales por año
– Aparentemente está todo bien, pero su ejecución es muy tardada (el resultada demora 37 s)

SELECT 
T0.CardCode 'Código',
T0.CardName 'Nombre_Cliente',

(SELECT SUM(T2.Debit) - sum(T2.Credit) 
FROM JDT1 T2 INNER JOIN OJDT T4 ON T4.TransID = T2.TransID AND Year(T4.Refdate) = 2015
WHERE T2.ShortName = T0.CardCode AND T2.TransType in ('13','14')) AS 'Ventas 2015',

(SELECT SUM(T2.Debit) - sum(T2.Credit) 
FROM JDT1 T2 INNER JOIN OJDT T4 ON T4.TransID = T2.TransID AND Year(T4.Refdate) = 2016
WHERE T2.ShortName = T0.CardCode AND T2.TransType in ('13','14')) AS 'Ventas 2016',

(SELECT SUM(T2.Debit) - sum(T2.Credit) 
FROM JDT1 T2 INNER JOIN OJDT T4 ON T4.TransID = T2.TransID AND Year(T4.Refdate) = 2017
WHERE T2.ShortName = T0.CardCode AND T2.TransType in ('13','14')) AS 'Ventas 2017',

(SELECT SUM(T2.Debit) - sum(T2.Credit) FROM JDT1 T2
INNER JOIN OJDT T4 ON T4.TransID = T2.TransID AND Year(T4.Refdate) = 2018
WHERE T2.ShortName = T0.CardCode AND T2.TransType in ('13','14')) AS 'Sales 2018'

FROM OCRD T0
WHERE T0.CardType = 'C' and T0.validfor='Y'
ORDER By T0.CardCode

Ejemplo 2. Se muestra el mismo Query de manera más eficiente.
– Se muestra el mismo resultado que en el Query anterior pero se usan menos líneas de código SQL y la ejecución toma mucho menos tiempo (el resultada demora 1.5 segundos)
– Elaborado por: Eric Álvarez Consultores IBIZ S.A. de C.V. Fecha: 23/04/2018

With Venta (Código, Nombre_Cliente, Año, Venta) as
(
SELECT 
T0.[ShortName],  
T2.[CardName],  
year (T1.[RefDate]),  
SUM(T0.[Debit]) - SUM(T0.[Credit]) 

FROM JDT1 T0  
INNER JOIN OJDT T1 ON T0.[TransId] = T1.[TransId]
INNER JOIN OCRD T2 ON T0.[ShortName]=T2.[CardCode] 
WHERE T1.[TransType] IN (13,14) and Year (T1.[RefDate] ) between 2015 and 2018 
GROUP BY T0.[ShortName], T2.[CardName], T1.[RefDate] 
)

SELECT * FROM Venta
PIVOT (SUM (Venta) For Año IN ([2015],[2016],[2017],[2018]) ) PIV 
Order By Código

Considero que tambien es Bueno compartir con los demas experiencias donde aprendemos algo nuevo.

7 Me gusta

Esto es una pregunta o un aporte?

Si es pregunta, se queda aquí… si es debate, se mueve a #educacion :+1:

Gracias @anon33106502 !

Pienso que es una pregunta discreta sobre una experiencia para debatir y al mismo tiempo un pequeño aporte o enseñanza, pero quizas hay otras vias de hacer ese mismo query de manera aun mas eficiente. Quiero seguir aprendiendo pero si gustas puedes moverlo a Educación. Yo lo dejaria unos días mas aqui, por si alguien quiere aportar algo mas. Tambien dime como entro a #educacion

1 me gusta

Buen Aporte
Lastimosamente en HANA no existe la funcion PIVOT :frowning:

Buen aporte @anon33106502 :+1:t5:

Buenos días a tod@s!!! pensando en el segundo código ya optimizado, cómo sería el pivot de una manera más dinámica :thinking: es posible?

SELECT * FROM Venta
PIVOT (SUM (Venta) For Año IN ([2015],[2016],[2017],[2018]) ) PIV 
Order By Código

Esta parte, en particular, como lo podría hacer para que quede algo así

SELECT * FROM Venta
PIVOT (SUM (Venta) For Año IN ([YEAR(getdate())-3],[YEAR(getdate())-2],[YEAR(getdate())-1],[YEAR(getdate())]) ) PIV 
Order By Código

Es posible?

Alguien ha realizado algo así?

Saludos a tod@s :raised_hand_with_fingers_splayed:

@andresramirez me mato con que no existe pivot en HANA :astonished:

1 me gusta

De echo no existe PIVOT en HANA jajajaja, creo una de las razones es porque HANA trabaja muy distinto al SQL.

2 Me gusta

Y si, HANA es una estructura más compleja pero más versatil que SQL Server…

Para mi esto es un error, * es un problema serio. Siempre de ser posible evitarlo. Incluso yo en lo personal prefiero hacer vistas y mis reportes linkearlos a las vistas.

Saludos,
David

Busca como hacer pivots dinámicos, esto se hace concatenando en una variable todos los nombres de los campos a pivotar y luego aplicandole una sql dinámico. Es fácil, aunque el código a la primera parezca confuso.

1 me gusta

Excelente aporte!!
Cabalmente HANA no necesita PIVOT, ya que almacena automaticamente columnas adicionalmente a las filas, y hace pivot de toda la base de datos.

1 me gusta

Este tema se cerró automáticamente 91 días después del último post. No se permiten nuevas respuestas.