2011-11-01 37 views
5

Tôi có một bảng tmp_drop_ids với một cột, id và 3,3 triệu mục nhập. Tôi muốn lặp lại trên bảng, làm một cái gì đó với mỗi 200 mục. Tôi có mã này:postgresql: offset + giới hạn sẽ rất chậm

LIMIT = 200 
for offset in xrange(0, drop_count+LIMIT, LIMIT): 
    print "Making tmp table with ids %s to %s/%s" % (offset, offset+LIMIT, drop_count) 
    query = """DROP TABLE IF EXISTS tmp_cur_drop_ids; CREATE TABLE tmp_cur_drop_ids AS 
    SELECT id FROM tmp_drop_ids ORDER BY id OFFSET %s LIMIT %s;""" % (offset, LIMIT) 
    cursor.execute(query) 

Điều này chạy tốt, lúc đầu, (~ 0,15 giây để tạo bảng tmp), nhưng đôi khi sẽ chậm lại, ví dụ: khoảng 300k vé nó bắt đầu lấy 11-12 giây để tạo ra bảng tmp này, và một lần nữa khoảng 400k. Về cơ bản nó có vẻ không đáng tin cậy.

Tôi sẽ sử dụng các id đó trong các truy vấn khác vì vậy tôi đã tìm ra nơi tốt nhất để có chúng trong bảng tmp. Có cách nào tốt hơn để lặp qua các kết quả như thế này không?

+0

Bạn đã lập chỉ mục tmp_drop_ids chưa? TẠO MẪU ĐỘC ĐÁO TỪ INDEX tmp_drop_ids_id_uidx TRÊN tmp_drop_ids (id); – filiprem

+0

@filiprem: i do yes – Claudiu

Trả lời

9

Sử dụng con trỏ để thay thế. Sử dụng một OFFSET và LIMIT là khá tốn kém - bởi vì pg phải thực hiện truy vấn, xử lý và bỏ qua một hàng OFFSET. OFFSET giống như "hàng bỏ qua", điều đó rất đắt.

cursor documentation

Cursor cho phép một sự lặp lại hơn một truy vấn.

BEGIN 
DECLARE C CURSOR FOR SELECT * FROM big_table; 
FETCH 300 FROM C; -- get 300 rows 
FETCH 300 FROM C; -- get 300 rows 
... 
COMMIT; 

Có lẽ bạn có thể sử dụng một con trỏ phía máy chủ mà không sử dụng rõ ràng của câu lệnh DECLARE, chỉ với sự hỗ trợ trong psycopg (phần tìm kiếm về con trỏ phía máy chủ).

+0

tôi đã làm điều này từ python (sử dụng 'fetchmany' của đối tượng con trỏ). – Claudiu

2

Nếu id của bạn được lập chỉ mục, bạn có thể sử dụng "giới hạn" với ">", ví dụ như trong giả trăn giống như:

limit=200 
max_processed_id=-1 
query ("create table tmp_cur_drop_ids(id int)") 
while true: 
    query("truncate tmp_cur_drop_ids") 
    query("insert into tmp_cur_drop_ids(id)" \ 
     + " select id from tmp_drop_ids" \ 
     + " where id>%d order by id limit %d" % (max_processed_id, limit)) 
    max_processed_id = query("select max(id) from tmp_cur_drop_ids") 
    if max_processed_id == None: 
    break 
    process_tmp_cur_drop_ids(); 
query("drop table tmp_cur_drop_ids") 

Bằng cách này Postgres có thể sử dụng chỉ số cho truy vấn của bạn.

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