RAND()
функция - постоянная времени выполнения в SQL Server. Это означает, что обычно оценивается один раз для запроса. Когда вы передаете значение в RAND
, это значение служит начальным начальным числом.
Вам нужно изучить план выполнения, и вы увидите, куда оптимизатор ставит оценку функций. В случае, который не дает ожидаемого результата, скорее всего оптимизатор оптимизировал его слишком агрессивно и переместил всю «случайность» за пределы цикла.
Также нет смысла переносить NEWID()
в CHECKSUM()
и RAND()
.
Простого NEWID()
достаточно. Или, что еще лучше, функция, предназначенная для создания случайного числа, например CRYPT_GEN_RANDOM()
Любая версия вашего запроса выглядит немного странно. Я бы написал так:
SELECT c, id INTO #R
FROM #S
CROSS APPLY
(
SELECT TOP(100) -- or #S.SomeField instead of 100
id
FROM #T
ORDER BY CRYPT_GEN_RANDOM(4) -- generate 4 random bytes, usually it is enough
) AS t
;
Это дает 100 случайных строк из #T
для каждой строки из #S
.
На самом деле, приведенный выше запрос не очень хорош. Оптимизатор снова видит, что внутренний запрос (внутри CROSS APPLY
) не зависит от внешнего запроса, и оптимизирует его.
Конечным результатом является то, что случайные строки выбираются только один раз.
Нам нужно что-то, чтобы оптимизатор запускал внутренний запрос для каждой строки из #S
.
Один из способов будет примерно таким:
SELECT c, id INTO #R
FROM #S
CROSS APPLY
(
SELECT TOP(100) -- or #S.SomeField instead of 100
id
FROM #T
ORDER BY CRYPT_GEN_RANDOM(4) + CHECKSUM(c)
) AS t
;
Что-то во внутреннем запросе для ссылки на строку из внешнего запроса. Если вместо постоянной TOP(100)
поставить TOP(#S.SomeField)
, то + CHECKSUM(c)
не требуется.
Это план для первого варианта. Вы можете видеть, что #T
сканируется один раз (читается 1000 строк).

Это план для второго варианта. Вы можете видеть, что #T
сканируется дважды (считывается 2000 строк).
