【问题标题】:question about postgresql bind variables关于postgresql绑定变量的问题
【发布时间】:2010-11-24 04:40:08
【问题描述】:

我正在查看question 并决定尝试使用绑定变量。我用

sql = 'insert into abc2 (interfield,textfield) values (%s,%s)'
a = time.time()
for i in range(10000):
    #just a wrapper around cursor.execute
    db.executeUpdateCommand(sql,(i,'test'))

db.commit()

sql = 'insert into abc2 (intfield,textfield) values (%(x)s,%(y)s)'
for i in range(10000):
    db.executeUpdateCommand(sql,{'x':i,'y':'test'})

db.commit()

看这两组的时间,上面好像没有太大的时差。事实上,第二个需要更长的时间。如果我在某个地方犯了错误,有人可以纠正我吗?在这里使用 psycopg2。

【问题讨论】:

    标签: python postgresql psycopg2


    【解决方案1】:

    查询在 Postgresql 中是等价的。

    Bind 是 oracle 的术语。使用时会保存查询计划,这样下次执行会快一点。 prepare 在 Postgres 中做同样的事情。

    http://www.postgresql.org/docs/current/static/sql-prepare.html

    psycopg2 支持内部“绑定”,而不是 preparecursor.executemany()cursor.execute()

    (但不要称其为绑定到 pg 人。称其为准备,否则他们可能不知道您的意思:)

    【讨论】:

      【解决方案2】:

      重要更新: 我已经查看了所有 python 库的源代码以连接到 FreeBSD 端口中的 PostgreSQL,并且可以说,只有 py-postgresql 会执行真正的准备好的语句!但它只是 Python 3+。

      py-pg_queue 也是一个有趣的库,实现了官方 DB 协议(python 2.4+)


      您错过了关于尽可能多地使用准备好的语句的问题的答案。 “绑定变量”是更好的形式,让我们看看:

      sql_q = 'insert into abc (intfield, textfield) values (?, ?)'  # common form 
      sql_b = 'insert into abc2 (intfield, textfield) values (:x , :y)' # should have driver and db support
      

      所以你的测试应该是这样的:

      sql = 'insert into abc2 (intfield, textfield) values (:x , :y)'
      for i in range (10000):
          cur.execute(sql, x=i, y='test')
      

      或者这个:

      def _data(n):
          for i in range (n):
               yield (i, 'test')
      sql = 'insert into abc2 (intfield, textfield) values (? , ?)'    
      cur.executemany(sql, _data(10000))
      

      等等。

      更新: 我刚刚发现 interest reciple 如何用准备好的和使用 %(name)s 透明地替换 SQL 查询

      【讨论】:

      • @Eir,我认为在 psycopg2 中绑定变量被指定为 %(name)s,不是吗?
      • 我会非常小心使用这种形式的 SQL,并且可能不会在生产中使用它。
      • @eir,认为我的问题是错误的。他们都做同样的事情,但就像 @nate 和 @forest 所说的那样,它特定于 oracle。
      • 这里的所有示例在 psycopg2 中的作用基本相同:它们将查询及其参数传递给连接器,连接器将它们组合起来并将结果字符串发送到服务器。 (公平地说,除非您检查 psycopg2 的源代码,否则很难判断这是否正在发生。)这不是当您使用“绑定变量”(Oracle 短语)时会发生的情况。对于“绑定变量”行为,您需要将查询和参数分别发送到服务器,以便服务器的查询计划器有机会在使用或不使用特定参数值的情况下进行优化。
      • '绑定变量'和'准备好的语句'相同
      【解决方案3】:

      据我所知,psycopg2 从未支持服务器端参数绑定(Oracle 用语中的“绑定变量”)。当前版本的 PostgreSQL 确实在协议级别使用准备好的语句支持它,但只有少数连接器库使用它。 Postgres wiki notes this here。以下是您可能想尝试的一些连接器:(我自己没有使用过这些。)

      只要您使用 DB-API 调用,您可能应该考虑 cursor.executemany() 而不是重复调用 cursor.execute()。

      此外,在 PostgreSQL 中将参数绑定到它们在服务器中(而不是在连接器中)的查询并不总是更快。注意this FAQ entry

      【讨论】:

      • cursor.executemany() 为 pyscopg2 initd.org/psycopg/docs/cursor.html#cursor.executemany'绑定'
      • 您会这么认为,但是如果您查看源代码,您会发现 psycopg2 对 execute() 和 executemany() 使用相同的代码。它在库中进行自己的参数绑定,而不是准备一条语句并将其发送到服务器进行绑定。
      • 因此,psycopg2 的 executemany() 可能会比 execute() 稍微快一点,因为它保留在已编译的代码中,而不是多次切换回 python 解释器,但它仍然没有执行当您使用Oracle 术语“绑定变量”。
      • 不幸的是,psycopg2 文档和 PostgreSQL 文档使用“准备”这个词来表示不同的东西,这令人困惑。 postgresql.org/docs/8.0/interactive/libpq-exec.html
      • dba-oracle.com/t_bind_variables.htm 表示 oracle 正在准备每个语句并通过字符串的哈希索引跟踪它。那么你将不得不在 pg 中手动调用 prepare 以获得等效性,对吧?
      最近更新 更多