在我的数据库模式中,我有一个已识别的实体。标识符可以重复使用,因此与实体存在一对多的关系。示例:一个人可以有一个昵称。昵称不是唯一的,可以在很多人之间共享。因此架构可能如下所示:
PERSON
id
name
nickname_id
NICKNAME
id
name
问题是,在插入新人时,我必须首先查询NICKNAME
以查看昵称是否存在。如果没有,那么我必须在NICKNAME
中创建一行。当插入许多人时,这可能会很慢,因为每个人插入都会导致查询NICKNAME
。
我可以通过首先查询所有昵称的昵称来优化大插入。 JPA查询语言:
SELECT n FROM NICKNAME n WHERE name in ('Krusty', 'Doppy', 'Flash', etc)
然后根据需要创建新的昵称,然后在人员上设置nickname_id。
这使得软件变得复杂,因为它必须暂时将昵称存储在内存中。此外,某些数据库对IN
子句的参数有限制(SQL Server为2100左右),因此我执行了多次查询。
我很好奇其他人如何处理这个问题。更具体地,当数据库被规范化并且实体与另一个实体具有关系时,插入新实体基本上导致必须检查另一个实体。对于大型插入,除非将操作提升到代码域,否则这可能很慢。有没有办法自动插入相关的表行?
仅供参考我正在使用Hibernate的JPA实现
答案 0 :(得分:1)
我不确定ORM是否可以处理这个问题,但是在直接SQL中你可以:
在您的示例中,除了一个人可以拥有多个昵称之外,您可以只使用另一个表中的NULLable昵称列。
答案 1 :(得分:0)
如实?我在昵称表中将昵称设为varchar列,并忘记了昵称表。昵称是一个人的属性,而不是一个单独的实体。
这是一个简化的示例,您的'标识符'真的做从实体关系中受益吗?
编辑:好的,明白这只是一个人为的例子。这个问题很好,因为它经常出现。
标准SQL支持带有可选“...ON DUPLICATE KEY UPDATE...
”子句的INSERT语句形式。对此语法的支持因数据库品牌而异。如果在Nickname表中为标识符名称添加UNIQUE
约束,则重复的条目将调用该子句的UPDATE
部分(您可以执行虚拟更新,而不是更改任何内容)。
CREATE TABLE Nickname (
id SERIAL PRIMARY KEY,
name VARCHAR(20) UNIQUE
);
INSERT INTO Nickname (name) VALUES ("Bill")
ON DUPLICATE KEY UPDATE name = name;
答案 2 :(得分:0)
INSERT INTO Person(Name, NicknameID)
VALUES(:name, (SELECT id FROM Nickname WHERE Name = :nickname))
如果INSERT由于昵称不存在而失败,则插入昵称,然后插入人员记录。
我假设:name和:nickname标识包含用户名和昵称的主机变量 - 并且当从SQL中省略该person.id列时,将自动为该person.id列分配值。适应您的情况。
如果您认为大多数昵称实际上都是唯一的,您可以简单地尝试无条件地插入昵称,但忽略昵称已经存在时发生的错误。
答案 3 :(得分:0)
或许,或许'MERGE'声明可能有帮助吗?它提供了插入新值或更新existsng值的选项。语法和支持因DB而异,但可能比'ON DUPLICATE'选项更常见。