2011-11-01 36 views
5

我有一個表tmp_drop_ids與一列,id,和330萬條目。我想遍歷表格,每200個條目做一些事情。我有這樣的代碼:postgresql:偏移+限制變得非常緩慢

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) 

這運行正常,首先,(0.15秒〜生成TMP表),但它偶爾會慢下來,例如大約30萬張門票開始花費11-12秒來生成這張tmp表格,並且再次大約40萬張。它基本上看起來不可靠。

我會在其他查詢中使用這些ID,所以我想到了讓他們在tmp表中的最佳位置。有沒有更好的方法來迭代這樣的結果?

+0

你有tmp_drop_ids索引嗎? CREATE UNIQUE INDEX tmp_drop_ids_id_uidx ON tmp_drop_ids(id); – filiprem

+0

@filiprem:我是的 – Claudiu

回答

9

改爲使用遊標。使用OFFSET和LIMIT非常昂貴 - 因爲pg必須執行查詢,處理並跳過OFFSET行。 OFFSET就像是「跳過行」,這很貴。

cursor documentation

光標允許在一個查詢中的迭代。

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

也許你可以使用服務器端遊標沒有明確的使用DECLARE語句,只是在psycopg(有關服務器端遊標搜索部分)的支持。

+0

我最終從python做了這個(使用遊標對象的'fetchmany')。 – Claudiu

2

如果您的ID被編入索引,您可以使用「限制」和「>」,例如在蟒蛇般的僞代碼:

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") 

這樣的Postgres可以使用索引查詢。