我有一个单列 MySQL 数据库表 ids
(id INTEGER PRIMARY KEY AUTOINCREMENT),我在其中按升序存储预生成的唯一 ID。为了从该表中获取随机 ID,我使用此查询:
SELECT id FROM ids ORDER BY RAND() LIMIT 1;
现在我想知道如何确保我获得的 ID 不再被使用。我看到两个选项。一种是从表中删除 id,另一种是添加一个列来跟踪该 id 的使用情况:
DELETE FROM ids WHERE id=?; //where id is the one I got from the previous query
或
SELECT id FROM ids WHERE used=0 ORDER BY RAND() LIMIT 1;
UPDATE ids SET used=1 WHERE id=?; //where used is new column with 0 as default value
这两个都只有一个小问题。如果服务器负载很重,那么在从列表中删除(或使用已用列禁用)之前,对随机 ID 的两次查询可能会返回相同的 ID。
事务有帮助吗?
最佳答案
将您的选择和您的更新包装在事务中将起作用。如果您想避免交易以及选择项目和将其标记为不可用之间的竞争条件,您可以先运行 UPDATE
。您将需要一种方法让您的每个进程在声明它和删除之间将自己标识为该行的所有者。例如,假设您的 ids
架构是
id
(整数)所有者
(字符串)
让每个进程选择一个 UUID(或其他适当唯一的东西)并运行以下命令:
UPDATE ids SET owner = $process_id WHERE owner IS NULL ORDER BY RAND() LIMIT 1
SELECT id FROM ids WHERE owner = $process_id
DELETE FROM ids WHERE id = $selected_id
(或以其他方式标记它已使用)
第 1 步以原子方式声明该进程的行,以便其他进程无法声明它。第 2 步取出声称的 ID。第 3 步从可用集合中永久删除 ID。如果第 3 步没有删除该行,只是将其标记为已使用,请确保您也清除了 owner
,这样您的进程以后就不会再次选择它。
关于php - 如何从重负载服务器的表中随机选择唯一值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30183213/