гарантировать порядок результатов табличной функции

ПРЕДПОСЫЛКА: код приложения нельзя изменить. Условия очень специфичны. Я ищу что-то нестандартное, последнее средство, если позволите.

У меня есть табличная функция (встроенная), которая создает от 2 до 7 записей. Иногда их может быть только 1 или до 15 (но редко).

Функция используется приложением только таким образом, без ORDER BY.

select * from dbo.myfunction(...)

Есть ли какой-либо способ, по вашему опыту, гарантировать (насколько вы когда-либо наблюдали при использовании определенного метода), что результаты возвращаются в порядке второго столбца? Столбцы: varchar(3), datetime, varchar(50). Не заставляйте меня начинать с select *, это НАМЕРЕННО, так что внешний интерфейс будет отображать столько столбцов, сколько я заставлю отображать функцию в будущем.

Исходя из опыта, с одним индексом (кластеризованным PK) для обхода данных любая текущая версия SQL Server и уровень SP должны всегда выполнять простое INDEX SCAN для ‹20 записей без параллелизма, что дает мне упорядоченные результаты в приложении. выберите.

Твои мысли? Я бы предпочел оставить теорию вне обсуждения. Если вы можете придерживаться практического опыта и вести проповеди о лучших практиках дома, я также был бы вам признателен.


ОБНОВЛЕНО Вот как это выглядит сейчас

