在INSERT或IGNORE之后获取PRIMARY KEY的ID

时间:2017-03-04 22:22:25

标签: python sqlite optimization query-optimization

我正在使用sqlite并且有一个如下所示的表:

CREATE TABLE IF NOT EXISTS dirnames (dirnameid INTEGER PRIMARY KEY,
                                     dirname TEXT NOT NULL UNIQUE);
CREATE INDEX IF NOT EXISTS dirnames_idx1 ON dirnames(dirnameid);
CREATE INDEX IF NOT EXISTS dirnames_idx2 ON dirnames(dirname);

我想获得任意目录的dirnameid,所以现在我正在做一些看起来像这样的事情:

INSERT or IGNORE INTO dirnames (dirname) VALUE (?)
SELECT dirnameid from dirnames where dirname=?

?替换为我的目录名。

有更有效的方法吗

1 个答案:

答案 0 :(得分:1)

无法进一步优化此查询,因为它需要在sqlite上执行此操作的命令 - 该操作不存在。

但是,有一种方法可以“优化”这个:你可以尝试使用LBYL,如果目录已经存在,你可以“保存”往返。

伪代码(因为我不知道你的代码是怎么样的):

import sqlite3

#(...)

connection = sqlite3.connect(':memory:')
cursor = connection.cursor()

dirname = 'foo'
dirnameid = None

cursor.execute("SELECT dirnameid from dirnames where dirname=?;", (dirname,))
dirnameid = cursor.fetchone()[0]

if not dirnameid:
    cursor.execute("INSERT or IGNORE INTO dirnames (dirname) VALUES (?);", (dirname,))

    # WARNING: The following line should be used if, and ONLY if the access to the sqlite is not concurrent (AKA: Only one connection inserting to the table)
    dirnameid = cursor.lastrowid

    # Otherwise, use this:
    cursor.execute("SELECT dirnameid from dirnames where dirname=?;", (dirname,))
    dirnameid = cursor.fetchone()[0]

connection.close()

可悲的是,如果这不是表上唯一的程序/线程,这段代码将添加另一个往返。

但我必须警告你,这似乎是一个不成熟的优化,应该不惜一切代价避免! (https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil