2011-01-23 2 views
2

次の2つのPythonコード例を考えてみましょう。Postgres:カーソルを使ったアップデートでの驚くべきパフォーマンス

import psycopg2, time 

conn = psycopg2.connect("dbname=mydatabase user=postgres") 
cur = conn.cursor('cursor_unique_name') 
cur2 = conn.cursor() 

startTime = time.clock() 
cur.execute("SELECT * FROM test for update;") 
print ("Finished: SELECT * FROM test for update;: " + str(time.clock() - startTime)); 
for i in range (100000): 
    cur.fetchone() 
    cur2.execute("update test set num = num + 1 where current of cursor_unique_name;") 
print ("Finished: update starting commit: " + str(time.clock() - startTime)); 
conn.commit() 
print ("Finished: update : " + str(time.clock() - startTime)); 

cur2.close() 
conn.close() 

そして:

import psycopg2, time 

conn = psycopg2.connect("dbname=mydatabase user=postgres") 
cur = conn.cursor('cursor_unique_name') 
cur2 = conn.cursor() 

startTime = time.clock() 
for i in range (100000): 
    cur2.execute("update test set num = num + 1 where id = " + str(i) + ";") 
print ("Finished: update starting commit: " + str(time.clock() - startTime)); 
conn.commit() 
print ("Finished: update : " + str(time.clock() - startTime)); 

cur2.close() 
conn.close() 

テーブルテストの作成文は次のとおりです。

CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar); 

そして、そのテーブルは100000行とVACUUMはTESTをANALYZE含まれています。実行されました。

私は次の結果をいくつかの試みで一貫して得ています。

最初のコード例:

Finished: SELECT * FROM test for update;: 0.00609304950429 
Finished: update starting commit: 37.3272754429 
Finished: update : 37.4449708474 

2番目のコード例:

これは私が思うだろうと私には非常に驚くべきことである
Finished: update starting commit: 24.574401185 
Finished committing: 24.7331461431 

は、カーソルを使用して、更新がなければならないことを意味し、全く逆であるべきですはるかに速くthis答えによると。

答えて

4

私は、あなたの最初のコードがカーソルからデータを取り出して更新しているのに対し、2番目のコードはデータを取得せずにIDで盲目的に更新しているとは限りません。私は、最初のコードシーケンスがFETCHコマンドに続いてUPDATE-に変換されると仮定します。これは、クライアント/サーバーの2つのコマンドの処理方法です。

は(それについて考えて、私はこの実際にパフォーマンスに影響を疑うが、あなたはそれを言及しなかったが、また最初のコードは、これは、バッファcache-にテーブル全体を引っ張る卓上に各行をロックすることにより開始します)

また、単純なテーブルの場合、ctidによる更新(多くの場合、where current of...が動作すると仮定しています)とプライマリキーを使用した更新との間に大きな違いはありません.pkey更新は余分なインデックスルックアップですが、インデックスは巨大なです。

このように100,000行を更新するには、前のタプルを見つけて削除済みとしてマークするのではなく、余分なタプルを生成してテーブルに追加するか、テーブルに追加することがほとんどだと思います。

関連する問題