【问题标题】:Most efficient way to find last record in a hierarchic table在分层表中查找最后一条记录的最有效方法
【发布时间】:2013-12-10 11:54:12
【问题描述】:

我有一个存储论坛帖子的 SQL 表。每条记录都有一个 ParentID,它是另一条记录的 ID。如果为空,则表示它是主论坛线程,因此没有父记录。每个帖子都可以有多个级别的子级。我正在寻找一种能够有效地通过子记录重复查找最后创建的函数(每条记录都有一个“已创建”字段)。

我确实有一个存储过程,它列出了属于特定父级的记录,但它非常占用 CPU,并且在列出主论坛线程和显示最后回复的日期时无法使用。

如果有帮助,这里是表格的基本结构:

CREATE TABLE [dbo].[ForumThreads](
    [ForumThreadID] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
    [ForumID] [numeric](18, 0) NULL,
    [ParentID] [numeric](18, 0) NULL,
    [PostSubject] [nvarchar](500) NULL,
    [PostBody] [nvarchar](max) NULL,
    [Created] [datetime] NULL,
    [CreatedBy] [numeric](18, 0) NULL
);

【问题讨论】:

标签: sql sql-server hierarchy hierarchical-data


【解决方案1】:

我仔细阅读了您的答案并删除了我的第一个答案,因为它是错误的。这是一个带有解决方案的 SQL FIDDLE,其中包括设置和递归 CTE 查询,该查询使用“TopLevelForumID”字段对所有相关论坛进行分组。此查询应该是高效的,但根据您的表统计信息,您可以添加一个 INDEX 以提高响应速度。

SQL Fiddle

添加了标量值函数,可以这样调用:

-- How yo use this Scalar-valued function
--SELECT [ForumThreadID]
--      ,[ForumID]
--      ,[ParentID]
--      ,[PostSubject]
--      ,[PostBody]
--      ,[Created]
--      ,[CreatedBy]
--      ,[dbo].[fn_getLastThread]([ForumID]) AS [LastThread]
--  FROM [dbo].[ForumThreads]

CREATE FUNCTION [dbo].[fn_getLastThread]
(
    @ParentForumID INT
)
RETURNS INT
AS
BEGIN

    DECLARE @Ret INT;

    -- recursive CTE query
    WITH hierarchy AS (

            -- select the parent row
            SELECT  [ForumID],[ParentID],[Created]
            FROM    ForumThreads
            WHERE   [ForumID]=@ParentForumID

            UNION ALL               
            SELECT  A.[ForumID],A.[ParentID],A.[Created]
            FROM    ForumThreads A
            INNER JOIN hierarchy H ON H.[ForumID] = A.[ParentID]
    )
    SELECT      TOP 1 @Ret = [ForumID]
    FROM        hierarchy
    ORDER BY    [Created] DESC
    OPTION      (MAXRECURSION 50); -- specify recursion limit (default is 100 if not specified)

    RETURN @Ret;

END

【讨论】:

  • 当我运行代码时,我收到一条错误消息:“语句已终止。在语句完成之前,最大递归 100 已用尽。”这可能是因为涉及大量数据(撰写本文时为 311572)。我希望有一个以 ParentID 作为参数的内联函数,并且我可以在列出最后 20 个新线程的查询中使用它。不过还是谢谢。
  • 一个函数很容易实现......你期望的最大递归数是多少? SQL Server 允许您指定递归限制以防止它失控,默认为 100。
  • 如果函数返回多行(“表值”函数),您打算如何在单个查询中使用它?您打算对函数进行子查询吗?
  • 如果递归数是指子级别的数量,我预计不会超过 10 个。在表中我肯定有不超过 10 个子级别,我不明白这个错误我正进入(状态。我需要一个标量值函数,它返回最后发布的孩子/孙子的 id,然后我可以使用连接来获取我需要的数据(发布日期、发布人......等等)
  • 谢谢,大卫。我正在使用这个查询,我只需要显示最后 20 个帖子,因此该函数一次不会用于超过 20 行。尽管如此,我还是设法通过在读取FROM ForumThreads A INNER JOIN hierarchy H ON H.[ForumID] = A.[ParentID] 的部分之后添加WHERE (A.ForumThreadID>=@ParentForumID) 来大大加快该功能,因为它必须重复出现的子记录总是在父线程之后创建。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多