视图与函数来获取表的顶部记录?

Bri*_*hak 6 sql-server view functions

我正在和一位同事讨论解决问题的方法。

我们有一个表来跟踪填充过程,该表在列Lot和上具有唯一的索引列(或至少应该) TestGrade

最近,我们添加了逻辑,以便当TestGrade创建大于 1 的任何值时,所有较低级别都会被创建。完成了一些逻辑,因此较低级别的行不一定与顶层相同。

例如,我插入一些东西Lot='ABCD'TestGrade=5然后在我的Fills表中我看到

id    Lot    TestGrade   OtherColumns
======================================
10    'ABCD'     1          blah3
9     'ABCD'     2          bar
8     'ABCD'     3          foo
7     'ABCD'     4          blah1
6     'ABCD'     5          blah
Run Code Online (Sandbox Code Playgroud)

现在的问题是在许多情况下,我只想要 Fills 表的顶级记录,因此在示例中,我只想要带有id=6.

关于如何做到这一点,我们有两个想法。我想做一个看起来像

CREATE VIEW [dbo].[vwFills]
AS
SELECT t.* FROM [dbo].[Fills] t
JOIN (SELECT [Lot], MAX(TestGrade) as TestGrade FROM dbo.Fills GROUP BY [Lot]) t2 ON t.[Lot] = t2.[Lot] AND t.[TestGrade] = t2.[TestGrade]
Run Code Online (Sandbox Code Playgroud)

我的同事想做类似的事情,但在一个看起来像这样的函数内

ALTER FUNCTION [dbo].[fnFills] (
 @Fills tyFills READONLY
 )
RETURNS @returnTable TABLE(
//Copy of the table definition of Fills, without
    id INT NOT NULL,
    Lot VARCHAR(10) NOT NULL,
    TestGrade INT NOT NULL,
    //rest of the columns..
    )
AS

Begin

insert into @returnTable
    select t2.* from (
        select [Lot], max([TestGrade]) as TestGrade from @Fills) t1
            left join Fills t2
            on t1.[Lot] = t2.[Lot] and t1.[TestGrade] = t2.[TestGrade]

Return

End
Run Code Online (Sandbox Code Playgroud)

然后调用这个函数,它看起来像

DECALARE @FillRecords tyFills;
INSERT INTO @FillRecords SELECT * FROM db.Fills;
SELECT * FROM dbo.fnFills(@FillRecords);
Run Code Online (Sandbox Code Playgroud)

我们确实在和dbo.Fills上有索引。然而,我的直觉是,使用插入变量然后将其提供给函数的函数方法,我们会丢失这些索引,因此通过此连接,我们将看到 O(n^2) 性能。这是一个公平的评价吗?我担心性能,因为服务器的硬件并不强大,因此任何有助于查询执行的东西都是首选。LotTestGrade

一般来说,在这种情况下,是否有最佳实践方法——视图或函数是“显而易见的”还是更好的选择?

Eri*_*ost 2

你的直觉是对的。风景就是必经之路。该函数除了简单的 SELECT 语句之外不执行任何其他操作,根本不涉及过程逻辑。

也可以使用函数,但最好将其定义为内联表值函数:

CREATE FUNCTION dbo.fnFills()
RETURNS TABLE
RETURN(
SELECT t.* 
FROM [dbo].[Fills] t
JOIN (SELECT [Lot], MAX(TestGrade) as TestGrade FROM dbo.Fills GROUP BY [Lot]) t2 ON t.[Lot] = t2.[Lot] AND t.[TestGrade] = t2.[TestGrade]
);
Run Code Online (Sandbox Code Playgroud)

这里很好地解释了表值函数和内联表值函数之间的区别。

但在这种情况下,该函数并没有比视图有任何优势,所以我会坚持使用良好的旧视图。

注意:我按原样接受了您的查询,但避免使用“SELECT *”语句被认为是最佳实践。