2

次の 2 つの Python コードの例を考えてみましょう。これらは同じことを実現しますが、パフォーマンスには驚くほど大きな違いがあります。

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 ステートメントは次のとおりです。

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

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

いくつかの試行で一貫して次の結果が得られました。

最初のコード例:

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

これは私にとって非常に驚くべきことです。これは正反対である必要があると思います。つまり、この回答によると、カーソルを使用した更新が大幅に高速になるはずです。

4

1 に答える 1

4

テストのバランスが取れているとは思いません。最初のコードはカーソルからデータをフェッチしてから更新しますが、2番目のコードはデータをフェッチせずにIDで盲目的に更新します。最初のコードシーケンスがFETCHコマンドに変換され、その後にUPDATE-が続くと仮定します。これは、1つではなく2つのクライアント/サーバーコマンドのターンアラウンドです。

(また、最初のコードはテーブルの各行をロックすることから始まります-これはテーブル全体をバッファキャッシュにプルします-それについて考えても、これが実際にパフォーマンスに影響を与えるとは思えませんが、あなたはそれについて言及しませんでした)

また、単純なテーブルの場合、ctidによる更新(これはどのようにwhere current of...機能すると思いますか)と主キーによる更新の間に大きな違いはないと思います-pkeyの更新は追加のインデックスルックアップですが、インデックスが巨大なそれはそれほど劣化ではありません。

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

于 2011-01-23T21:33:28.933 に答える