我想要一个将名称映射到唯一ID的sqlite表。我可以通过以下方式创建此表:
CREATE TABLE name_to_id (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)
使用select语句,我可以得到包含所需名称的行,并从该行获取相应的ID。
如果我尝试获取表中尚未包含的名称的ID,则会出现此问题。在这种情况下,预期的行为是将添加新名称并返回其新生成的ID。我有两个可能的解决方案/实现。
第一个解决方案很简单:
我不喜欢这个解决方案,因为可能会发生第一个进程检查表中是否有名称,它看到名称不存在,同时另一个进程将名称添加到表中然后第一个进程尝试添加相同的名称。
第二种解决方案似乎更好:
insert if not exist
。第二种解决方案是最优的还是有更好的解决方案?
答案 0 :(得分:0)
避免表中重复条目的常规方法是创建唯一约束。如果记录已存在,数据库将检查您是否存在,如果存在则失败。在可靠性和性能方面,这应该是最好的。
接下来,SQLite FAQ建议使用函数last_insert_rowid()来获取ID,而不是运行第二个查询。这实际上是FAQ的第一个问题;)
答案 1 :(得分:0)
在伪代码中,第一个解决方案如下所示:
cursor = db.execute("SELECT id FROM name_to_id WHERE name = ?", name)
if cursor.has_some_row:
id = cursor["id"]
else:
db.execute("INSERT INTO name_to_id(name) VALUES(?)", name)
id = db.last_insert_rowid
和第二个像这样:
db.execute("INSERT OR IGNORE INTO name_to_id(name) VALUES(?)", name)
cursor = db.execute("SELECT id FROM name_to_id WHERE name = ?", name)
id = cursor["id"]
第一个解决方案需要围绕这两个命令进行事务处理,但对于第二个解决方案来说,这也是一个好主意,以避免多个隐式事务的开销。
第二个解决方案需要name
上的唯一constaint,但对于第一个解决方案来说,这也是一个好主意,正确性和加速name
查找。
两种解决方案都使用两个SQL语句,速度相似。 (第二次搜索该行两次,但该数据被缓存。) 所以没有任何明显的东西使另一个更好。