在我的数据库应用程序中,我需要为每个客户提供唯一的4位数字段。直到9999我才能使用自动增量,但之后我将不得不重复使用已被删除的客户数量(在给定时间内不会超过5000个客户,但在生命周期内可能会有超过9999个客户)系统)。
问题1:是否有(My)SQL语句可以找到下一个可重复使用的空闲号码?
问题2:如果我得到号码,将其分配给新客户并将客户全部保存在一个交易中,同时发生的类似交易将由数据库按顺序排列,因此数字不会发生冲突,对?
答案 0 :(得分:7)
最好存储一个表,其中定义了所有10,000个可能的值,并且每个表都有一个“使用中”标志。这样,释放重复使用的数字是设置“inuse = false”的简单更新。
还可以找到最低的可用值
SELECT idstring
FROM idstringtable
ORDER BY idstring ASC
WHERE (available = 1)
LIMIT 1
使用适当的锁/事务执行此操作会阻止两个或多个请求获得相同的ID,并且由于它是一个小表,因此执行全局表锁定不会显着影响性能。
否则,你会被困在用户桌旁翻找,试图在编号序列中找到第一个“缺口”。
答案 1 :(得分:2)
如果你必须使用这个模型(我建议反对它),那么我会创建一个“可用”数字池,在创建帐户时,只需从中获取TOP 1。然后,当删除用户时,将该号码返回到池中。
答案 2 :(得分:1)
这是为了找到第一个可用的插槽:
select i1.id + 1 as FirstAvailable
from issues i1 left join issues i2 on (i1.id = i2.id - 1)
where i2.id is null
limit 1
这是针对生产Redmine实例运行的,以查找第一个缺少的ID。根据您的需求进行调整。
答案 3 :(得分:1)
使用单独的表来跟踪正在使用的ID的建议将起作用,但如果您不想使用单独的表来跟踪使用的ID,则可以进行自联接以查找ID号中的间隙。自联接非常简单:
select top 1 t1.id + 1
from table t1
left join table t2 on t1.id = t2.id - 1
where t1.id < 10000
and t2.id is null
在MS SQL Server中,我使用TOP 1来获得最重要的结果,但在MySQL中它可能是不同的语法。
答案 4 :(得分:0)
以上答案(由Adrian Carneiro撰写)非常棒,并且除非表格使用不同的字段作为主键并且没有“id&#39;”的密钥。
给定一个主键为userid的表: -
MariaDB [unixua]> select userid, uid from accounts;
+---------+----------+
| userid | uid |
+---------+----------+
| acc0001 | 89814678 |
| acc0002 | 38000474 |
| acc0005 | 38000475 |
| acc0017 | 38000478 |
+---------+----------+
4 rows in set (0.00 sec)
我们预计最低免费号码为38000476。
MariaDB [unixua]> SELECT t1.uid +1 FROM accounts t1
LEFT JOIN accounts t2 ON (t1.uid +1 = t2.uid)
WHERE t2.uid IS NULL AND t1.uid>38000474 LIMIT 1;
+-----------+
| t1.uid +1 |
+-----------+
| 89814679 |
+-----------+
1 row in set (0.00 sec)
但是,因为MySQL / MariaDB正在按主键顺序选择它们,所以这会失败,并且在&#34; acc001&#34;之后给出次高的值。 通过向uid列添加一个键,只在&#34; uid&#34;上执行SELECT。在列中,MySQL / MariaDB将使用索引来检索数据(而不是读取表)。由于索引是&#34;有序&#34;,结果是不同的: -
MariaDB [unixua]> alter table accounts add unique index (uid);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [unixua]> SELECT t1.uid +1 FROM accounts t1
LEFT JOIN accounts t2 ON (t1.uid +1 = t2.uid)
WHERE t2.uid IS NULL AND t1.uid>38000474 LIMIT 1;
+-----------+
| t1.uid +1 |
+-----------+
| 38000476 |
+-----------+
1 row in set (0.00 sec)
确保您的表具有“客户ID”字段的键(并且该客户ID字段为数字)。
这是有效的,因为优化器可以从索引(aka accounts.myi,而不是accounts.myd)中检索select的所有必要数据,而不是表数据。