2012-12-12 31 views
3

一個常見操作是插入一個新行(如果不存在或更新現有行)。不幸的是,插入和更新SQL語句的語法是完全不同的:Insert獲取一列後接相應的值列表,而更新獲取列=值對的列表。 MySQL「insert ... on duplicate key update」語句(它的upsert語句)不能解決這個問題,因爲它仍然需要完整的插入列/值列表,然後是完整的更新列/值列表。 [更新:來自Wrikken的評論指出,這兩個語句可以共享column = value語法,但其他問題仍然存在。]簡化MySQL中的更新/插入(upsert)處理

與此問題相關的是,如果您使用觸發器來檢查數據我需要),你需要兩個觸發器(before-insert和before-update),並且,因爲他們必須使用「new」限定符,所以你必須寫兩次檢查代碼,每次觸發一次,或者把它放入程序。如果您使用過程,則必須將每列作爲單獨參數傳遞,因爲該過程不能使用「新」,如果您有很多列,則很可能會出現容易出錯的輸入。每一列必須在create table語句中具有其類型,然後再次在檢查過程的定義中。一旦出現一點小錯誤,你創建了一個微妙的,難以發現的錯誤。我不喜歡任何涉及兩次編碼同一事物的方法。 (它的非正常化的等價物)

這個插入/更新問題的思考,我一直在玩弄以下的想法,我想一些反饋,特別是如果任何人真正嘗試過:

僅對佔位符行使用插入,僅保留最少量的數據以及獲取或設置主鍵。然後,將所有用戶輸入的數據放入更新語句中。現在,您不需要「插入...重複密鑰更新」,就像純更新一樣。此外,您只需在更新前觸發器上檢查數據,因爲沒有任何內容需要檢查。 (來自輸入表格的所有用戶提供的數據都由更新處理,而不是由插入處理。)

該方法的主要缺點當然是對於新行有兩個操作:插入後跟更新,而不是插入。但是,這可能不是一個因素,因爲:

  1. 插入可能比較少見。例如,在幾年前我爲Richardson(TX)學區做過的學生評分申請中,每年只增加幾千名學生,而成千上萬的更新,因爲老師使用系統在整個學年。

  2. 在我創建的其他系統中,性能無關緊要。例如,我正在處理的當前系統只有兩三個人每週只更新數據庫幾個小時。負載非常小,以至於只有一個操作就足夠了,兩個操作(insert + update)引起的開銷不大。 (這僅適用於新行,切記。)

那麼,有沒有人真正嘗試這樣的:插入只有創造簡約的佔位符行,併爲所有用戶提供的數據更新使用更新?

+1

你知道'INSERT INTO tablename SET col1 = 1,col2 = 2' ...等是否有效?我還沒有找到寫一個查詢只是一個累贅... – Wrikken

+0

http://dev.mysql.com/doc/refman/5.5/en/insert.html – jchapa

+0

感謝您指出這一點。在PHP中,如果賦值被組合爲一個字符串,那麼該字符串可以在兩個地方的「insert ... on duplicate key」語句中使用,這有點幫助。但是,需要兩個觸發器仍然存在。我的想法仍然只允許一個觸發器,這大大簡化了觸發器編碼。想法呢? –

回答

7

如果我需要數據庫來執行數據有效性的「規則」,我仍然需要INSERT觸發器以及UPDATE觸發器,因爲在數據庫級別,我不能保證某人不會執行包含無效數據的INSERT。無論如何,我傾向於同時觸發這兩種觸發器。

插入「佔位符」行然後更新的另一個缺點是(對於可變長度記錄),存在碎片方面。後續的更新幾乎可以保證行的長度會增加,這將導致數據庫中碎片的不必要的增加(如果你只是插入行,因爲它需要在那裏,這不會發生。 )

我還需要考慮當佔位符的INSERT成功但UPDATE失敗的情況。我必須有一些額外的機制來處理這種情況。

運行單個語句會更高效,只需插入我知道需要的值,而不是運行兩個單獨的語句(一個插入佔位符行,然後第二個語句更新它)。

就個人而言,我只是去與INSERT ... ON DUPLICATE KEY UPDATE,而不是重複UPDATE部分中的值,我只是引用在INSERT語句中爲這些列提供的值,例如

INSERT INTO foo (a,b,c) VALUES (1,'one','won'), (2,'two','too') 
    ON DUPLICATE KEY 
    UPDATE a = VALUES(a) 
     , b = VALUES(b) 
     , c = VALUES(c) 

注:本陳述的副作用需要注意的,尤其是如果它是主要被執行UPDATE。該語句將爲試圖插入的每一行增加一個AUTO_INCREMENT ID。該AUTO_INCREMENT ID值本質上將被「浪費」,因爲生成的值不會被插入到表中,而是會「消失」。 (下一個生成的值將會更高。)

+0

非常好的一點,我錯過了:將檢查(驗證)放入數據庫是爲了確保它們始終有效,而不是由應用程序員決定,但要求只有佔位符的插入纔會將其留給應用程序員。我沒有看到這個矛盾。 –