top of page
Search

Cada vez que le digo a alguien que el costo porcentual en el plan de ejecución miente y que no deben confiar en él cuando se está haciendo performance tuning a una consulta, recibo diferentes reacciones / preguntas como:

¡Tú eres el que miente!

¿Puedes probarlo?

¿Por qué lo pusieron si esta mal?

Siempre que recibo esta pregunta, les comparto una publicación hecha por mi amigo Forrest [t,b] . Deberías leer esta publicación antes de ponerte a leer mis locuras, el es mucho más inteligente que yo :)

Aqui esta el post: Percentage Non Grata

Ayer, alguien comenzó a hacer muchas preguntas después de leer el post arriba mencionado, esta persona asegura de que los porcentajes estaban mal porque las estadísticas fueron forzadas, etc. Intenté explicar que el punto principal fue probado, y las estadísticas no son perfectas en un entorno de producción, pero no fue suficiente para convencerlo(s), así que decidí compartir mi pantalla y demostrarlo en una sesión en web.


Aquí hay un script para crear nuestro laboratorio, una tabla y una función (UDF).

--\\Create table
CREATE TABLE [dbo].[UserProfile] (UserID INT  PRIMARY KEY CLUSTERED IDENTITY(1,1)
,AboutMe NVARCHAR(1500) NOT NULL
, MyValue1 INT NOT NULL);
GO
--\\ Insert some data :)
INSERT INTO [dbo].[UserProfile](AboutMe,MyValue1)
SELECT TOP (2000000)    AboutMe= REPLICATE( LEFT(CAST(NEWID() AS VARCHAR(520)), 5), 3)
				,   ROW_NUMBER() OVER (ORDER BY a.name)%3
FROM sys.all_objects a
CROSS JOIN sys.messages c
UNION ALL
SELECT TOP (2000000)    AboutMe= REPLICATE( LEFT(CAST(NEWID() AS VARCHAR(520)), 5), 3)
				,   3
FROM sys.all_objects a
CROSS JOIN sys.messages c;
GO
--\\Create and index to help our query.
CREATE INDEX IX_Value1 ON [dbo].[UserProfile] (MyValue1) WITH FILLFACTOR=100;
GO
--\\ Create scalar function.
CREATE OR ALTER FUNCTION dbo.Total(@MyValue1 INT)  
RETURNS BIGINT  
WITH SCHEMABINDING
AS   
BEGIN    
    DECLARE @Total BIGINT;        
	SELECT @Total=COUNT_BIG(*) 
	FROM [dbo].[UserProfile]
	WHERE MyValue1=@MyValue1;

    RETURN @Total;    
END;
GO

Una vez que la tabla esté lista, ejecutaremos las siguientes consultas, asegúrese de incluir el Plan de ejecución (Actual Execution Plan).

Nota: El nivel de compatibilidad se establecio en 140 (SQL 2017)
--\\ Compare the function and raw query
--\\ Include Actual Execution Plan (Ctrl + M)

SELECT Total=COUNT_BIG(*) 
FROM [dbo].[UserProfile]
WHERE MyValue1=3;

SELECT dbo.Total(3) as Total;

Ambas consultas son idénticas, la misma lógica, los mismos resultados y el mismo número de lecturas, la única diferencia es la función (UDF). ¿Qué pasa con los porcentajes? Serán los mismos?. Por favor vea a continuación ...


SQL Server no puede expandir la lógica detrás de la función (UDF), por lo tanto, los porcentajes están mintiendo

Soy consciente de SQL Server 2019 y Froid, pero seamos honestos, no vamos a actualizar pronto y Froid no va a arreglar todos las funciones (UDF).

Las consultas anteriores no fueron manipuladas, entonces, ¿qué sucede si confundimos un poco a SQL Server?


Ejecutemos estas tres consultas:

SELECT  A.MyValue1
	   ,A.AboutMe
FROM [dbo].[UserProfile] A  
WHERE A.MyValue1=3
ORDER BY A.MyValue1
OPTION(FAST 10); --\\ Give me the first 10 rows as fast as you can.

SELECT TOP (10) A.MyValue1
              , A.AboutMe
FROM [dbo].[UserProfile] A
WHERE A.MyValue1=3
ORDER BY A.MyValue1; --\\ Let SQL server handle.


SELECT TOP (10) A.MyValue1
              , B.AboutMe 
FROM [dbo].[UserProfile] A 
		INNER LOOP JOIN [dbo].[UserProfile] B --\\Forcing Loop Join and selference, expecting SQL Server seeks using cluster and noncluster indexes.
				ON A.UserID= B.UserID
WHERE A.MyValue1=3
ORDER BY A.MyValue1;
  1. Consulta #1, regresa 2,000,000 filas, pero yo le pedí a SQL Server que regresara las primeras 10 filas lo más rápido posible (Query Hint).

  2. Consulta #2, regresa 10 filas, una consulta muy simple y sin trucos.

  3. Consulta #3, regresa 10 filas, he forzado a que se genere un Nested Loop Join con una referencia a si mismo.

Como podras anticipar, los porcentajes mienten nuevamente... Vea más abajo porfavor.

Si tiene alguna pregunta o sugerencia, hágamelo saber en los comentarios.

  • Writer: Victor Escott
    Victor Escott
  • Apr 13, 2019
  • 2 min read

Esta publicación es la segunda parte de una serie sobre operadores de unión física, asegúrese de revisar:


El Nested Loops es uno de los cuatro operadores a cargo de combinar datos y generar un flujo de salida.


El operador Nested Loops es, con mucho, el algoritmo más simple, echemos un vistazo a su apariencia visual.

¿Cómo leer el plan de arriba?

