用于批量更新分层表的有效方法

Tho*_*que 5 sql optimization performance hierarchy hierarchical-data

我有一个数据库表,表示文件和目录的层次结构,具有以下结构(简化):

ItemId        int
Path          text
Type          int        (0 for files, 1 for directories)
ParentId      int
BackupTime    datetime

目前该BackupTime列仅用于文件,目录设置为null.

现在我需要为目录填充此列:它必须是BackupTime所有后代(文件和目录)中的最小值.

这个(天真和低效)的查询说明了我想要做的事情:

update Items i
set BackupTime = (select min(BackupTime)
                  from Items d
                  where d.Path like i.Path || '%'
                  and d.Type = 0)
where i.Type = 1
Run Code Online (Sandbox Code Playgroud)

我的问题是我似乎找不到有效的方法.上面的查询对大量数据需要太长时间(此表通常包含超过100K行)

min(BackupTime)只搜索直接孩子可能会更快:

update Items i
set BackupTime = (select min(BackupTime)
                  from Items d
                  where d.ParentId = i.ItemId)
where i.Type = 1
Run Code Online (Sandbox Code Playgroud)

但为了实现这一点,我必须确保后代将在他们的祖先之前更新,所以我必须从下往上递归地遍历层次结构.问题是我没有简单的方法知道哪些项目是层次结构中最深的.我正在使用SQLite,所以我不能使用分层查询.

有关如何有效地做到这一点的任何想法?

理想情况下,我希望能够在单个UPDATE查询中执行此操作,但如果不可能,我会对其他选项开放,只要它们有效

Ste*_*ass 1

这是在黑暗中进行的尝试,但它可能会起作用。这是手动处理自下而上问题的尝试。(我不知道 sqlite 的限制,但这可能是标准 SQL-92,希望没问题。)

第 1 步:决定如何处理空目录。我认为这里的解决方案仅在没有空目录或空目录最初更新时才有效,因此它们具有人为的非空备份时间。(人工的 BackupTime 应该是什么可能很重要,具体取决于数据发生更改时如何维护 BackupDate 列。使用当前日期或人工的未来日期可能有效,但您应该考虑一下。)

步骤 2. 重复执行以下查询,直到没有更多行受到影响:

  update Items i set
    BackupTime = (
      select min(BackupTime)
      from Items d
      where d.ParentId = i.ItemId
    )
  where i.Type = 1
  and i.BackupTime is null
  and not exists (
    select *
    from Items d
    where d.ParentId = i.ItemId
    and d.Type = 1
    and d.BackupTime is null
  )
Run Code Online (Sandbox Code Playgroud)

换句话说,当您需要并且还拥有所有信息时更新目录的 BackupTime:当它们的 BackupTime 为 null 并且它们不包含 BackupTime 值也为 null 的子目录时。

因此,第一次运行此命令时,它将为所有不包含子目录、仅包含文件的目录设置 BackupTime。第二次,它将为包含子目录但不包含子子目录的目录设置BackupTime。

您也许可以通过将 BackupTime 设置为 coalesce((select...),current_timestamp) 来处理空目录问题。