2016-10-25 69 views
1

我有一個包含大量數據的表格。數據的來源是一個外部API。每隔幾個小時,我需要同步數據庫,以便更改從外部api更新。我正在進行完全同步(api不允許增量同步)。MySQL:更新大型表格的最佳方法

發生同步時,我想確保數據庫中的數據也可以讀取。所以,我按照下面的步驟:

  1. 我在表中有一個cloumn作爲數據是否可讀的標誌。只有帶有標誌設置的數據被標記爲可讀。
  2. 我將api的所有數據插入表中。
  3. 一旦寫入所有數據,我將刪除標記集中表中的所有數據。
  4. 刪除後,我正在更新表並設置所有行的標誌。

表約有5000萬行左右,預計會增長。表中有一個customerId字段。同步通常基於customerId,並將其傳遞給api。

我的問題是,上面的步驟3和4需要很多時間。查詢是這樣的:

第3步 - >delete from foo where customer_id=12345678 and flag=1

第4步 - >update foo set flag=1 where customer_id=12345678

我試圖劃分基於CUSTOMER_ID的表以及CUSTOMER_ID少的行數它的偉大工程,但對於某些customer_id,每個分區本身的行數都會達到〜500萬。

大約90%的數據在兩次同步之間沒有變化。我怎樣才能讓這個速度更快?

我正在考慮只使用更新查詢,而不是插入查詢,然後檢查是否有任何更新。如果不是,我可以爲同一行發出插入查詢。這樣,任何更新都將與插入一起處理。但我不確定在更新過程中操作是否會阻止讀取查詢。

+0

此api是否返回每個項目的最後一次更改的時間戳記? – krasipenkov

+0

關於分區方法,您是如何執行刪除操作的?通過刪除整個客戶分區或普通的選擇? – krasipenkov

+0

@ agarwalankur85如果我理解正確,表只讀(對用戶,而不是API和你的國旗當然),並且所有的行都被api完全重新插入到表中。你可以定義一個不同的表作爲你的api插入的目的地(api寫入的地方,你可以將這些行移動到真正的表)?而且,由於您目前有一段時間可以讀取0行(介於3到4之間),因此我認爲(短)的宕機時間可以接受?最後但並非最不重要的是:你的mysql版本是什麼? – Solarflare

回答

0

對於您的設置(只讀數據,完全同步),更新表的最快方法是根本不更新,但是要將數據導入到不同的表中並在之後重命名以使其成爲新表。

創建一個與原始表格類似的表格,例如使用

create table foo_import like foo; 

如果您有例如觸發器,也添加它們。

從現在開始,讓導入api將其(完全)同步寫入這個新表。

後同步完成後,交換兩個表:

RENAME TABLE foo TO foo_tmp, 
    foo_import TO foo, 
    foo_tmp to foo_import; 

它將(字面)只需要一秒鐘。

這個命令是原子的:它將等待訪問這些表的事務完成,它不會出現沒有表foo的情況,如果其中一個表不會執行,它將完全失敗(並且不會執行任何操作)不存在或foo_tmp已經存在。

最後一步,清空你的導入表(現在包含您的舊數據),以備下次導入:

truncate foo_import; 

這將再次只是需要一秒鐘。

其餘的查詢可能假設爲flag=1。直到(如果有的話)您更新代碼以不再使用標誌,您可以將其默認值設置爲1以保持其兼容性,例如,使用

alter table foo modify column flag tinyint default 1; 

既然你沒有外鍵,它沒有打擾你,但對於其他人有類似的問題,這可能是有用的知道外鍵將得到調整,這樣的外鍵引用foo將在重命名錶後引用foo_import。爲了讓它們再次指向新表foo,它們必須被刪除並重新創建。其他所有內容(例如,視圖,查詢,過程)將按當前名稱解析,因此他們將始終訪問當前的foo

+0

想到它:你沒有直接回答我的問題,如果原始表中的所有行都完全重新插入導入或不導入,我在這裏假設他們是。如果您只更新特定客戶,這種方法不會直接工作,但您可以使用分區執行相同的邏輯(您可以將分區與重命名錶類似),但需要按客戶ID進行分區。如果您擁有固定數量的客戶,那麼最好是,但您可以將其用於大型客戶(並立即更新小型客戶)。 – Solarflare

+0

謝謝Solarflare。並非所有的行都被完全替換。它們根據customer_id進行更新。一次,客戶完全同步,而不是該表中的所有行。我將嘗試你的交換分區的方法。客戶數量不固定。 – agarwalankur85

+0

性能很可能會超過50個分區。因此,請考慮「按區域劃分(customer_id)」,但它們本身只有最大的20個分區。維護將是棘手的。 –

0
CREATE TABLE new LIKE real; 
Load `new` by whatever means you have; take as long as needed. 
RENAME TABLE real TO old, new TO real; 
DROP TABLE old; 

RENAME是原子和「瞬時」; real「始終」可用。

(我沒有看到flag的需要。)

OR ...

因爲實際上更新表的一大塊,考慮這些...

如果塊小...

  1. 加載新的數據到tmp目錄表
  2. 刪除舊行
  3. INSERT ... SELECT ...移動新行中。(在表中已經有新的數據可能是實現這一目標的最快捷方式。)

如果塊很大,並且你不想鎖定表「太長」,還有一些其他的技巧。但首先,客戶的每一行是否有某種形式的唯一行號? (我正在考慮批量移動一堆或多行,但在拼寫出來之前需要更多細節。)

+0

問題在於,一次同步發生在一個客戶身上。所以我不能放棄較舊的桌子。 – agarwalankur85

+0

請參閱附加... –

+0

否。只有行ID(設置爲自動遞增)。問題在於大型客戶。它需要4-5分鐘(用分區)刪除客戶的所有行。 – agarwalankur85

相關問題