使用 MySQL 唯一索引来防止重复,而不是重复搜索?
Using MySQL unique index to prevent duplicates, instead of duplicate searching?
我有一个很大的 table(500 万行),有一个名为 'unique_id'
的唯一标识符列
我是 运行 通过 Node.js(node-mysql
绑定)的 INSERT 查询,可能会尝试插入重复项。
两种解决方案是:
1) 创建 'unique_id' 索引,并在 INSERT 之前检查整个数据库是否有重复记录:
'SELECT unique_id WHERE example = "'+unique_id+'" LIMIT 1'
2) 使 'unique_id' 成为 MySQL 中的唯一索引,并执行 INSERT 而无需 检查重复项。显然,任何重复项都会导致错误,并且不会被插入到 table.
中
我的直觉是解决方案 2) 更好,因为它可以防止搜索最坏情况 (500 万 - 1) 行中的重复项。
使用解决方案 2) 有什么缺点吗?
为 unique_id 列定义唯一的主索引有很多优点:
- 语义正确性 - 目前该名称不反映实际情况,因为您可以在名为 'unique_id'、
的列中重复
- 自动生成唯一 ID - 您可以将此工作委托给数据库并避免 ID 冲突(如果您使用 UUID 而不是整数,这将不是问题),
- 速度增益 - 作为可靠的解决方案 1 需要阻塞事务(在检查重复项和插入行之间不应插入新行)。将此委托给 MySQL 会更有效率,
- 遵循通用模式 - 这正是唯一索引和主索引的设计目的。您的解决方案将很容易被其他开发人员理解,
- 更少的代码。
对于第二种解决方案,您可能需要处理插入重复项的尝试(除非您的唯一 ID 是由 MySQL 生成的)。
自动递增的主索引:
https://dev.mysql.com/doc/refman/5.7/en/example-auto-increment.html
令人惊讶的是,它在性能方面几乎没有什么区别。搜索将使用(并要求)相同的索引。
但是,您的 (2) 解决方案有一点性能差异。
实际上在 MySQL 中,您可以使用 IGNORE 关键字完全消除错误:
INSERT IGNORE INTO ... VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9)...;
将始终成功(将跳过插入重复项)。这允许在单个语句中插入多个值,如上所述。
您可能还对 ON DUPLICATE KEY UPDATE
技巧系列感兴趣 :-)。
真正的区别,如M.M。已经说过,在完整性。使用 UNIQUE 索引约束,您可以确定您的数据;否则,您需要在检查它的时刻和插入新元组的时刻之间锁定 table,以避免其他人插入相同值的风险。
如果数据的 "duplicateness" 需要大量的业务逻辑工作,而无法轻易转换为 MySQL 约束,则您的 (1) 解决方案可能会有用武之地。在那种情况下你会
- 锁定table,
- 搜索候选重复项(假设你得到了 20 个),
- 获取数据并验证他们是否是真正的候选人
- 如果none冲突,插入新的元组,
- 解除锁定。
(可能有充分的理由认为,需要进行如此复杂的旋转木马是由于数据库设计中的一些错误。理想情况下你应该能够在 MySQL 中完成所有事情。但是 商业现实 有时远非理想)。
我有一个很大的 table(500 万行),有一个名为 'unique_id'
的唯一标识符列我是 运行 通过 Node.js(node-mysql
绑定)的 INSERT 查询,可能会尝试插入重复项。
两种解决方案是:
1) 创建 'unique_id' 索引,并在 INSERT 之前检查整个数据库是否有重复记录:
'SELECT unique_id WHERE example = "'+unique_id+'" LIMIT 1'
2) 使 'unique_id' 成为 MySQL 中的唯一索引,并执行 INSERT 而无需 检查重复项。显然,任何重复项都会导致错误,并且不会被插入到 table.
中我的直觉是解决方案 2) 更好,因为它可以防止搜索最坏情况 (500 万 - 1) 行中的重复项。
使用解决方案 2) 有什么缺点吗?
为 unique_id 列定义唯一的主索引有很多优点:
- 语义正确性 - 目前该名称不反映实际情况,因为您可以在名为 'unique_id'、 的列中重复
- 自动生成唯一 ID - 您可以将此工作委托给数据库并避免 ID 冲突(如果您使用 UUID 而不是整数,这将不是问题),
- 速度增益 - 作为可靠的解决方案 1 需要阻塞事务(在检查重复项和插入行之间不应插入新行)。将此委托给 MySQL 会更有效率,
- 遵循通用模式 - 这正是唯一索引和主索引的设计目的。您的解决方案将很容易被其他开发人员理解,
- 更少的代码。
对于第二种解决方案,您可能需要处理插入重复项的尝试(除非您的唯一 ID 是由 MySQL 生成的)。
自动递增的主索引: https://dev.mysql.com/doc/refman/5.7/en/example-auto-increment.html
令人惊讶的是,它在性能方面几乎没有什么区别。搜索将使用(并要求)相同的索引。
但是,您的 (2) 解决方案有一点性能差异。
实际上在 MySQL 中,您可以使用 IGNORE 关键字完全消除错误:
INSERT IGNORE INTO ... VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9)...;
将始终成功(将跳过插入重复项)。这允许在单个语句中插入多个值,如上所述。
您可能还对 ON DUPLICATE KEY UPDATE
技巧系列感兴趣 :-)。
真正的区别,如M.M。已经说过,在完整性。使用 UNIQUE 索引约束,您可以确定您的数据;否则,您需要在检查它的时刻和插入新元组的时刻之间锁定 table,以避免其他人插入相同值的风险。
如果数据的 "duplicateness" 需要大量的业务逻辑工作,而无法轻易转换为 MySQL 约束,则您的 (1) 解决方案可能会有用武之地。在那种情况下你会
- 锁定table,
- 搜索候选重复项(假设你得到了 20 个),
- 获取数据并验证他们是否是真正的候选人
- 如果none冲突,插入新的元组,
- 解除锁定。
(可能有充分的理由认为,需要进行如此复杂的旋转木马是由于数据库设计中的一些错误。理想情况下你应该能够在 MySQL 中完成所有事情。但是 商业现实 有时远非理想)。