首先我觉得数据库不是这样做的最好的地方。虽然你的更大的名单正在发送电子邮件(由于你试图瘫痪,我猜测的规模很大),但你必须使用临时表,因为你不想限制发送不同的电子邮件给以前的邮件。
缓存将是显而易见的选择,在这里维持地址列表,或服务器作为共享内存资源。
但是你能做到这一点在数据库中,并从我的理解,如果一个电子邮件地址存在不止一次因为所有你正在做的是检查一个过去没有被发送到是不是真的至关重要。如果没有锁定策略,您无法真正控制多个脚本同时发送到同一地址的争用情况。但是,您可以通过使用索引来提高效率。我不会索引实际地址,但会创建一个带有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