保证表值函数结果的顺序

发布于 2024-11-30 11:41:43 字数 1512 浏览 0 评论 0原文

前提:应用程序代码无法更改。条件非常具体。我正在寻找一些书外的东西,如果可以的话,这是最后的解决方法。

我有一个表值函数(内联),可以生成 2 到 7 条记录。有时可能只有 1 个或最多 15 个(但很少)。

该函数仅由应用程序以这种方式使用,无需任何 ORDER BY。

select * from dbo.myfunction(...)

根据您的经验,是否有任何方法可以保证确保(就您使用特定技术观察到的情况而言)结果按第二列排序返回?列有:varchar(3)、日期时间、varchar(50)。 不要让我开始select *,这是故意的,这样前端就会显示我将来让函数显示的多少列。

根据经验,使用单个索引(聚簇 PK)来遍历数据,任何当前版本的 SQL Server 和 SP 级别都应该始终对 <20 条记录执行简单的 INDEX SCAN,而不需要并行性,从而在选择应用程序。

你的想法是什么?我宁愿不讨论理论。如果您能坚持实践经验并在家中讲授最佳实践,我也将不胜感激。


已更新 这就是现在的样子

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。
  • 列足够小,单个 8K 页面中应始终容纳 20 行。

这可行吗(使用应用程序层中的直接 SELECT)?

PREMISE: The application code cannot be changed. The conditions are very specific. I am looking for something off the books, a last resort workaround if you may.

I have a table-valued function (inline) that produces between 2 and 7 records. At times it could be only 1 or up to 15 (but rarely).

The function is only used by an application in this way, without any ORDER BY.

select * from dbo.myfunction(...)

Is there any way at all, in your experience, to guarantee ensure (as far as you have ever observed using a particular technique) that the results are returned ordered by the second column? Columns are: varchar(3), datetime, varchar(50).
Don't get me started on select *, it is INTENTIONAL so that the front end will display however many columns I make the function display in the future.

From experience, with a single index (clustered PK) to traverse the data, any current version of SQL Server and SP level should always perform a simple INDEX SCAN on <20 records without parallelism, thereby giving me ordered results in the application select.

Your thoughts? I would prefer to keep theory out of the discussion. If you can stick to practical experience and keep sermons about best practice at home, I would also appreciate it.


UPDATED
This is what it looks like now

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
  • If you look at the above, the population of @RES is done sequentially in the order desired, manually.
  • @RES has a clustered PK representing the order inserted.
  • the columns are small enough that 20 rows should always fit in a single 8K page

Would this work (with the straightforward SELECT from the application layer)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

猫烠⑼条掵仅有一顆心 2024-12-07 11:41:43

对于内联 TVF 来说,没有什么能真正起作用。不仅如此,内联 TVF 甚至可能返回比您想象的更多的行,并且在执行 TVF 后这些行将被修剪(基本上是 TVF 定义中的谓词)可以从 TVF 中拉出并移动到查询树中的其他位置)。请参阅 T -SQL 函数并不暗示特定的执行顺序 作为发生这种情况的示例。

将内联 TVF 转换为多语句将引入一些过程顺序,因为语句不能无序执行,但 TVF 结果可能会被重新排序、排序、拆分、假脱机,基本上被优化器生成的计划破坏,并且在最后打破了你对输出顺序的假设。恐怕如果您必须有一定的执行顺序,那么游标是您最好的朋友。

For an inline TVF nothing will really work. Not only that, the inline TVF may even return more rows than you believe it should, and the rows will be trimmed after the TVF executed (basically a predicate in the TVF definition can be pulled out of the TVF and moved somewhere else in the query tree). See T-SQL functions do no imply a certain order of execution for an example of this happening.

Converting the inline TVF to a multi statement one will introduce some procedural order, since the statements cannot be executed out of order, but the TVF result may be re-ordered, sorted, split, spooled, basically mangled by the optimizer generated plan and in the end break your assumption about output order. I'm afraid if you must have a certain order of execution, cursors are your best friend.

油焖大侠 2024-12-07 11:41:43

难道只是因为您不喜欢听到的答案吗?事实上,只有 order by 子句才能保证顺序。这不是意见,这是事实。如果这是您正在寻找的保证,那就别无选择。

Is it just that you don't like the answer you are hearing? Truth is, order is only guaranteed with an order by clause. It's not an opinion, it is fact. There is no alternative if it is a guarantee you are looking for.

驱逐舰岛风号 2024-12-07 11:41:43

如果只有一个应用程序正在使用该函数,按照您提到的这种特殊方式(因此没有加入/应用于另一个对象),这应该是一个存储过程!
在数据返回查询中添加 order by 子句,以按特定顺序接收结果集。

您的 fn 始终存在被其他开发人员使用的风险,但不是按照您预期的方式使用,从而导致各种问题。性能是我担心的一个。

If only a single app is using the function, in this particular way as you mentioned ( so not joined/applied to another object) this should have been a sproc !
Add an oder by clause to the data returning query to receive the result set in a particular order.

There is always a risk your fn will be used by another dev, but not in the way you intended it to be used, causing issues of all kind. Performance being the one I would be worried about.

岁月静好 2024-12-07 11:41:43

如果您使用单语句 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;

You'll have a better shot at a predictable query plan if you use a single-statement TVF instead of a multistatement TVF. ROW_NUMBER OVER should enfore the ordering you want in your RES2 query, and if it doesn't, just put it inside a CTE and order by your row number column. See below.

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文