2014-06-19 25 views
12

我有一張名爲Bookings的表格。該表包含代表針對特定服務進行的預訂的數據,其中包含許多變量。有效管理數據變化

前一段我碰到一個問題就來了我目前的數據結構,從而任何更改預訂,影響時間,日期或價格將影響到其他相關的財務記錄,預訂名單的日期等

我的解決方案在現在需要創建一個修改表來跟蹤對預訂所做的任何更改。然後,無論何時預訂模型被要求退回預訂,它都會添加所做的修改(在afterFind() Cake回調中),並呈現最新的預訂版本,如下所示(原因在於Paint drawing):當你問的預訂模式返回訂票#1234

enter image description here

此方法效果很好。它返回預訂的最新表示形式,包括所有修改(相互分層),包括一個包含所有原始預訂數據的修改的數組以供參考。

我的問題是,最近我意識到,我需要能夠查詢這種模式自定義條件,如果這些條件之一的修改之一是實現了,其結果將不匹配,因爲該模型正在搜索原始記錄而不是最終呈現的記錄。示例,其中我查詢模型返回行,其中abc是藍色(未灰色):

enter image description here

在該示例中,模型看起來在直的行的原始數據,其中abc是藍色,並且不返回這個結果,因爲藍色值是在附加附加的修改中找到了原始結果。

我現在所做的是將一個查詢放入預訂模型的beforeFind()回調中,查找與給定條件相匹配的修改,加入預訂以確保任何其他條件仍匹配。當它在上面的例子中返回藍色時,它將該結果作爲類屬性存儲在數組中,並繼續使用常規find(),但不包括從返回的預訂ID(因爲我們發現更新它的版本)。然後它會將它們合併在一起,並在afterFind()中再次分類。

雖然這是一個更囉嗦,我希望可以。

畢竟,我已經意識到,在這個應用程序的其他部分,有手動加入預訂表和搜索預訂的模型。所以現在我需要一種方法來將所有這些手動連接的修改合併到MySQL中的表中,而不會影響原始數據,並且最好不要更改我的代碼。

我的想法是我需要刪除手動連接並創建模型關聯。當我查詢說有多少訂單的客戶模型(將修改應用到每個預訂)時,預訂模型的beforeFind()afterFind()是否仍然運行?

我的其他選擇是通過刪除修改中可能包含的任何條件,從MySQL返回更多的行,然後使用PHP按照我的搜索條件過濾結果。這個選項讓我有點害怕,因爲結果集有可能是沒有這個標準的龐大數字......


我該如何實現這個數據結構?我的關鍵要求仍然是我不想更改原始預訂記錄,而是在頂部添加修改記錄,但我需要能夠通過模型查詢預訂(包括修改)。

我想嘗試,並保持儘可能多的場面可能這背後的整合,所以我不會要經過我的整個應用程序來改變n數量的查詢看起來像這樣:

$get_blue = $this->Booking->find('all', array(
    'conditions' => array(
     'Booking.abc' => 'blue' 
    ) 
)); 

我希望能夠隱含地包含對預訂進行的任何修改,以便在上述查詢中返回最新的預訂。

另一個問題是,當預訂模型手工加入到搜索查詢,像這樣:

$get_transactions_on_blue_bookings = $this->Transaction->find('all', array(
    'joins' => array(
     array(
      'table' => 'sql_bookings_table', // non-standard Cake format, I know - it's an example 
      'alias' => 'Booking', 
      'type' => 'LEFT', 
      'conditions' => 'Booking.booking_id = Transaction.booking_id' 
     ) 
    ), 
    'conditions' => array(
     'Booking.abc' => 'blue' 
    ) 
)); 

正如你所看到的,上面的查詢將不包括在上面我MSPAINT例如修改,因爲它是用SQL手動加入表格的(修改集成在Booking模型的beforeafterFind()回調函數中)。

任何幫助,將不勝感激。

編輯

我知道這是足夠長的時間了,但我想我補充一點,我之所以要跟蹤這些變化,而不是更新的原始記錄是,金融方面不能改變,因爲它會影響報告。

迄今爲止我所能看到的最快最簡單的解決方案是在所有情況下直接對原始預訂進行修改,除非財務信息仍然作爲修改進行跟蹤(因爲我目前不需要搜索基於這個信息)。

