我正在使用以下查询生成一个唯一的新用户:
INSERT INTO `users`
SET `display_name` = CONCAT(
'user',
(
IF(
EXISTS(
SELECT COUNT(`id`) FROM (
SELECT `id` FROM `users`
) AS `A`),
(SELECT COUNT(`id`) + 1 FROM (
SELECT `id` FROM `users`
) AS `A`),
1
)
)
);
列id
是INT和AUTO_INCREMENT PRIMARY KEY。列display_name
是VARCHAR并且不是NULL。此查询插入具有顺序显示名称的新用户,例如user1,user2,user3,user4,...
DESCRIBE返回了这个:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
3 DERIVED users index NULL UNIQUE 302 NULL NULL Using index
4 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
5 DERIVED users index NULL UNIQUE 302 NULL NULL Using index
这个查询有效吗?如果没有,什么是更有效的方法?
答案 0 :(得分:1)
将效率暂时搁置一秒,删除用户行后查询将无效。在这种情况下,Count将减少,您将重用旧的display_name。
话虽如此,MAX()
可能是更好地为您的逻辑提供服务的功能,并允许您摆脱EXISTS
检查和第二次查询。从而使更快。
然而,如果你的逻辑变得复杂。我建议根据您的MySQL版本查看用户定义的函数或过程。这些都是经过编译的,速度更快,看起来更清晰,即
INSERT INTO users SET display_name = UNIQUE_DISPLAY_NAME();
答案 1 :(得分:1)
您的查询不是一项好技术,因为它可能会导致种族异常并删除异常。
例如,如果两个客户端同时创建用户,则他们可以统计15个现有用户并且都分配用户16。
此外,如果您有15个用户,但删除了user10,那么count()将报告14,您将重新分配user15。
相反,我会将id设为自动生成的主键。 MySQL在事务隔离规则之外分配id值,因此保证并发客户端永远不会分配相同的值。
编辑:遗憾的是,您无法使用触发器,因为生成的键值在before触发器中不可用,并且您无法在after触发器中更改display_name的值。所以你必须在插入中执行此操作,然后进行更新。
INSERT INTO users DEFAULT VALUES;
UPADTE users SET display_name = CONCAT('user', LAST_INSERT_ID())
WHERE id = LAST_INSERT_ID();
不要担心差距。也就是说,如果user15永远不会被删除,回滚或其他什么,那也没关系。不要落入Pseudokey Neat-Freak antipattern。