2013-03-01 104 views
2

假設我有一對夫婦的腳本發送(合法!)的電子郵件。每個腳本處理更大列表的一部分,並且它們同時運行。在發送之前,必須檢查每個地址以避免兩次發送到相同的地址。工作,避免鎖

要做到這一點,我創建了一個簡單的表(MySQL 5.1中,InnoDB的),只用電子郵件地址。如果它不在表格中,則添加它併發送郵件。現在我需要避免多個腳本同時測試同一個地址並錯誤地推斷它沒有被髮送到的競爭條件。我想我可以使用這個鎖,但我寧願不這樣做,因爲性能的原因。

所以我想知道如果下面的選擇是正確的:

  • 在地址欄
  • 只需插入地址加入了獨特的指數,沒有選擇
  • 陷阱MySQL的檢查返回錯誤代碼:如果它是1062,則該地址已存在。

在此設置中,是否仍有競爭條件的可能性?我的意思是:是否仍有可能兩個幾乎同時插入地址的腳本都斷定該郵件尚未發送?或者我應該使用鎖嗎?

感謝, 斯泰恩

+0

出於興趣,爲什麼不使用1個腳本? – George 2013-03-01 10:32:44

+0

這些電子郵件從哪裏來?如果腳本在電子郵件實際發送之前崩潰,是否是一個問題?是什麼讓你認爲鎖不能正常工作? (除此之外,唯一索引是避免欺騙的有效方法。) – 2013-03-01 10:46:09

+0

@ F4r-20:啓用到後綴服務器的多個併發連接。 – svdr 2013-03-01 10:55:31

回答

0

首先我覺得數據庫不是這樣做的最好的地方。雖然你的更大的名單正在發送電子郵件(由於你試圖癱瘓,我猜測的規模很大),但你必須使用臨時表,因爲你不想限制發送不同的電子郵件給以前的郵件。

緩存將是顯而易見的選擇,在這裏維持地址列表,或服務器作爲共享內存資源。

但是你能做到這一點在數據庫中,並從我的理解,如果一個電子郵件地址存在不止一次因爲所有你正在做的是檢查一個過去沒有被髮送到是不是真的至關重要。如果沒有鎖定策略,您無法真正控制多個腳本同時發送到同一地址的爭用情況。但是,您可以通過使用索引來提高效率。我不會索引實際地址,但會創建一個帶有CRC32散列地址的新列(可以是隻佔用4個字節內存的32位無符號整數)。由於生日悖論,使用CRC32方法您還必須檢查查詢中的電子郵件地址。

例如:

SELECT COUNT(*) FROM email_addresses 
WHERE email_address_crc = CRC32(?address) 
AND email_address = ?address 

有一些東西,是高效應有助於避免競態條件但正如我曾說過,以保證唯一方法是鎖定數據庫,而每封電子郵件被髮送,所以你然後可以保留一個確切的清單 - 這不幸的是沒有規模,並且意味着發送電子郵件的並行任務可能無濟於事。

編輯迴應下面的評論:

正如我居然忘了解決SVDR的替代鎖定解決方案的評論中指出。確實,如果地址存在,那麼包含電子郵件地址(或包含活動ID和地址的複合索引)的唯一索引確實會拋出MySQL異常,從而導致使用並行腳本發送到相同地址的工作解決方案同時。但是,如果在腳本嘗試發送電子郵件之前輸入地址,則很難處理任何異常,例如由於SMTP錯誤/網絡問題而未發送電子郵件,這可能會導致收件人無法收到電子郵件。還提供這是一個非常簡單的INSERT和SELECT,它應該很好,只是爲了捕獲MySQL異常,但是如果有更復雜的事情,例如事務中的包裝命令或使用SELECT FOR UPDATE等,這可能導致死鎖情況。

另一個需要考慮的因素是,如果使用INNODB,這個限制是767字節,因爲電子郵件地址的最大有效長度是254(長度+1字節)如果使用VARCHAR),你應該沒問題,因爲你沒有一些巨大的主鍵。

指數表現也應該被解決,CHAR和VCHAR應該被評估。 CHAR字段上的索引查找速度通常比等同的VCHAR查找速度快15% - 25% - 根據所使用的表引擎,固定寬度的表大小也可以提供幫助。總而言之,是的,你的非鎖定解決方案是可行的,但應該根據你的確切需求仔細測試和評估(我不能評論具體細節,因爲我假設你的現實生活場景比你的SO問題更復雜)。正如答案的第一行中所述,我仍然相信數據庫不是最好的地方,而且緩存或共享內存空間將更加高效且易於實現。

+0

謝謝!我們需要持久性,因爲廣告系列可能會重新發送給添加的收件人,我們需要再次進行檢查。好主意使用散列作爲索引。關於我的替代鎖定:你能解釋爲什麼這不起作用嗎? – svdr 2013-03-04 20:27:07

+0

@svdr我會編輯我的答案 - 我得到了另一種方法,我完全忘記了解決這個問題! – Steve 2013-03-04 20:53:56

+0

感謝您的廣泛答覆。我會做一些測試以找到最佳解決方案。一旦我達到了15的聲望,我會盡快回復你的答案;) – svdr 2013-03-05 21:10:14