Python的DB-API中游标是如何工作的?

33

我一直在使用Python与关系型数据库(MySQL和PostgreSQL),但是我注意到我真的不太了解如何使用游标。

通常,人们会使用客户端DB-API(例如psycopg2或MySQLdb)使脚本连接到数据库:

connection = psycopg2.connect(host='otherhost', etc)

然后创建一个游标:

cursor = connection.cursor()

然后可以发出查询和命令:

cursor.execute("SELECT * FROM etc")

现在问题来了,查询结果在哪里呢?是在服务器上吗?还是一部分在我的客户端上,一部分在我的服务器上?如果我们需要访问一些结果,那么我们就会去获取它们:

rows = cursor.fetchone() 
或者
rows = cursor.fetchmany()

现在假设我并没有检索到所有的行,并决定执行另一个查询,那么之前的结果会发生什么?它们是否会带来额外的开销。

此外,对于每种命令,我是否应该创建一个光标,并以某种方式不断地重复使用它?我听说 psycopg2 可以优化那些执行多次但具有不同值的命令,如何进行优化,这样做值得吗?

谢谢


3
从FAQ(http://initd.org/psycopg/docs/faq.html)中有关游标最佳实践的回复:“我们建议几乎总是创建一个新游标,并在不再需要数据时立即处理旧游标(对它们调用close())。唯一的例外是紧密循环,其中通常使用同一个游标进行整个INSERT或UPDATE批量操作。” - Matthew Cornell
3个回答

9

哎呀,我知道这已经是几个月前的事情了 :P

DB-API的游标似乎是紧密模仿SQL游标而来。就资源(rows)管理而言,DB-API并没有规定客户端必须检索所有行或声明实际的SQL游标。只要fetchXXX接口按预期运行,DB-API就满足。

就AFA psycopg2游标而言(你可能已经知道),“未命名的DB-API游标”将获取整个结果集——据我所知,由libpq在内存中缓冲。“命名的DB-API游标”(一种可能不可移植的psycopg2概念)将按需请求行(fetchXXX方法)。

如“unbeknown”所引用的,executemany可用于优化多次运行相同命令的情况。但是,它不能满足预处理语句的需求;当需要使用不直接连续的不同参数集重复执行语句时,executemany()的性能与execute()相同。DB-API确实“提供”了驱动程序作者缓存已执行语句的能力,但其实现方式(语句的范围/生命周期是什么?)未定义,因此无法在DB-API实现之间设置期望。

如果您正在向PostgreSQL加载大量数据,强烈建议尝试找到一种使用COPY的方法。


2
假设您正在使用PostgreSQL,那么游标可能只是使用数据库的本机游标API实现的。您可能需要查看pg8000的源代码,这是一个纯Python的PostgreSQL DB-API模块,以了解它如何处理游标。您还可以查看PostgreSQL游标文档

1

当你查看mysqldb文档时,可以看到他们为游标实现了不同的策略。所以一般的答案是:这取决于情况。

编辑:这里是mysqldb API文档。有一些关于每个游标类型行为的信息。标准游标将结果集存储在客户端中。因此,如果您不检索所有结果行,则会产生开销,因为您没有获取的行也必须传输到客户端(可能通过网络)。我的猜测是它与postgresql并没有太大的区别。

当您想要优化重复调用多个值的SQL语句时,您应该查看cursor.executemany()。它准备了一个SQL语句,以便每次调用它时不需要解析它:

cur.executemany('INSERT INTO mytable (col1, col2) VALUES (%s, %s)',
                [('val1', 1), ('val2', 2)])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接