У меня есть простой скрипт, который получает четыре случайных числа (от 1 до 4), а затем присоединяется обратно, чтобы получить соответствующий номер database_id. Когда я запускаю скрипт с LEFT JOIN, я каждый раз получаю четыре строки назад (ожидаемый результат). Однако, когда я запускаю его с INNER JOIN, я получаю различное количество строк - иногда две, иногда восемь.
Логически, не должно быть никакой разницы, потому что я знаю, что строки с database_ids 1-4 существуют в sys.databases. И поскольку мы выбираем из таблицы случайных чисел с четырьмя строками (в отличие от присоединения к ней), никогда не должно быть больше четырех строк.
Это происходит как в SQL Server 2012, так и в 2014 году. Что заставляет INNER JOIN возвращать различное количество строк?
/* 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;
источник
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()) ;
я думаю, что это работает нормально, потому что нет соединения со значением недетерминированной функции.Ответы:
Добавляя дополнительный SELECT, он толкает вычисленную скалярную оценку глубже в план и дает предикат соединения, вычисляющий скаляр вверху затем ссылается на предыдущий.
До сих пор выясняю, почему он так поздно это делает, но сейчас читаю этот пост Пола Уайта ( https://sql.kiwi/2012/09/compute-scalars-expressions-and-execution-plan-performance.html ) , Возможно, это как-то связано с тем, что NEWID не является детерминированным?
источник
Это может дать некоторое представление, пока один из более умных людей на сайте не вмешивается.
Я помещаю случайные результаты во временную таблицу и получаю 4 результата независимо от типа соединения.
Если я сравню планы запросов между вашим вторым запросом и вариантом с табличной переменной, я вижу, что между ними есть определенная разница. Красный X -
No Join Predicate
это то, что кажется странным моему мозгу разработчика пещерЕсли я исключу случайный бит запроса из константы
1 % (4)
, мой план будет выглядеть лучше, но Compute Scalar был исключен, так что я поближе посмотрелЭто вычисление выражения для случайного числа после объединения. Будь это ожидаемо, я все же оставляю внутренним мастерам на сайте, но, по крайней мере, поэтому вы получаете переменные результаты в своем объединении.
2014
Для тех, кто играет дома, вышеуказанные планы запросов были сгенерированы из экземпляра 2008 R2. Планы на 2014 год выглядят иначе, но операция Compute Scalar остается после объединения.
Это план запроса на 2014 год с использованием константного выражения.
Это план запроса для экземпляра 2014 с использованием выражения newid.
Это, по-видимому, является намерением, проблема подключения здесь. Спасибо @paulWhite за знание того, что существовало.
источник