我有一个Web应用程序,用户可以在其中创建存储在MySQL数据库中的对象。每个对象都有一个存储在表中的全局唯一标识符。
DROP TABLE IF EXISTS `uidlist`;
CREATE TABLE IF NOT EXISTS `uidlist` (
`uid` varchar(9) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`chcs` varchar(16) DEFAULT NULL,
UNIQUE KEY `uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=ascii;
当要创建和存储新对象时,我生成一个新的uid,并确保它在uidlist
表中不存在。 (我应该提一下碰撞是罕见的,因为我所拥有的UID的潜在范围非常大。)
这里没有问题 - 它运作得很好。但是,随着越来越多的用户希望同时创建+存储对象,检查uidlist的需求可能成为瓶颈。
在这里解决问题就是我所做的:
我有一张辅助表
DROP TABLE IF EXISTS `uidbank`;
CREATE TABLE IF NOT EXISTS `uidbank` (
`uid` varchar(9) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`used` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=ascii;
我通过CRON作业以较短的间隔预先填充此表 - 这可确保它始终具有1000个uid值,并对其进行唯一性测试。
当实时用户需要新的UID时,我会执行以下操作:
function makeUID()
{
global $dbh;
$sql = "DELETE FROM `uidbank` WHERE used = '1';";
//discard all "used" uids from previous hits on the bank
$sql .= "UPDATE `uidbank` SET used = '1' WHERE used = '0' LIMIT 1;";
//setup a new hit
$dbh->exec($sql);
//be done with that
$sql = "SELECT uid FROM `uidbank` WHERE used = '1'";
$uid = $dbh->query($sql)->fetchColumn();
//now pickup the uid hit we just setup
return $uid;
//return the "safe" uid ready for use
}
这里也没有问题。它在我的单用户测试环境中运行良好。但是,我的SQL技能非常基础,所以我不是100%确定
我非常感谢有关如何改进此计划的任何提示。
答案 0 :(得分:0)
您是否因为使用序列号作为唯一标识符?这肯定是我的第一个建议,并且会否定你所拥有的复杂设置的必要性。
假设有一些原因,那么我在你当前的makeUID调用中可以看到的最大缺陷就是你可能会遇到这样一种情况,即更新将'used'设置为1并且通过辅助调用删除此行makeUID能够成功返回列之前意味着你的第二个选择(SELECT uid FROM uidbank
WHERE used ='1')将不返回任何行
你能解释为什么你不使用连续剧那么我可以尝试更好地了解发生了什么