2015-05-24 22 views
7

Từ tài liệu psycopg2:Python psycopg2 con trỏ

Khi một truy vấn cơ sở dữ liệu được thực hiện, con trỏ Psycopg thường lấy về tất cả các hồ sơ được trả về bởi các phụ trợ, chuyển chúng đến quá trình khách hàng. Nếu truy vấn trả lại một lượng lớn dữ liệu, một lượng bộ nhớ lớn sẽ được phân bổ bởi máy khách. Nếu tập dữ liệu quá lớn để được xử lý thực tế ở phía máy khách, có thể tạo con trỏ phía máy chủ.

Tôi muốn truy vấn bảng có thể có hàng nghìn hàng và thực hiện một số hành động cho mỗi hàng. Con trỏ bình thường có thực sự mang toàn bộ tập dữ liệu trên máy khách không? Điều đó nghe không hợp lý lắm. Mã này nằm dọc theo dòng:

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

Tôi hy vọng đây là một hoạt động truyền trực tuyến. Và câu hỏi thứ hai liên quan đến phạm vi của con trỏ. Bên trong vòng lặp của tôi, tôi muốn cập nhật một bảng khác. Tôi có cần phải mở một con trỏ mới và đóng mỗi lần không? Mỗi cập nhật mục phải nằm trong giao dịch của riêng mình vì tôi có thể cần phải thực hiện khôi phục.

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

======== EDIT: ĐÁP CỦA TÔI ĐẾN ĐẦU ======== PHẦN

Ok, tôi sẽ cố gắng trả lời phần đầu của câu hỏi của tôi. Các con trỏ bình thường thực sự mang toàn bộ tập dữ liệu ngay khi bạn gọi thực thi, thậm chí trước khi bắt đầu lặp lại tập kết quả. Bạn có thể xác minh điều đó bằng cách kiểm tra dấu chân bộ nhớ của quá trình tại mỗi bước. Nhưng nhu cầu về con trỏ phía máy chủ thực sự là do máy chủ postgres chứ không phải máy khách và được ghi lại ở đây: http://www.postgresql.org/docs/9.3/static/sql-declare.html

Bây giờ, điều này không rõ ràng ngay từ tài liệu, nhưng con trỏ này thực sự có thể được tạo tạm thời cho thời hạn của giao dịch. Không cần phải tạo một hàm một cách rõ ràng trả về một refcursor trong cơ sở dữ liệu, với câu lệnh SLQ cụ thể, v.v. Với psycopg2 bạn chỉ cần đặt tên trong khi lấy con trỏ và con trỏ tạm thời sẽ được tạo cho giao dịch đó. Vì vậy, thay vì:

cursor = conn.cursor() 

bạn chỉ cần để:

cursor = conn.cursor('mycursor') 

Đó là nó và nó hoạt động. Tôi cho rằng điều tương tự cũng được thực hiện dưới các trình bày khi sử dụng JDBC, khi thiết lập fetchSize. Nó chỉ là một chút minh bạch hơn. Xem tài liệu tại đây: https://jdbc.postgresql.org/documentation/head/query.html#query-with-cursor

Bạn có thể kiểm tra tài liệu này hoạt động bằng cách truy vấn chế độ xem pg_cursors bên trong cùng một giao dịch. Con trỏ phía máy chủ xuất hiện sau khi có con trỏ phía máy khách và biến mất sau khi đóng con trỏ phía máy khách. Vì vậy, dòng dưới cùng: Tôi hạnh phúc để làm điều đó thay đổi mã của tôi, nhưng tôi phải nói đây là một gotcha lớn cho một người không có kinh nghiệm với postgres.

+0

Bạn có thể tránh tất cả lưu lượng truy cập đó và công việc con trỏ bằng cách chọn và cập nhật trong cùng một truy vấn. Đăng các truy vấn thực sự và rất có khả năng bạn sẽ nhận được câu trả lời tốt hơn nhiều. –

+0

Tôi đoán bạn có ý nghĩa với tuyên bố "cập nhật ở đâu", đúng không? Trong trường hợp sử dụng của tôi, việc xử lý khá phức tạp hơn thế. –

+0

Tôi có nghĩa là truy vấn CTE. Bất kể sự phức tạp. –

Trả lời

0

Thực tế, bạn đã trả lời câu hỏi;).

  1. Có bạn nên sử dụng máy chủ bên con trỏ để lấy hồ sơ trực tiếp http://initd.org/psycopg/docs/usage.html#server-side-cursors

Từ tài liệu:

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

Và trong mã:

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. Có bạn nên mở mới con trỏ, nếu bạn muốn có các hàng có con trỏ phía máy chủ.
+0

Vì vậy, với con trỏ bình thường ngay khi tôi thực thi sql, toàn bộ tập kết quả sẽ được nạp vào bộ nhớ? Nếu tôi không có quyền truy cập vào cơ sở dữ liệu để tạo một đối tượng phía máy chủ thì sao? Không có thứ gì giống như một tập kết quả JDBC? Cảm ơn –

+0

Xem ví dụ trong trình điều khiển JDBC mà không cần có con trỏ phía máy chủ rõ ràng: https://jdbc.postgresql.org/documentation/head/query.html#query-with-cursor –

+0

tài liệu: Khi truy vấn cơ sở dữ liệu được thực thi , con trỏ Psycopg thường lấy tất cả các bản ghi được trả về bởi chương trình phụ trợ, chuyển chúng đến quy trình khách hàng. Nếu truy vấn trả lại một lượng lớn dữ liệu, một lượng bộ nhớ lớn sẽ được phân bổ bởi máy khách. – kwarunek

Các vấn đề liên quan