2011-11-10 49 views
4

我用的Mnesia來存儲用戶的數據和記錄的結構類似於袋限制mnesia中某個鍵下的記錄數的慣用方式是什麼?

{用戶名,字段1,filed2,時間戳}

爲了不讓數據庫爆炸,我想設置一個限制屬於某個用戶的記錄數,例如,如果用戶的記錄數達到500,則在插入新記錄之前刪除具有最早時間戳的記錄。

有沒有一種有效的方法來做到這一點?

在此先感謝。

回答

0

我提供了兩種可能性。一個適合你的設計,一個引入你的記錄定義的小改動。看哪一個最適合您的需求。下面的第一個是在你的設計中工作。

 
-record(user,{username,field1,field2,timestamp}). 

%% execute the function below in a mnesia transaction 

insert(#user{username = U,timestamp = _T} = User)-> 
    case mnesia:read({user,U}) of 
     [] -> mnesia:write(User); 
     AllHere -> 
      case length(AllHere) == 500 of 
       false -> %% not yet 500 
         mnesia:write(User); 
       true -> 
        %% value has reached 500 
        %% get all timestamps and get the 
        %% oldest record and delete it 
        %% 
        OldRecord = get_oldest_stamp(AllHere), 
        ok = mnesia:delete_object(Record), 
        mnesia:write(User) 
      end 
    end. 

get_oldest_stamp(UserRecords)-> 
    %% here you do your sorting 
    %% and return the record with 
    %% oldest timestamp 
    .... 
    OldRecord. 


交易中的length/1函數不是最優的。讓我們想一個更好的方法。另外,我不知道你的時間戳是怎麼樣的,所以我們確信你有一種排序方式,找出最新的時間戳,挑出擁有這個時間戳記的記錄,然後返回它。我已經給出了這個解決方案,以適應您的設計。我也認爲我們需要一些indexing。下一個實施對我來說似乎更好。一些如何改變記錄定義,我們引入一個字段oldest,它需要一個bool(),我們將它索引爲

 
-record(user,{ 
      username, 
      field1, 
      field2, 
      timestamp, 
      oldest  %% bool(), indexed
}).
insert_user(Username,Field1,Field2)-> User = #user{ username = Username, field1 = Field1, field2 = Field2, timestamp = {date(),time()}
}. insert(User).
%% execute this within a mnesia transaction
insert(#user{username = U} = User)-> case mnesia:read({user,U}) of [] -> mnesia:write(User#user{oldest = true}); AllHere -> case length(AllHere) == 500 of false -> %% unset all existing records' oldest field %% to false F = fun(UserX)-> ok = mnesia:delete_object(UserX), ok = mnesia:write(UserX#user{oldest = false}) end, [F(XX) || XX <- AllHere], ok = mnesia:write(User#user{oldest = true}); true -> [OldestRec] = mnesia:index_read(user,true,oldest), ok = mnesia:delete_object(OldestRec), ok = mnesia:write(User#user{oldest = true}) end end.
上面的實現對我來說似乎更好。成功!

0

另一種方式可能是有你的記錄是

{username, value_list, timestamp} 

其中VALUE_LIST包含的值的列表。你的桌子現在可以是一套而不是一個袋子,你可以做這種類型的東西

{NewList,_ignore}=lists:Split(500, [{NewFld1,NewFld2}|Value_list]), 
%mnesia:write(Rec#{value_list=NewList}) type of code goes next 

只要你插入。 NewList將包含至多500個元素,並且由於最老的元素在最後,所以如果您有501個元素,最後一個將放在_ignore列表中,您將...忽略。

您交易恆定時間查找您的密鑰的一些列表操作,但可能是一個很好的權衡取決於您的應用程序。您也可能能夠擺脫時間戳字段和相關代碼來維護該字段。

+0

這種方法非常簡單(我實際上在生產中有類似的東西),但是如果記錄數量的限制很高,那麼效率可能非常低,因爲Mnesia必須讀取或寫入用戶的所有數據,每個在該用戶上執行的操作。 – igorrs

相關問題