首先我覺得數據庫不是這樣做的最好的地方。雖然你的更大的名單正在發送電子郵件(由於你試圖癱瘓,我猜測的規模很大),但你必須使用臨時表,因爲你不想限制發送不同的電子郵件給以前的郵件。
緩存將是顯而易見的選擇,在這裏維持地址列表,或服務器作爲共享內存資源。
但是你能做到這一點在數據庫中,並從我的理解,如果一個電子郵件地址存在不止一次因爲所有你正在做的是檢查一個過去沒有被髮送到是不是真的至關重要。如果沒有鎖定策略,您無法真正控制多個腳本同時發送到同一地址的爭用情況。但是,您可以通過使用索引來提高效率。我不會索引實際地址,但會創建一個帶有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問題更復雜)。正如答案的第一行中所述,我仍然相信數據庫不是最好的地方,而且緩存或共享內存空間將更加高效且易於實現。
出於興趣,爲什麼不使用1個腳本? – George 2013-03-01 10:32:44
這些電子郵件從哪裏來?如果腳本在電子郵件實際發送之前崩潰,是否是一個問題?是什麼讓你認爲鎖不能正常工作? (除此之外,唯一索引是避免欺騙的有效方法。) – 2013-03-01 10:46:09
@ F4r-20:啓用到後綴服務器的多個併發連接。 – svdr 2013-03-01 10:55:31