首先,我觉得数据库不是最好的地方。虽然您的更大列表正在发送电子邮件(由于您尝试瘫痪,我猜测规模非常大)您必须使用临时表,因为您不想限制向收件人发送不同的电子邮件以前的邮件。
在这里,缓存将是维护地址列表或充当共享内存资源的服务器的明显选择。
但是,您可以在数据库中执行此操作,并且根据我的理解,如果一个电子邮件地址多次存在并不是很重要,因为您所做的只是检查一个过去没有发送到该地址。如果没有锁定策略,您将无法真正控制多个脚本同时发送到同一地址的竞争条件。但是,您可以通过使用索引来提高效率。我不会索引实际地址,而是使用地址的 CRC32 哈希创建一个新列(它可以是一个 32 位无符号整数,只占用 4 个字节的内存)。由于生日悖论,使用 CRC32 方法您还必须检查查询中的电子邮件地址。
例如:
SELECT COUNT(*) FROM email_addresses
WHERE email_address_crc = CRC32(?address)
AND email_address = ?address
拥有一些有效的东西应该有助于对抗竞争条件,但是正如我之前所说,保证它的唯一方法是在发送每封电子邮件时锁定数据库,这样你就可以维护一个准确的列表——不幸的是,这不能扩展和这意味着让并行任务发送电子邮件可能无济于事。
编辑以回应以下评论:
正如评论中指出的那样,我实际上忘记解决 svdr 的锁定解决方案替代方案。确实,如果地址存在,包含电子邮件地址的唯一索引(或包含活动 ID 和地址的复合索引)确实会引发 MySQL 异常,从而导致并行脚本发送到同一地址的有效解决方案同时。但是,如果在脚本“尝试”发送电子邮件之前输入地址,则很难处理任何异常,例如由于 SMTP 错误/网络问题而无法发送电子邮件,这可能会导致收件人收不到电子邮件。还提供了一个非常简单的 INSERT 和 SELECT 它应该可以捕获 MySQL 异常,
另一个考虑因素是,出于性能原因,电子邮件地址字段需要完全索引,如果使用 INNODB,则此限制为 767 字节——假设电子邮件地址的最大有效长度为 254(如果使用 VARCHAR,则长度为 +1 字节)如果你没有一些巨大的主键,你应该没问题。
索引性能也应该得到解决,并且应该评估 CHAR 与 VCHAR。CHAR 字段上的索引查找通常比等效的 VCHAR 查找快 15% - 25% - 固定宽度的表大小也可以根据使用的表引擎提供帮助。
总而言之,是的,您的非锁定解决方案可以工作,但应该根据您的确切要求仔细测试和评估(我无法评论具体细节,因为我认为您的现实生活场景比您的 SO 问题更复杂)。正如答案的第一行所述,我仍然认为数据库不是最好的地方,缓存或共享内存空间会更有效,更容易实现。