有3个挑战。
您的查询在表和之间没有JOIN
条件,这实际上是有限的- 您很可能不打算这样做。即每部符合条件的电话都与符合条件的每个组相结合。如果您有 100 部电话和 100 个组,则已经有 10,000 个组合。phones
groups
CROSS JOIN
插入不同的组合(group_id, phone_name)
避免插入table中已经存在group_phones
的行。
所有事情都认为它可能看起来像这样:
INSERT INTO group_phones(group_id, phone_name)
SELECT i.id, i.name
FROM (
SELECT DISTINCT g.id, p.name -- get distinct combinations
FROM phones p
JOIN groups g ON ??how are p & g connected??
WHERE g.id IN ($add_groups)
AND p.name IN ($phones)
) i
LEFT JOIN group_phones gp ON (gp.group_id, gp.phone_name) = (i.id, i.name)
WHERE gp.group_id IS NULL -- avoid duping existing rows
并发
这种形式最大限度地减少了并发写操作出现竞争条件的机会。如果您的表有 大量并发写入负载,您可能希望独占锁定表或使用可序列化事务隔离,这可以防止在约束验证(行不存在)和查询中的写操作。
BEGIN ISOLATION LEVEL SERIALIZABLE;
INSERT ...
COMMIT;
如果它因序列化错误而回滚,请准备好重复该事务。有关该主题的更多信息,好的起点可能是@depesz 的这篇博客文章或关于 SO 的相关问题。
但是,通常情况下,您甚至不必为此烦恼。
表现
LEFT JOIN tbl ON right_col = left_col WHERE right_col IS NULL
通常是右表中具有不同列的最快方法。如果您在列中有欺骗(特别是如果有很多),
WHERE NOT EXISTS (SELECT 1 FROM tbl WHERE right_col = left_col)
可能会更快,因为它可以在找到第一行后立即停止扫描。
您也可以使用IN
,就像 @dezso 演示的那样,但在 PostgreSQL 中它通常较慢。