+2

最近我們遇到了一個類似的問題,那就是舊的數據結構不適合用途。我們嘗試了在頂部添加圖層來處理更改的方法,但最終會產生太多的錯誤。最後,我們從頭開始重新設計了數據結構,並編寫了CLI導入程序來移動所有現有數據。這樣做意味着我們可以緩慢地將面向客戶端的功能移動到新系統中,因爲數據正在被跟蹤。當我們對新系統完全滿意時,我們只需從項目中刪除遺留代碼。希望有所幫助。 –

+0

@orciny確實有幫助。我想我們最終將不得不重新設計這種方式。 –

回答

5

這聽起來像你試圖實施Temporal Database。時間支持是ANSI/ISO SQL:2011標準的主要補充之一。 MySQL(與大多數RDBMS一樣)落後於標準。將時態數據庫視爲CVS/SVN/Git的DBMS等價物。

相比之下,我們使用的沒有時間特徵的傳統數據庫可以被稱爲當前數據庫

當前數據庫,如果你嘗試實施的時間支持,你可以在很多方面失敗,不同的方法:

  • 一表的方法。當您需要進行修改時,您會在原始記錄上執行UPDATEs,除非您有某種本土觸發/審計邏輯,否則歷史記錄不存在。即使您有審覈/更改日誌,您也必須進行一些難以挖掘的重構更改歷史記錄。

  • 雙表法。不是在原地進行修改,而是將數據分成兩個表格,一個包含基本/原始記錄(例如預訂),另一個表格用於更改/修改/增量。然後至少你保留了你的原始數據,但是你必須編寫複雜的邏輯才能查看原始數據並進行修改。它變得更糟,如果你只想要一些的修改應用。

  • 預先計算的結果表方法。你保留3個或更多的表格:基礎記錄,修改,以及試圖總是得到結果的表格(保持最新的基礎+修改)。祝你好運寫觸發器和程序來做這個計算,只要你做INSERTs,天堂會幫助你,如果需要UPDATEDELETE。該設置是脆弱的,可能會突然失去同步,例如死鎖&回滾。如果你不使用觸發器/過程在數據庫中執行此操作,則可以嘗試在應用程序代碼中實現最終的計算結果,但是運氣好的話 - 它可能會讓多線程用戶感到難堪。而且,您仍然無法輕鬆訪問僅應用某些修改的結果。

結論:如果你不限於MySQL,你真的應該考慮使用具有內置的時間支持的DB。否則,你會重新執行輪子。

+0

嗨約書亞 - 感謝您的回答,哪些數據庫建立在臨時支持? –

+0

這對我來說也是新的,但如果你想保持開源,那麼PostgreSQL與Temporal Postgres的貢獻包看起來很有趣 - http://pgfoundry.org/projects/temporal/。這些鏈接可能會導致其他起點http://en.wikipedia.org/wiki/Temporal_database#Implementations_in_databases。看起來好像有很多它圍繞有效地使用PERIOD數據類型。我剛剛從IBM那裏瞭解到了這一點,它有很多關於這個問題的地方:http://www.ibm.com/developerworks/data/library/techarticle/dm-1204db2temporaldata/ –

+0

嗨,約書亞,我給你賞金,因爲你的答案是最有用的,儘管事實上暫時的數據庫支持在MySQL中尚不存在。感謝您的回答! –

2

而不是將修改應用於原始記錄,如果您做了相反的操作並將原始記錄應用於修改,該怎麼辦?您可以修改修改表格(或新表格)以保留應用了修改的原始記錄,並在那裏指定您的搜索。

另一個想法是,如果財務數據是所有需要保留的,爲什麼不把它保存在另一個字段或表中,並在需要時引用它? 我同意重新設計可能是長期解決方案中最好/最聰明的方法,但我想我會將我的想法放在桌子上以防萬一。

+0

在短期內,我們決定這樣做並分別保存財務數據,同時立即應用所有其他更改(並且仍保留修改日誌)。關於將原始預訂應用於修改 - 是否符合「有效管理」以潛在地複製數據?我可以看到每行都完全重複,因爲非常快地增加了數據庫大小......? –

