当IterSize小于DATA SIZE并且FETCH NUMBER小于IterSIZE时,心理Copg2服务器端游标是如何操作的? [英] How does psycopg2 server side cursor operate when itersize is less than data size and fetch number is less than itersize?

查看:28
本文介绍了当IterSize小于DATA SIZE并且FETCH NUMBER小于IterSIZE时,心理Copg2服务器端游标是如何操作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了文档和几篇文章、帖子和帖子以及所有内容,但我不确定我是否清楚地理解了这一点。让我们假设这个场景:

1. I have a server side cursor.
2. I set the itersize to 1000.
3. I execute a SELECT query which would normally return 10000 records.
4. I use fetchmany to fetch 100 records at a time.

我的问题是这是如何在幕后完成的?我的理解是,查询被执行,但是服务器端游标读取了1000条记录。除非光标滚动经过当前读取的1000的最后一条记录,否则光标不会读取下一个1000。此外,服务器端游标将1000保存在服务器内存中,并一次滚动100个,将它们发送到客户端。我也很想知道公羊的消费会是什么样子?根据我的理解,如果执行完整查询需要10000 kb的内存,服务器端游标将仅占用服务器上的1000kb,因为它一次仅读取1,000条记录,而客户端游标将使用100kb。我的理解正确吗?

更新 根据文档和我们在响应中进行的讨论,我希望此代码一次打印一个包含10个项目的列表:

from psycopg2 import connect, extras as psg_extras
    
with connect(host="db_url", port="db_port", dbname="db_name", user="db_user", password="db_password") as db_connection:
     with db_connection.cursor(name="data_operator", 
         cursor_factory=psg_extras.DictCursor) as db_cursor:
         db_cursor.itersize = 10
         db_cursor.execute("SELECT rec_pos FROM schm.test_data;")
         for i in db_cursor:
             print(i)
             print(">>>>>>>>>>>>>>>>>>>")
但是,在每次迭代中,它只打印一条记录。我获得10条记录的唯一方法是使用FETCHMANY:

from psycopg2 import connect, extras as psg_extras
    
with connect(host="db_url", port="db_port", dbname="db_name", user="db_user", password="db_password") as db_connection:
     with db_connection.cursor(name="data_operator", 
        cursor_factory=psg_extras.DictCursor) as db_cursor:
        db_cursor.execute("SELECT rec_pos FROM schm.test_data;")
         records = db_cursor.fetchmany(10)
         while len(records) > 0:
             print(i)
             print(">>>>>>>>>>>>>>>>>>>")
             records = db_cursor.fetchmany(10)

根据这两个代码片段,我猜测在前面提到的场景中正在发生的情况是,根据下面的代码...

from psycopg2 import connect, extras as psg_extras
    
with connect(host="db_url", port="db_port", dbname="db_name", user="db_user", password="db_password") as db_connection:
    with db_connection.cursor(name="data_operator", 
        cursor_factory=psg_extras.DictCursor) as db_cursor:
        db_cursor.itersize = 1000
        db_cursor.execute("SELECT rec_pos FROM schm.test_data;")
        records = db_cursor.fetchmany(100)
        while len(records) > 0:
            print(i)
            print(">>>>>>>>>>>>>>>>>>>")
            records = db_cursor.fetchmany(100)

.迭代大小是服务器端的事情。它所做的是,当查询运行时,它将限制为仅从数据库加载1000条记录。但FetchMany是一件客户端的事情。它从服务器获得1000个中的100个。每次获取多个运行时,都会从服务器获取下一个100。当服务器端上的所有1000个都滚动后,将从服务器端的数据库中提取下一个1000个。但我感到相当困惑,因为这似乎不是医生们所暗示的。但话又说回来。代码似乎暗示了这一点。

推荐答案

我会在这里花一些时间Server side cursor

您将发现itersize仅适用于您在游标上迭代时:

for record in cur:
     print record
由于您使用的是fetchmany(size=100),因此一次只能处理100行。<%s>服务器将无法在内存中容纳1000行。我搞错了。游标将把内存中的所有行返回给客户端,如果没有使用指定的游标,fetchmany()将以指定的批处理大小从那里拉取行。如果使用命名游标,则它将以批处理大小从服务器提取。

更新。演示itersizefetchmany()如何工作。

itersizefetchmany()与命名游标一起使用:

cur = con.cursor(name='cp')
cur.itersize = 10
cur.execute("select * from cell_per")
for rs in cur:     
   print(rs) 
cur.close()

#Log
statement: DECLARE "cp" CURSOR WITHOUT HOLD FOR select * from cell_per
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: CLOSE "cp"

cur = con.cursor(name='cp') 
cur.execute("select * from cell_per")
cur.fetchmany(size=10) 

#Log
statement: DECLARE "cp" CURSOR WITHOUT HOLD FOR select * from cell_per
statement: FETCH FORWARD 10 FROM "cp"

fetchmany与未命名游标一起使用:

cur = con.cursor()
cur.execute("select * from cell_per")
rs = cur.fetchmany(size=10)
len(rs)                                                                                                                                                                   
10

#Log
statement: select * from cell_per

因此,指定的游标在迭代时按itersize设置的批处理获取行(从服务器),或在使用fetchmany(size=n)时按size设置的批处理提取行。而未命名游标将所有行拉入内存,然后根据fetchmany(size=n)中设置的size从内存中取出它们。

进一步更新

itersize仅当您迭代光标对象本身时才适用:

cur = con.cursor(name="cp")
cur.itersize = 10 
cur.execute("select * from cell_per")
for r in cur: 
    print(r) 
cur.close()

#Postgres log:
statement: DECLARE "cp" CURSOR WITHOUT HOLD FOR select * from cell_per
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: FETCH FORWARD 10 FROM "cp"
statement: CLOSE "cp"
在上面的r中,将从服务器端(命名的)游标返回的每批10行中提取一行。该批大小=itersize。因此,当您迭代指定的游标对象本身时,查询指定的所有行都将在迭代器中返回,只是成批返回itersize

未迭代命名的游标对象。使用fetchmany(size=n)

cur = con.cursor(name="cp") 
cur.itersize = 10
cur.execute("select * from cell_per") 
cur.fetchmany(size=20)
cur.fetchmany(size=20)
cur.close()

#Postgres log:
statement: DECLARE "cp" CURSOR WITHOUT HOLD FOR select * from cell_per
statement: FETCH FORWARD 20 FROM "cp"
statement: FETCH FORWARD 20 FROM "cp"
CLOSE "cp"
已设置itersize,但它作为命名的游标对象无效 没有被迭代。相反,fetchmany(size=20)让服务器端游标在每次调用时发送一批20条记录。

这篇关于当IterSize小于DATA SIZE并且FETCH NUMBER小于IterSIZE时,心理Copg2服务器端游标是如何操作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