繁体   English   中英

使用 psycopg2 缓存中间表

[英]Caching intermediate table with psycopg2

采取这个涉及两个SELECT的 psycopg2 调用块:

import psycopg2

with psycopg2.connect("dbname=test user=postgres") as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT a, b, c FROM table WHERE a > 5 and d < 10;")
        r1 = cur.fetchall()
        cur.execute("SELECT a, b, c FROM table WHERE a > 5 and d > 20;")
        r2 = cur.fetchall()

这有点低效; 潜在的 O(N) 检查WHERE a > 5似乎只执行一次,并在该中间结果上执行子查询。

通过 psycopg2 API 执行此操作的规范方法是什么?

就像是:

with psycopg2.connect("dbname=test user=postgres") as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT a, b, c FROM table WHERE a > 5")
        # ...
        cur.execute("SELECT a, b, c FROM temp_table WHERE d < 10;")
        r1 = cur.fetchall()
        cur.execute("SELECT a, b, c FROM temp_table WHERE d > 20;")
        r2 = cur.fetchall()

使用文字"CREATE TEMP TABLE..."的最佳解决方案是什么?

我从Django ORM的角度来看这个问题,QuerySet 的后续评估重用缓存的结果。 psycopg2 API 有没有类似的东西?

您可以执行单个查询并将结果拆分为两个列表:

with psycopg2.connect("dbname=test user=postgres") as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT a, b, c, d FROM my_table WHERE a > 5 and (d < 10 or d > 20);")
        rows = cur.fetchall()

r1 = [(i[0], i[1], i[2]) for i in rows if i[3] < 10]
r2 = [(i[0], i[1], i[2]) for i in rows if i[3] > 20]

在结果集不是很大的情况下,上述解决方案应该是最有效的。 或者,您可以创建一个临时表:

with psycopg2.connect("dbname=test user=postgres") as conn:
    with conn.cursor() as cur:
        cur.execute("""
            CREATE TEMP TABLE t AS
            SELECT a, b, c, d 
            FROM my_table 
            WHERE a > 5 and (d < 10 or d > 20);""")
        cur.execute("SELECT a, b, c FROM t WHERE d < 10;")
        r1 = cur.fetchall()
        cur.execute("SELECT a, b, c FROM t WHERE d > 20;")
        r2 = cur.fetchall()        

当连接关闭时,临时表将被自动删除。

如果结果集太大而无法在客户端实际处理,请使用服务器端 cursor。 当您在循环中获取单行时,这些行实际上是从存储桶中的服务器检索的。 您可以通过设置itersize来定义存储桶的大小。 .

r1 = []
r2 = []
with psycopg2.connect("dbname=test user=postgres") as conn:
    with conn.cursor('my_cursor') as cur:
        cur.itersize = 1000
        cur.execute("SELECT a, b, c, d FROM my_table WHERE a < 5 and (d < 10 or d > 20);")
        for row in cur:
            if row[3] < 10:
                r1.append((row[0], row[1], row[2]))
            else:
                r2.append((row[0], row[1], row[2]))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM