2012-04-26 54 views
5

我有一個代表的文件和目錄層次結構的數據庫表的大規模更新,具有以下結構(簡化)的有效算法,它被設置爲空目錄。的爲層次表

現在我需要爲目錄填充此列:它必須是所有後代(文件和目錄)的最小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 

我的問題是,我似乎無法找到一個有效的方法。上面的查詢時間太長對大量數據(此表通常包含超過10萬行)

它可能會更快搜索僅在min(BackupTime)直接孩子:

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

但對於這爲了工作,我必須確保後代會在他們的祖先之前更新,所以我必須從下往上遞歸地進行分級。問題是我沒有簡單的方法來知道哪些項目是最深層次的。我正在使用SQLite,所以我不能使用分層查詢。

有關如何有效地做到這一點的任何想法?

理想情況下,我寧願能做到在一個UPDATE查詢,但如果這是不可能的,我開放給其他的選項,只要它們是有效的

回答

1

這是一個鏡頭在黑暗中,但它可能工作。這是一個嘗試手動處理自下而上的問題。 (我不知道sqlite的限制,但這可能是標準的SQL-92,希望可以。)

步驟1:決定如何處理空目錄。我認爲這裏的解決方案只適用於沒有空目錄或空目錄最初更新的情況,因此它們具有人爲的非NULL備份時間。 (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爲空,他們不包含BackupTime值也爲空的子目錄。

因此,您第一次運行此操作時,它將爲所有不包含子目錄的目錄(僅包含文件)設置備份時間。第二次,它將爲包含子目錄但沒有子子目錄的目錄設置備份時間。

您可以通過將BackupTime設置爲合併((select ...),current_timestamp)來處理空目錄問題。

+0

謝謝,我會試一試! – 2012-04-26 22:47:32

+0

好吧,花了5秒鐘處理一個有100000個項目的數據庫......這非常好;)。我嘗試了一個「虛擬」數據庫,所以我需要確定一個真實的數據庫,但我相信它會有類似的性能。順便說一下,'not exists'的最後一個條件是沒有必要的:如果有null,'min'將返回null,所以它最終會得到相同的結果,迭代次數更少(14次而不是27次) – 2012-04-26 23:38:58

+0

如果* only *值爲NULL,MIN將返回NULL。如果NULL和其他值彙總,MIN不會返回NULL。 NOT EXISTS是需要保證迭代從下到上的。如果你刪除NOT EXISTS,你會得到錯誤的結果!假設/ dir1 /包含兩個項目 - 1)具有BackupTime 4/12的文件和2)包含具有備份時間4/9的1個文件的目錄/ dir2 /。如果沒有NOT EXISTS,在第一次迭代期間/ dir1 /將得到不正確的4/12的備份時間。不存在,它會等到下一次迭代。您看到的迭代次數越少,這些錯誤答案就越多。 – 2012-04-27 00:49:17