TOP
без ORDER BY
не является детерминированным.
Это просто означает «Выбрать любые 10 записей».Таким образом, вы выбираете произвольный набор из 10 результатов из запроса 1 и произвольный набор из 10 записей из запроса 2, а затем упорядочиваете эти 20 записей по имени.
Какой TOP 10
в итоге вы получите, зависит от выбранного плана(что может отличаться в хранимой процедуре) Вам необходимо добавить порядок (для набора столбцов без связей) к каждому запросу, чтобы сделать его детерминированным.
Ваш текущий запрос похож на
SELECT TOP 10 *
FROM master..spt_values
UNION ALL
SELECT TOP 10 *
FROM master..spt_values
ORDER BY name
Вы видите, что SQL Server просто добавляет итератор TOP
в обе ветви плана, чтобы ограничитьвывод обоих запросов, затем они поступают в Союз, и после этого происходит сортировка по имени.Для этого SQL Server выбрал сканирование кластеризованного индекса, поэтому результаты, скорее всего, будут ТОП-10 в порядке кластеризованного индекса type,number,name
(хотя на это не следует полагаться и без указанного порядка, чтобы указать, к чему относится TOP
любой набор из 10 строк будет действительным. Было бы совершенно правильно использовать здесь функцию расширенного сканирования и дать вам произвольные 10 строк, которые, как он знает, находятся в кэше какони были только что прочитаны при сканировании другого запроса.)
Чтобы переписать запрос с TOP...ORDER BY
, указанным для каждого элемента, вы можете использовать CTE, как показано ниже.
;WITH Query1 AS
(
SELECT TOP 10 *
FROM master..spt_values
ORDER BY name,number,type
), Query2 AS
(
SELECT TOP 10 *
FROM master..spt_values
ORDER BY number,type,name
)
SELECT *
FROM Query1
UNION ALL
SELECT *
FROM Query2
ORDER BY name