+0

總的來說,我傾向於儘可能避免重複數據,但我建議,因爲我不確定你能做什麼,不能做什麼,涉及多少數據等等。爲了回答你的問題,我最初的反應是No ,它不符合有效的管理,但在某些情況下它可能是一個有價值的解決方案(取決於我列出的項目)。如果單獨存儲財務數據是一個可行的解決方案,那可能就是我希望的_short-term_解決方案。重寫可能仍然是最佳的長期解決方案,具體取決於您的實際實施情況。 – Trick

2

如果您在修改原始表之前使用備份表來存儲原始表中的數據,該怎麼辦?您可以使用回滾功能將數據恢復到以前的狀態。

這裏是我的數據庫更新過程初論的流程圖: http://i1371.photobucket.com/albums/ag300/joshua127/BookingFlowchartinsert_zps5c2d55f8.png

這是我的選擇過程初論的流程圖: http://i1371.photobucket.com/albums/ag300/joshua127/BookingFlowchartselect_zps702fa902.png

希望這有助於,只是另一種方式來看待它。

P.S.爲了保持財務信息不變,您可以編寫更新函數來計算要更新的列數(基於更新的列名稱數組),並提供變量來保存這些列的特定值。您可以在SQL語句中引用數組索引($ array ['index'])以使其變爲動態。

+0

嗨@ jfh6我不打算在任何時候複製這一行,如果是這樣的話,這將是我已經做的事情。我的推理是,如果一個「預訂」被編輯了十次,那麼你就有11行(10編輯和一個當前),所有列都包含數據 - > 10倍以上的數據比我想要的存儲。如果我有一百萬行,那麼我將有1000萬行,列數相同。我寧願能夠將每個修改後的字段存儲爲自己的行,以便它只有四個字段:booking_id,field_name,modified_value和modified_date。小多了。 –

1

在我看來,你需要的是一種桌子的歷史,以便你能夠知道當時發生了什麼。

我通常通過創建一個稱爲原始追加_history的並行表來實現這種方法。 Bookings_history你的情況。該結構將類似於原來的,但前面加上列:

一)timestamp,從而節省當變更發生

B)id,以確定在原表

唯一索引行在這兩列將被創建。

每次修改發生時,在應用修改之前,將原始行復制到歷史記錄表。然後在原始表上應用修改。這樣做,歷史表就像一個堆棧,您可以保存原始數據的快照。

我特別喜歡這個模型,因爲連接表和在歷史表上應用搜索引擎可以用與原始表類似的方式完成,因爲結構非常相似。另外,如果你想知道修改,你只需要比較歷史表的行。

我希望這會有所幫助。

+0

嗨,謝謝你的回答。我真的不想重複行 - 這是因爲數據庫大小的原因比什麼都重要,否則我會這樣做 –

+0

不用擔心。遵循這個模型,你實際上並不複製行。您正在存儲快照,並且這些快照是彼此不同的。就表格的性能/大小而言,這是一個不同的問題,必須考慮到其他事實,例如硬件資源,數據增長速度等。感謝您的反饋意見。 –

1

從你已經收集到的答案中可以看出,無論你做什麼,都需要進行一些或者更多的重新設計。

解決的辦法之一,我不看還和我已經在過去用來解決這樣的問題(即改變訂單)是保持在同一個表一切和使用領域(S)區分它們。

您可以更改bookings表,以便爲每個預訂(即version_number)和is_latest字段添加遞增的整數。通過這種方式,您可以使用is_latest=true查詢以獲取當前記錄及其version_number。如果它是0,則沒有變化,如果它> 0,則有變化(該數字將等於變化的次數)。如果您從最新版本轉到0或相反的方式,並且每次您將完整記錄您的應用無需修改即可理解,您將能夠「回放」或「重放」歷史記錄。

如果is_latest被索引,查詢速度將(幾乎)等於原始表查詢速度,當然,如果您需要多次獲得原始預訂,您可以添加更多的布爾值,如is_original

這有一個好處,它很可能會要求您只更改Booking模型,但這取決於您的代碼。

編輯:我相信這種方法將最符合您關於報告和財務記錄的要求,因爲您始終可以輕鬆獲得原始記錄(版本0)。