гарантийный порядок результатов табличных функций - PullRequest
0 голосов
/ 19 августа 2011

ПОМЕЩЕНИЕ : Код приложения не может быть изменен. Условия очень специфичны. Я ищу что-то по книгам, в крайнем случае, если можете.

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

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

select * from dbo.myfunction(...)

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

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

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


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

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 имеет кластеризованный PK, представляющий вставленный порядок.
  • столбцы достаточно малы, чтобы 20 строк всегда помещались на одной 8K-странице

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

Ответы [ 5 ]

7 голосов
/ 19 августа 2011

Возможно, вопрос должен был быть:

Что я могу сделать, чтобы поощрить упорядоченные результаты, учитывая, что я невозможно изменить приложение для добавления предложения ORDER BY? "

Запрашиваемая гарантия (как и в оригинальном вопросе) должна всегда давать правильный ответ: без внешней оговорки ORDER BY гарантии нет.

Один из способов проиллюстрировать отсутствие гарантии - посмотреть на просмотр кластеризованного индекса возвращаемой табличной переменной в плане запроса. Без условия ORDER BY свойство Ordered показывает False. Это означает, что механизмы выполнения запросов и хранилища могут создавать строки в любом порядке. Например, для хранилища может быть иногда удобно проходить кластеризованный индекс в обратном порядке ключей во время выполнения. Атрибут направления сканирования отсутствует, если свойство Ordered имеет значение False.

Добавление предложения ORDER BY изменит план, минимально установив для свойства Ordered при сканировании индекса значение True, а для направления сканирования - FORWARD. Это вместе с другими гарантиями и инвариантами в коде гарантирует, что строки будут возвращены клиенту, упорядоченному указанным способом.

Эти гарантии могут влиять на все, начиная с того, как сохраняется порядок после его установления, от того, сканируется ли индекс вперед или назад, используются ли асинхронные или синхронные методы, и как пакеты упаковываются для передачи по сети.

Для ясности, Ordered:True при индексном сканировании само по себе недостаточно. План запроса - это абстракция структуры кода, которая фактически выполняется - его не следует воспринимать буквально. Никто без доступа к исходному коду и необходимого навыка не может дать никаких гарантий сверх того, что задокументировано.

Итак, оставив в стороне тот факт, что вопрос некорректен, вы сделали все, что могли, чтобы поощрить сохранение заказа у клиента? Наверное. Возможно. Кто знает?

7 голосов
/ 19 августа 2011

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

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

2 голосов
/ 19 августа 2011

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

0 голосов
/ 19 августа 2011

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

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

0 голосов
/ 19 августа 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;
...