Sql 一种有效的分层表批量更新方法

Sql 一种有效的分层表批量更新方法,sql,performance,optimization,hierarchy,hierarchical-data,Sql,Performance,Optimization,Hierarchy,Hierarchical Data,我有一个数据库表,它表示文件和目录的层次结构,简化了以下结构: ItemId int Path text Type int (0 for files, 1 for directories) ParentId int BackupTime datetime 我的问题是我似乎找不到一个有效的方法。上面的查询对大量数据占用的时间太长。此表通常包含超过10万行 仅在直接子对象上搜索minBackupTime可能会更快: up

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

ItemId int Path text Type int (0 for files, 1 for directories) ParentId int BackupTime datetime 我的问题是我似乎找不到一个有效的方法。上面的查询对大量数据占用的时间太长。此表通常包含超过10万行

仅在直接子对象上搜索minBackupTime可能会更快:

update Items i
set BackupTime = (select min(BackupTime)
                  from Items d
                  where d.ParentId = i.ItemId)
where i.Type = 1
但为了让这项功能发挥作用,我必须确保子代将在其祖先之前更新,因此我必须从下到上递归地遍历层次结构。问题是我没有简单的方法知道哪些项目是层次结构中最深的。我使用的是SQLite,所以不能使用分层查询

你知道如何有效地做到这一点吗


理想情况下,我更希望能够在一个更新查询中完成这项工作,但如果不可能,我愿意接受其他选项,只要它们是有效的

这是一个暗中操作,但它可能会起作用。这是一种手动处理自下而上问题的尝试。我不知道sqlite的局限性,但这可能是标准的SQL-92,希望还可以

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

第二步。重复执行以下查询,直到不再影响其他行:

  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
  )
换言之,在需要时更新目录的备份时间,并且还拥有所有信息:当目录的备份时间为null且不包含备份时间值也为null的子目录时

因此,第一次运行此程序时,它将为所有不包含子目录、仅包含文件的目录设置备份时间。第二次,它将为包含子目录但没有子目录的目录设置备份时间


您可以通过将BackupTime设置为coalesceselect…,current_timestamp来处理空目录问题。

OK,处理一个包含100000个项目的数据库需要5秒钟。。。那很好;。我尝试了一个虚拟数据库,所以我需要用一个真实的数据库来确认,但我相信它会有类似的性能。顺便说一句,不存在的最后一个条件是不必要的:如果有null,min将只返回null,因此它最终将给出相同的结果,在我的testMIN中,迭代次数减少14次而不是27次,如果唯一的值为null,min将返回null。如果聚合了NULL和其他值,则MIN不会返回NULL。需要NOT EXISTS来保证迭代自下而上进行。如果删除“不存在”,则会得到错误的结果!假设/dir1/包含两项—1是备份时间为4/12的文件,2是包含备份时间为4/9的文件的目录/dir2/。如果不存在,则在第一次迭代期间,/dir1/将获得不正确的备份时间4/12。如果不存在,它将等待下一次迭代。你看到的迭代次数越少,说明这些错误答案。你是对的,我错了。。。我想我已经很久没有做任何严肃的SQL了;
  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
  )