create function dbo.myfunction(....)
returns @RES table
    (
    [#] int identity primary key clustered,
    [Varchar3Col] varchar(3),
    [DateTimeCol] datetime,
    [Varchar50Col] varchar(50)
    ) as
BEGIN
declare @RES2 table
    (
    rn int,
    [Varchar3Col] varchar(3),
    [DateTimeCol] datetime,
    [Varchar50Col] varchar(50)
    )

insert @RES2
select rn=row_number() over (order by action_time),
    [Varchar3Col]
    [DateTimeCol]
    [Varchar50Col]
from (.....)
inner join (.....) ON (.....)

declare @i int
set @i = 0
while @@rowcount > 0 begin
    set @i=@i+1
    insert @RES
    select [Varchar3Col], [DateTimeCol], [Varchar50Col]
    from @RES2
    where rn=@i
end
return
END
GO
  • Если вы посмотрите на приведенное выше, заполнение @RES выполняется последовательно в желаемом порядке вручную.
  • @RES имеет кластеризованный ПК, представляющий вставленный порядок.
  • столбцы достаточно малы, чтобы 20 строк всегда помещались на одной странице размером 8 КБ.

Будет ли это работать (с простым SELECT на прикладном уровне)?


person RichardTheKiwi    schedule 19.08.2011    source источник
comment
Нет, гарантии нет. Если вам нужна гарантия, добавьте ORDER BY к заявке. Так действует гарантия. Это не проповедь о лучших практиках, это просто правда... оптимизатор запросов может упорядочить ваши результаты любым способом, который он считает наиболее эффективным. И да, это может произойти с 20 строками, и это может измениться при изменении статистики в базовых таблицах, накопительном обновлении, пакете обновления, обновлении и т. д.   -  person Aaron Bertrand    schedule 19.08.2011
comment
может выбрать.. считает.. может случиться. Итак, SQL Server — это компьютерная программа с фиксированными алгоритмами, а не стиральная машина с нечеткой логикой. Так что же он на самом деле делает?   -  person RichardTheKiwi    schedule 19.08.2011
comment
Я не писал оптимизатор, поэтому я не могу сказать вам, что он на самом деле делает. Но я могу сказать вам, что это чрезвычайно сложный фрагмент кода, написанный одними из самых ярких умов на планете. Сомневаюсь, что они расскажут вам, как это работает, потому что именно поэтому SQL Server работает так хорошо, но готов поспорить на коробку пончиков, что они скажут вам то же самое, что и я. НЕ НАДЕЯТЕСЬ НА НАБЛЮДАЕМОЕ ПОВЕДЕНИЕ ЗАКАЗА, ЧТОБЫ ОСТАВАТЬСЯ ПОСТОЯННЫМ. Если вам нужна гарантия, добавьте ORDER BY.   -  person Aaron Bertrand    schedule 19.08.2011
comment
Я полагаю тогда, что ни один программист никогда не использовал недокументированные возможности в Win32 API, учитывая, что MS не дает никаких гарантий? Мне не нужна позолоченная гарантия, а просто какое-то наблюдение черного ящика, подкрепленное опытом или внутренними знаниями для очень конкретной проблемной области. У вас явно нет того, что мне нужно, потому что вы не играли с книгой, поэтому (без неуважения, но) я не думаю, что вы моя целевая аудитория.   -  person RichardTheKiwi    schedule 19.08.2011
comment
Люди все время используют недокументированные вещи, но обычно они понимают риски и не делают никаких гарантий относительно своего поведения (если только они не знают ничего лучше или им все равно). Я просто не понимаю, что такого сложного в добавлении ORDER BY 2 в код вашего приложения. Если бы это было мое приложение, я бы лучше спал по ночам с явной гарантией... и вы могли бы покончить с этим за время, которое вы потратили на создание этого вопроса и принижение любого, кто задает вам вопросы. Получайте удовольствие от своей проблемы.   -  person Aaron Bertrand    schedule 19.08.2011
comment
@Аарон. Допустим, у Джо рак. Врачи (специалисты) констатируют терминальную через 1 месяц и без обращения. Должен ли Джо искать альтернативную медицину/молитву/вуду? Хорошо, я не упомянул, что приложение нельзя изменить. Но вот где я, у меня есть проблема, и я ищу способ обойти ее, недокументированный, негарантированный или что-то еще. Это не всеохватывающий вопрос, а всего лишь один очень конкретный случай и условия. Ценю ваше время на этот вопрос, но если вы чувствуете, что вам нужно бросить мне библии MSSQL, у меня есть подозрение, что я могу выступить против вас в любой другой день.   -  person RichardTheKiwi    schedule 19.08.2011
comment
Ладно, если вы хотите полагаться на поведение, которое, как вы понимаете, не гарантируется, зачем вы задаете вопрос? Вы, кажется, заранее знали, какой будет ответ. Вам нужно решить, стоят ли того последствия… что именно произойдет, когда это приложение, которое делало предположения о порядке, не заявляя об этом явно, вдруг начнет получать результаты в неожиданном порядке?   -  person Aaron Bertrand    schedule 19.08.2011


Ответы (4)


Для встроенного TVF ничего не будет работать. Мало того, встроенный TVF может даже возвращать больше строк, чем вы считаете нужным, и строки будут обрезаны после выполнения TVF (в основном это предикат в определении TVF можно вытащить из TVF и переместить в другое место в дереве запросов). См. T -SQL-функции не подразумевают определенного порядка выполнения, например, это происходит.

Преобразование встроенного TVF в множественный оператор введет некоторый процедурный порядок, поскольку операторы не могут выполняться не по порядку, но результат TVF может быть переупорядочен, отсортирован, разделен, буферизован, в основном искажен сгенерированным оптимизатором планом и в конец сломает ваше предположение о порядке вывода. Боюсь, если у вас должен быть определенный порядок выполнения, курсоры — ваши лучшие друзья.

person Remus Rusanu    schedule 19.08.2011
comment
Я добавил тело функции. Я преобразовал его в составной оператор и использую цикл, чтобы гарантировать порядок вставки (вдоль сгруппированного ПК). Это помогает? - person RichardTheKiwi; 19.08.2011
comment
Можете ли вы представить себе причину, по которой QO переупорядочивает, (пере)сортирует или разделяет результат TVF, содержащий менее 20 записей? - person RichardTheKiwi; 19.08.2011

Просто вам не нравится ответ, который вы слышите? Правда в том, что порядок гарантируется только предложением order by. Это не мнение, это факт. Альтернативы нет, если это гарантия, которую вы ищете.

person mnDBA    schedule 19.08.2011
comment
Я отредактировал вопрос, чтобы лучше отразить причину вопроса. SQLkiwi прочитал правильно. - person RichardTheKiwi; 19.08.2011

Если только одно приложение использует эту функцию именно таким образом, как вы упомянули (поэтому не присоединялись/применялись к другому объекту), это должен был быть sproc! Добавьте предложение order by в запрос, возвращающий данные, чтобы получить набор результатов в определенном порядке.

Всегда есть риск, что ваш fn будет использоваться другим разработчиком, но не так, как вы предполагали, что вызовет проблемы всех видов. Производительность - это то, о чем я бы беспокоился.

person ALZDBA    schedule 19.08.2011

У вас будет больше шансов получить предсказуемый план запроса, если вы будете использовать TVF с одним оператором вместо TVF с несколькими операторами. ROW_NUMBER OVER должен предшествовать желаемому порядку в вашем запросе RES2, а если это не так, просто поместите его в CTE и упорядочите по столбцу с номером строки. Увидеть ниже.

CREATE FUNCTION [dbo].[MyFunction]
(
/*
Parameters
*/
)
RETURNS TABLE
RETURN
WITH res2
(
    rn,
    Varchar3Col,
    DateTimeCol,
    Varchar50Col
)
AS
(
    SELECT
        ROW_NUMBER() OVER (ORDER BY action_time) AS rn,
        Varchar3Col,
        action_time AS DateTimeCol,
        Varchar50Col
    FROM
/*
        [...from statement...]
*/      
)
SELECT
    rn,
    Varchar3Col,
    DateTimeCol,
    Varchar50Col
FROM
    res2
ORDER BY
    rn;
person Slappy    schedule 19.08.2011
comment
Как вы думаете, почему это больше гарантирует сохранение определенного порядка при вызове без порядка, чем tvf с несколькими операторами? Сортировка все еще может повлиять на результат ПОСЛЕ того, как результаты функции были материализованы, поэтому нет никакой гарантии, независимо от того, что находится внутри функции. - person Aaron Bertrand; 19.08.2011
comment
Предложение order by в конце CTE гарантирует порядок, в котором строки возвращаются из функции. Он работает как атомарный оператор, в отличие от итеративных вставок в TVF с несколькими операторами, предложенными в вопросе. Это будет работать более эффективно. - person Slappy; 19.08.2011
comment
Это не гарантируется, если вы просто скажете SELECT * FROM dbo.MyFunction() без ORDER BY. Не знаю, как еще это объяснить. Обратите внимание, что выполнение этого 1000 раз и каждый раз соблюдение одного и того же порядка не означает гарантию. - person Aaron Bertrand; 19.08.2011
comment
ROW_NUMBER() применяет ранжирование номеров строк на основе порядка сортировки, переданного в (action_time). Внутренний оператор называет этот столбец псевдонимом rn. Внешний оператор заказывает rn. Как не гарантируется заказ? - person Slappy; 19.08.2011
comment
Поскольку оптимизатор может пересортировать ВНЕШНИЕ результаты после того, как функция произвела свой вывод. Вам нужен ORDER BY вне функции, если вы хотите, чтобы заказ был гарантирован. Без него вы можете получить желаемый заказ по стечению обстоятельств, но это не гарантируется. Это похоже на то, как TOP 100 PERCENT ... ORDER BY в представлении больше не гарантирует упорядочение, если вы выбираете из представления без упорядочения по, и как GROUP BY сама по себе больше не диктует упорядочение по тем же столбцам, что и GROUP BY. Мы ничего не выдумываем — ваша функция просто не гарантирует порядка. - person Aaron Bertrand; 19.08.2011
comment
Таким образом, он будет игнорировать внешний порядок по предложению? Я никогда не видел такого поведения. Если это правда, то это кажется мне довольно большой ошибкой. - person Slappy; 19.08.2011
comment
Если вы считаете, что ROW_NUMBER гарантирует порядок вывода, прочитайте здесь: stackoverflow.com/questions/1110643/ - person Remus Rusanu; 19.08.2011
comment
Как это ошибка? ORDER BY внутри функции сообщает функции, как упорядочить строки; row_number говорит, как применить значение номера строки, но не обязательно, как будут возвращаться заказы; top...order by аналогичным образом определяет, как выбираются строки, но опять же не гарантирует, что они будут возвращены в том же порядке. Есть еще один уровень: когда вы выполняете SELECT из функции, это является внешним запросом, о котором я говорю, и именно туда должен идти ORDER BY, если вам нужна гарантия. Сортируйте последним или не полагайтесь на него. - person Aaron Bertrand; 19.08.2011