Eu tenho um script simples que obtém quatro números aleatórios (1 a 4) e depois se junta novamente para obter o número database_id correspondente. Quando executo o script com LEFT JOIN, recebo quatro linhas sempre (o resultado esperado). No entanto, quando o executo com um INNER JOIN, recebo um número variável de linhas - às vezes duas, às vezes oito.
Logicamente, não deve haver nenhuma diferença, porque eu sei que existem linhas com database_ids 1-4 no sys.databases. E como estamos selecionando da tabela de números aleatórios com quatro linhas (em vez de ingressar nela), nunca deve haver mais do que quatro linhas retornadas.
Isso acontece no SQL Server 2012 e 2014. O que está fazendo com que o INNER JOIN retorne vários números de linhas?
/* 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
fonte
fonte
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()) ;
acho que funciona bem porque não há junção no valor da função não determinística.Respostas:
Ao adicionar o SELECT adicional, ele aprimora a avaliação escalar de computação no plano e fornece o predicado de junção; o escalar de computação na parte superior faz referência à anterior.
Ainda procurando por que demora tanto para fazê-lo, mas atualmente lendo este post de Paul White ( https://sql.kiwi/2012/09/compute-scalars-expressions-and-execution-plan-performance.html ) . Talvez tenha algo a ver com o fato de o NEWID não ser determinístico?
fonte
Isso pode dar algumas dicas, até que uma das pessoas mais inteligentes do site faça a diferença.
Coloco os resultados aleatórios em uma tabela temporária e recebo consistentemente 4 resultados, independentemente do tipo de associação.
Se eu comparar planos de consulta entre sua segunda consulta e a variação com uma variável de tabela, posso ver que há uma diferença definida entre as duas. O X vermelho é
No Join Predicate
tão estranho para o meu cérebro desenvolvedor de homens das cavernasSe eu eliminar o bit aleatório da consulta para uma constante
1 % (4)
, meu plano parecerá melhor, mas o Escalar de computação foi eliminado, o que me levou a olhar mais de pertoEstá computando a expressão para o número aleatório após a junção. Se isso é esperado, ainda deixo para os assistentes internos do site, mas pelo menos é por isso que você está obtendo resultados variáveis em sua associação.
2014
Para aqueles que tocam em casa, os planos de consulta acima foram gerados a partir de uma instância do 2008 R2. Os planos de 2014 parecem diferentes, mas a operação de computação escalar permanece após a associação.
Este é o plano de consulta para um 2014 usando a expressão constante
Este é o plano de consulta para uma instância de 2014 usando a expressão newid.
Aparentemente, isso ocorre por design, problema do Connect aqui. Agradecemos a @paulWhite por saber que existia.
fonte