Tengo un script simple que obtiene cuatro números aleatorios (1 a 4) y luego se une para obtener el número correspondiente de database_id. Cuando ejecuto el script con un LEFT JOIN, obtengo cuatro filas cada vez (el resultado esperado). Sin embargo, cuando lo ejecuto con un INNER JOIN, obtengo un número variable de filas, a veces dos, a veces ocho.
Lógicamente, no debería haber ninguna diferencia porque sé que existen filas con database_ids 1-4 en sys.databases. Y debido a que estamos seleccionando de la tabla de números aleatorios con cuatro filas (en lugar de unirlas), nunca debería haber más de cuatro filas devueltas.
Esto sucede tanto en SQL Server 2012 como en 2014. ¿Qué está causando que INNER JOIN devuelva un número variable de filas?
/* Works as expected -- always four rows */
SELECT rando.RandomNumber, d.database_id
FROM
(SELECT 1 + ABS(CHECKSUM(NEWID())) % (4) AS RandomNumber
FROM sys.databases WHERE database_id <= 4) AS rando
LEFT JOIN sys.databases d ON rando.RandomNumber = d.database_id;
/* Returns a varying number of rows */
SELECT rando.RandomNumber, d.database_id
FROM
(SELECT 1 + ABS(CHECKSUM(NEWID())) % (4) AS RandomNumber
FROM sys.databases WHERE database_id <= 4) AS rando
INNER JOIN sys.databases d ON rando.RandomNumber = d.database_id;
/* Also returns a varying number of rows */
WITH rando AS (
SELECT 1 + ABS(CHECKSUM(NEWID())) % (4) AS RandomNumber
FROM sys.databases WHERE database_id <= 4
)
SELECT r.RandomNumber, d.database_id
FROM rando AS r
INNER JOIN sys.databases d ON r.RandomNumber = d.database_id;
sql-server
t-sql
Doug Lane
fuente
fuente
SELECT TOP (4) d.database_id FROM sys.databases AS d CROSS JOIN (VALUES (1),(2),(3),(4)) AS multi (i) WHERE d.database_id <= 4 ORDER BY CHECKSUM(NEWID()) ;
supongo que funciona bien porque no hay una unión en el valor de la función no determinista.Respuestas:
Al agregar el SELECT adicional, empuja la evaluación escalar de cálculo más profundamente en el plan y le da el predicado de unión, el escalar de cálculo en la parte superior luego hace referencia al anterior.
Todavía estoy investigando por qué espera tan tarde para hacerlo, pero actualmente leyendo esta publicación de Paul White ( https://sql.kiwi/2012/09/compute-scalars-expressions-and-execution-plan-performance.html ) . ¿Quizás tiene algo que ver con el hecho de que NEWID no es determinista?
fuente
Esto podría dar una idea hasta que una de las personas más inteligentes del sitio intervenga.
Puse los resultados aleatorios en una tabla temporal y constantemente obtengo 4 resultados independientemente del tipo de combinación.
Si comparo planes de consulta entre su segunda consulta y la variación con una variable de tabla, puedo ver que hay una diferencia definitiva entre las dos. La X roja es
No Join Predicate
muy extraña para mi cerebro desarrollador de cavernícolasSi elimino el bit aleatorio de la consulta a una constante
1 % (4)
, mi plan se ve mejor, pero se eliminó Compute Scalar, lo que me llevó a mirar más de cercaEstá calculando la expresión para el número aleatorio después de la unión. Ya sea que eso sea esperado, aún dejo a los asistentes internos en el sitio, pero al menos es por eso que obtienes resultados variables en tu unión.
2014
Para aquellos que juegan en casa, los planes de consulta anteriores se generaron a partir de una instancia de 2008 R2. Los planes de 2014 se ven diferentes, pero la operación Compute Scalar permanece después de la unión.
Este es el plan de consulta para un 2014 usando la expresión constante
Este es el plan de consulta para una instancia de 2014 utilizando la expresión newid.
Esto aparentemente es por diseño, conecte el problema aquí. Gracias a @paulWhite por saber que existía.
fuente