簡體   English   中英

Python psycopg2游標

[英]Python psycopg2 cursors

從psycopg2文檔中:

執行數據庫查詢時,Psycopg游標通常會獲取后端返回的所有記錄,並將它們轉移到客戶端進程。 如果查詢返回了大量數據,則客戶端將按比例分配大量內存。 如果數據集太大而無法在客戶端實際處理,則可以創建服務器端游標。

我想查詢一個可能包含數千行的表,並對每個表執行一些操作。 普通游標會真正將整個數據集帶到客戶端嗎? 聽起來不太合理。 該代碼類似於以下內容:

conn = psycopg2.connect(url)
cursor = conn.cursor()
cursor.execute(sql)
for row in cursor:
    do some stuff
cursor.close()

我希望這是一個流操作。 第二個問題是關於游標的范圍。 在我的循環中,我想更新另一個表。 我是否需要打開一個新的光標並每次都關閉? 每個項目更新都應在自己的事務中,因為我可能需要回滾。

for row in cursor:
    anotherCursor = anotherConn.cursor()
    anotherCursor.execute(update)
    if somecondition:
        anotherConn.commit()
    else:
        anotherConn.rollback
cursor.close()

========編輯:我對第一部分的回答========

好的,我將嘗試回答問題的第一部分。 普通游標實際上會在您調用execute之后立即帶走整個數據集,甚至開始迭代結果集之前。 您可以通過在每個步驟檢查進程的內存占用量來進行驗證。 但是實際上需要服務器端游標是由於Postgres服務器而不是客戶端,並且在此處進行了說明: http : //www.postgresql.org/docs/9.3/static/sql-declare.html

現在,這在文檔中還不是很明顯,但是實際上可以在事務期間臨時創建此類游標。 無需使用特定的SLQ語句等顯式創建返回數據庫中的refcursor的函數。使用psycopg2,您僅需在獲取游標時給出名稱,便會為該事務創建一個臨時游標。 所以代替:

 cursor = conn.cursor()

您只需要:

 cursor = conn.cursor('mycursor')

就是這樣,它起作用了。 我假設在使用JDBC和設置fetchSize的情況下,相同的操作都是在后台進行的。 它只是更加透明。 在此處查看文檔: https : //jdbc.postgresql.org/documentation/head/query.html#query-with-cursor

您可以通過查詢同一事務內的pg_cursors視圖來測試此方法是否有效。 獲取客戶端游標后,服務器端游標出現,而關閉客戶端游標后,服務器端游標消失。 因此,最重要的是:我很高興對我的代碼進行更改,但是我必須說,對於那些沒有使用postgres的人來說,這是一個很大的難題。

實際上,您已經回答了問題;)。

  1. 是的,您應該使用服務器端光標來獲取流式傳輸的記錄http://initd.org/psycopg/docs/usage.html#server-side-cursors

從文檔:

CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS $$
BEGIN
    OPEN $1 FOR SELECT col FROM test;
    RETURN $1;
END;
$$ LANGUAGE plpgsql;

並在代碼中:

cur1 = conn.cursor()
cur1.callproc('reffunc', ['curname'])

cur2 = conn.cursor('curname')
for record in cur2:     # or cur2.fetchone, fetchmany...
    # do something with record
    pass
  1. 是的,如果您想使用服務器端游標獲取行,則應該打開新游標。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM