psycopg2 postgresql driver for python don't support prepared statement Direct

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB PostgreSQL 版,企业版 4核16GB
推荐场景:
HTAP混合负载
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介:
前面使用py-postgresql测试过PostgreSQL性能, 可能是这个驱动效率较低, 我们接下来使用psycopg2测试一下.
psycopg2使用libpq接口, 支持2PC, 支持异步提交等,  但是不支持绑定变量.
安装
[root@localhost ~]# . /home/postgres/.bash_profile 
root@localhost-> which pg_config
/opt/pgsql9.3.5/bin/pg_config
[root@localhost ~]# pip3.4 install psycopg2 --upgrade
或
[root@localhost ~]# pip3.4 install psycopg2


异步操作, 对数据库端来说意义不大, 因为在执行的话, 不能再次提交SQL请求.
如下 :
import psycopg2
import time
import select
conn = psycopg2.connect(database="postgres", user="postgres", password="postgres", host="/data01/pgdata/pg_root", port="1921", async=True)
>>> def wait(conn):
...     while 1:
...         state = conn.poll()
...         if state == psycopg2.extensions.POLL_OK:
...             break
...         elif state == psycopg2.extensions.POLL_WRITE:
...             select.select([], [conn.fileno()], [])
...         elif state == psycopg2.extensions.POLL_READ:
...             select.select([conn.fileno()], [], [])
...         else:
...             raise psycopg2.OperationalError("poll() returned %s" % state)
... 

wait(conn)
curs = conn.cursor()
curs.execute("insert into tt values(%(id)s, 'digoal.zhou', 32, 'digoal@126.com', '276732431')", {"id": 1})
curs.execute("insert into tt values(%(id)s, 'digoal.zhou', 32, 'digoal@126.com', '276732431')", {"id": 1})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
psycopg2.ProgrammingError: execute cannot be used while an asynchronous query is underway
>>> wait(curs.connection)
>>> wait(curs.connection)
>>> curs.execute("insert into tt values(%(id)s, 'digoal.zhou', 32, 'digoal@126.com', '276732431')", {"id": 1})
>>> wait(curs.connection)
>>> curs.execute("insert into tt values(%(id)s, 'digoal.zhou', 32, 'digoal@126.com', '276732431')", {"id": 1})
>>> wait(curs.connection)
>>> conn.poll()
0
>>> curs.execute("insert into tt values(%(id)s, 'digoal.zhou', 32, 'digoal@126.com', '276732431')", {"id": 1})
>>> conn.poll()
0
>>> curs.execute("insert into tt values(%(id)s, 'digoal.zhou', 32, 'digoal@126.com', '276732431')", {"id": 1})
>>> conn.poll()
0
>>> psycopg2.extensions.POLL_OK
0
>>> psycopg2.extensions.POLL_WRITE
2
>>> psycopg2.extensions.POLL_READ
1


