5

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

项目 ID int
路径文字
输入 int(0 表示文件,1 表示目录)
ParentId int
BackupTime 日期时间

目前该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

我的问题是我似乎找不到有效的方法。上面的查询在大量数据上耗时太长(该表通常包含超过 100K 行)

min(BackupTime)搜索唯一的直接子代可能会更快:

update Items i
set BackupTime = (select min(BackupTime)
                  from Items d
                  where d.ParentId = i.ItemId)
where i.Type = 1

但要做到这一点,我必须确保后代将在其祖先之前更新,因此我必须自下而上递归地遍历层次结构。问题是我没有简单的方法知道哪些项目在层次结构中最深。我正在使用 SQLite,所以我不能使用分层查询。

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

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

4

1 回答 1

1

这是在黑暗中拍摄的,但它可能会奏效。这是一种手动处理自下而上问题的尝试。(我不知道 sqlite 的限制,但这可能是标准 SQL-92 并且希望没问题。)

第 1 步:决定如何处理空目录。我认为这里的解决方案只有在没有空目录或者空目录最初被更新以使其具有人为的非 NULL BackupTime 时才有效。(人为的 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
  )

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

所以第一次运行它时,它将为所有不包含子目录的目录设置 BackupTime,只包含文件。第二次,它将为包含子目录但不包含子子目录的目录设置 BackupTime。

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

于 2012-04-26T22:04:29.707 回答