Cada persona tiene su propia forma de leer los planes de ejecución, pero generalmente tenemos que leer los planes de ejecución de derecha a izquierda, siguiendo las flechas de flujo de datos. Por lo tanto, en la imagen de arriba vemos dos flechas de flujos de datos que pasan datos al Nested Loops, la flecha que está en la parte superior se llama Outer Input, la que está en la parte inferior se llama Inner Input, luego a la izquierda de el operador Nested Loops vemos la salida final (los datos combinados).


¿Cómo funciona?

La lógica es muy simple de entender, ya que es como tener dos cursores anidados, el cursor principal son los datos de la entrada externa (Outer Input) y el cursor anidado son los datos de la entrada interna (Inner Input). Entonces, tome el primer valor de la entrada externa (Outer Input) y compárelo con cada valor de la entrada interna (cursor anidado), una vez que se complete el primer bucle, tome el siguiente valor de la entrada externa (Outer Input) y compárelo con cada valor de la entrada interna (Inner Input). en. Por favor ver más abajo.


¿Los bucles anidados pueden hacer Seek?

De hecho, hay varias optimizaciones que permiten que el operador Nested Loops busque directamente las filas, por ejemplo (pero sin limitarse a):

  • Cluster Index

  • Nonclustered Index

  • Spool

¿Te preguntas cómo funciona esto? Por favor ver más abajo.



SQL Server aún tiene que recorrer la entrada externa (Outer Input) una fila a la vez, pero ya no lo hace en la entrada interna (Inner Input), sin embargo, la búsqueda se ejecutó cuatro veces (para cada fila en la entrada externa "Inner Input")


Consideraciones.

  • Si la entrada externa es pequeña (cardinalidad baja) y la entrada interna tiene un bajo costo, entonces el operador Nested Loops será muy eficiente.

  • Los índices correctos permiten buscar a través de la entrada interna.

  • En circunstancias normales, el operador Nested Loops no es un operador que cause bloqueo.

Por último, pero no menos importante, quiero aclarar que el propósito principal de este post es explicar de la manera más simple posible la forma en que el operador Nested Loops funciona, esta es la razón por la que no cubrí otras cosas interesante( Dynamic vs Static Inner inputs, Prefetching, Rebind and Rewinds, etc).


¡Diviértanse aprendiendo!

Updated: Apr 13, 2019

Esta publicación es la primera de una serie sobre operadores de unión física , asegúrese de revisar:

Pensé en saltar directamente para hablar sobre los operadores físicos, pero creo que esta serie merece una buena base.

La Confesión.


Hace algún tiempo, tuve una entrevista en una conocida empresa de tecnología para una posición que parecía ser el trabajo de mis sueños, las responsabilidades para esta posición eran una combinación perfecta (60% de desarrollador de SQL y 40% de desarrollador .NET). Durante la entrevista, hicieron muchas preguntas técnicas sobre .NET, webservices y otras cosas, pero nada relacionado con SQL Server.


Después de varias horas de entrevistas con diferentes personas, el Jefe de Desarrollo entró en la sala de conferencias, me dijo que el equipo de DBA está trabajando en algunas cosas urgentes y que no pueden finalizar la entrevista ese día, pero que le gustaría agendar una llamada telefónica , acepté y me fui del lugar con un papelito que alguien me entregó, era la hora y dia de la entrevista final.


Las tres preguntas.


Al día siguiente, el equipo de DBA me llamó, se disculparon por el día anterior, uno de los DBA me dijo que, en compensación, solo tienen tres preguntas para mí, sonreí y acepté (estaba pensando "pan comido") ... Estaba tan equivocado , juro que nunca olvidaré las dos preguntas que me hicieron, sí, solo dos ya que no llegué a la tercera.


Por favor ve abajo y trata de no reírte demasiado fuerte = P.


DBA: ¿Son malos los scans ? Pregunta #1

Silly Victor: ¡Depende! Sí, lo utilicé y funcionó a la perfección, pero no sabía la respuesta.

DBA: Sí, depende.

DBA: ¿Cuáles son los tres operadores de unión física? Pregunta #2

Silly Victor: Tres?

DBA: Si, tres.

Silly Victor: Inner Join…

DBA: Operadores de unión física!

Silly Victor: Left Join…

DBA: Gracias, Victor, esas son todas las preguntas que tengo para ti. ¿Tienes alguna pregunta para mí?

Silly Victor: No gracias..



la autopsia .


¿Cómo me sentí después de todo?

Una mala entrevista puede hacer que te sientas frustrado y molesto, realmente estaba muy molesto conmigo mismo. Pero esto no fue nada comparado con lo estúpido que me sentí ese día.


¿Por qué he fallado?

Yo no era humilde, pensé que como podía escribir consultas muy complejas, ya había dominado SQL Server.


¿Puedo arreglarlo?

No, no podemos cambiar el pasado, pero podemos evitarlo en el futuro.


¿Cuál fue la tercera pregunta?

No tengo ni idea y no estoy seguro de estar listo para responder a esa pregunta, pero hago lo mejor que puedo todos los días.


Conclusiones.


  • Sé humilde y ayuda a los demás tanto como puedas.

  • Si no sabe la respuesta, por favor, no intente inventar cosas, es mejor decir algo como "No sé, pero estoy dispuesto a aprender".

  • Nunca te rindas, no importa cómo te sientas, por favor nunca te rindas.

  • Sigue aprendiendo, nunca dejas de aprender.

  • SQL Server es una especie de ciencia.

Prometo que en la próxima serie voy a hablar sobre Nested Loop Join.

¡Diviértanse aprendiendo!

© 2018 by Victor Escott.

bottom of page