同时psycopg2不支持prepared statement
>>> curs.prepare("insert into tt values(%(id)s, 'digoal.zhou', 32, 'digoal@126.com', '276732431')")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'psycopg2._psycopg.cursor' object has no attribute 'prepare'
>>> dir(curs)
['__class__', '__delattr__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'arraysize', 'binary_types', 'callproc', 'cast', 'close', 'closed', 'connection', 'copy_expert', 'copy_from', 'copy_to', 'description', 'execute', 'executemany', 'fetchall', 'fetchmany', 'fetchone', 'itersize', 'lastrowid', 'mogrify', 'name', 'nextset', 'query', 'row_factory', 'rowcount', 'rownumber', 'scroll', 'scrollable', 'setinputsizes', 'setoutputsize', 'statusmessage', 'string_types', 'typecaster', 'tzinfo_factory', 'withhold']


为什么这么说呢?, 调用 curs.execute("insert into tt values(%(id)s, 'digoal.zhou', 32, 'digoal@126.com', '276732431')", {"id": 1})
你觉得是绑定变量吗? 看看PostgreSQL的日志吧 :
2015-02-05 22:37:32.901 CST,"postgres","postgres",69785,"[local]",54d37ee8.11099,1,"idle",2015-02-05 22:32:08 CST,3/1996971,0,LOG,00000,"statement: insert into tt values(1, 'digoal.zhou', 32, 'digoal@126.com', '276732431')",,,,,,,,"exec_simple_query, postgres.c:890",""

调用的是exec_simple_query接口, 当然不是绑定变量.

间接的使用绑定变量, 但实际上SQL调用的还是 exec_simple_query接口, 只是在处理execute这个SQL时使用到了绑定变量.
这个是较老的用法.
>>> curs.execute("prepare pre1(int) as insert into tt values($1, 'digoal.zhou', 32, 'digoal@126.com', '276732431')")
>>> conn.poll()
0
>>> curs.execute("execute pre1(1)")
>>> conn.poll()
0
>>> curs.execute("execute pre1(1)")
>>> conn.poll()
0

PostgreSQL日志 :
2015-02-05 22:50:42.678 CST,"postgres","postgres",69785,"[local]",54d37ee8.11099,5,"idle",2015-02-05 22:32:08 CST,3/1996975,0,LOG,00000,"statement: prepare pre1(int) as insert into tt values($1, 'digoal.zhou', 32, 'digoal@126.com', '276732431')",,,,,,,,"exec_simple_query, postgres.c:890",""
2015-02-05 22:50:59.425 CST,"postgres","postgres",69785,"[local]",54d37ee8.11099,6,"idle",2015-02-05 22:32:08 CST,3/1996976,0,LOG,00000,"statement: execute pre1(1)","prepare: prepare pre1(int) as insert into tt values($1, 'digoal.zhou', 32, 'digoal@126.com', '276732431')",,,,,,,"exec_simple_query, postgres.c:890",""
2015-02-05 22:51:22.425 CST,"postgres","postgres",69785,"[local]",54d37ee8.11099,7,"idle",2015-02-05 22:32:08 CST,3/1996977,0,LOG,00000,"statement: execute pre1(1)","prepare: prepare pre1(int) as insert into tt values($1, 'digoal.zhou', 32, 'digoal@126.com', '276732431')",,,,,,,"exec_simple_query, postgres.c:890",""

效率如何呢?
使用8个线程插入100W数据, 耗时41秒.
py-postgresql驱动耗时226秒, psycopg2效率高了很多, 接近pgbench的16秒了.
[root@localhost ~]# cat t.py
import psycopg2
import time
import threading



class n_t(threading.Thread):   #The timer class is derived from the class threading.Thread
  def __init__(self, num):
    threading.Thread.__init__(self)
    self.thread_num = num

  def run(self): #Overwrite run() method, put what you want the thread do here
    conn = psycopg2.connect(database="postgres", user="postgres", password="postgres", host="/data01/pgdata/pg_root", port="1921")
    curs = conn.cursor()
    conn.autocommit=True

    start_t = time.time()
    print("TID:" + str(self.thread_num) + " " + str(start_t))

    for i in range(self.thread_num*125000, (self.thread_num+1)*125000):
      curs.execute("insert into tt values(%(id)s, 'digoal.zhou', 32, 'digoal@126.com', '276732431')", {"id": i})

    stop_t = time.time()
    print("TID:" + str(self.thread_num) + " " + str(stop_t))
    print(stop_t-start_t)

def test():
  t_names = dict()
  for i in range(0,8):
    t_names[i] = n_t(i) 
    t_names[i].start()
  return

if __name__ == '__main__':
  test()

测试结果 : 
[root@localhost ~]# python t.py
TID:0 1423148404.5820847
TID:1 1423148404.5828164
TID:2 1423148404.5850544
TID:3 1423148404.58532
TID:4 1423148404.5861893
TID:5 1423148404.5867805
TID:6 1423148404.5882406
TID:7 1423148404.588671
TID:2 1423148445.146449
40.561394691467285
TID:7 1423148445.2051861
40.616515159606934
TID:6 1423148445.2321012
40.64386057853699
TID:1 1423148445.263236
40.68041968345642
TID:5 1423148445.2703242
40.68354368209839
TID:0 1423148445.2967775
40.71469283103943
TID:3 1423148445.3065617
40.72124171257019
TID:4 1423148445.3345916
40.74840235710144

postgres=# select count(*),count(distinct id) from tt;
  count  |  count  
---------+---------
 1000000 | 1000000
(1 row)

[参考]
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
3月前
|
机器学习/深度学习 算法 Python
Python高级算法——支持向量机(Support Vector Machine,SVM)
Python高级算法——支持向量机(Support Vector Machine,SVM)
180 2
|
1月前
|
分布式计算 DataWorks 关系型数据库
DataWorks操作报错合集之使用连接串模式新增PostgreSQL数据源时遇到了报错"not support data sync channel, error code: 0001",该怎么办
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
1月前
|
JSON 关系型数据库 API
Python 使用 FastAPI 和 PostgreSQL 构建简单 API
最近一年公司也在卷 LLM 的应用项目,所以我们也从 goper => Pythoner。 这一年使用最多的就是 Python 的 FastAPI 框架。下面一个简易项目让你快速玩转 Python API Web。 API代表应用程序编程接口,是软件开发中最重要的概念之一。它允许程序通过发送和接收数据与其他服务进行交互。API Web 通信最广泛使用的标准之一是 REST,它依赖于JSON 格式或键值对,类似于 Python 的字典。 如果想用 Python 构建一个,那么可以从几个框架中选择。Flask -RESTful、Django Rest Framework 和 FastAPI 是最受
|
2月前
|
SQL 关系型数据库 数据库
Python执行PostgreSQL数据库查询语句,并打印查询结果
本文介绍了如何使用Python连接和查询PostgreSQL数据库。首先,确保安装了`psycopg2`库,然后创建数据库连接函数。接着,展示如何编写SQL查询并执行,例如从`employees`表中选取所有记录。此外,还讨论了处理查询结果、格式化输出和异常处理的方法。最后,提到了参数化查询和事务处理以增强安全性及确保数据一致性。
Python执行PostgreSQL数据库查询语句,并打印查询结果
|
1月前
|
数据挖掘 Python
【Python】已解决 ImportError: Missing optional dependency ‘xlrd‘. Install xlrd >= 1.0.0 for Excel support
【Python】已解决 ImportError: Missing optional dependency ‘xlrd‘. Install xlrd >= 1.0.0 for Excel support
34 0
|
2月前
|
SQL 关系型数据库 数据库
Python查询PostgreSQL数据库
木头左教你如何用Python连接PostgreSQL数据库:安装`psycopg2`库,建立连接,执行SQL脚本如创建表、插入数据,同时掌握错误处理和事务管理。别忘了性能优化,利用索引、批量操作提升效率。下期更精彩!💡 csvfile
Python查询PostgreSQL数据库
|
3月前
|
监控 关系型数据库 Java
SpringBoot【集成 01】Druid+Dynamic+Greenplum(实际上用的是PostgreSQL的驱动)及 dbType not support 问题处理(附hikari相关配置)
SpringBoot【集成 01】Druid+Dynamic+Greenplum(实际上用的是PostgreSQL的驱动)及 dbType not support 问题处理(附hikari相关配置)
216 0
|
SQL 关系型数据库 测试技术
Python多进程并发写入PostgreSQL数据表
1、前言      前两天开了两个进程,把Python抓回的数据链接并发写入Mysql中,结果显示出错。后来一查才知道需要自己设置锁,好生麻烦。这时PostgreSQL进入了我的视野,因为这家伙原生就是多进程的,但它是否支持多进程并发写入呢,还需要实际实验一下才知道。
3075 0
|
Python
arserWarning: Falling back to the ‘python‘ engine because the ‘c‘ engine does not support regex sepa
arserWarning: Falling back to the ‘python‘ engine because the ‘c‘ engine does not support regex sepa
121 0
arserWarning: Falling back to the ‘python‘ engine because the ‘c‘ engine does not support regex sepa
|
Python
Python 修改tuple元组提示:TypeError: ‘tuple‘ object does not support item assignment. 问题原因
Python 修改tuple元组提示:TypeError: ‘tuple‘ object does not support item assignment. 问题原因
1134 0