Postgres: удивительная производительность в обновлениях с помощью курсора

StackOverflow https://stackoverflow.com/questions/4776127

Вопрос

Рассмотрим два следующих примера кода 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()

Оператор CREAT для табличного теста:

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

И эта таблица содержит 100000 строк и вакуумный анализ; был запущен.

Я получил следующие результаты последовательно по нескольким попыткам.

Пример первого кода:

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

Второй пример кода:

Finished: update starting commit: 24.574401185
Finished committing: 24.7331461431

Это очень удивительно для меня, как я думаю, должно быть точно противоположным, что означает, что обновление, использующее курсор, должно быть значительно быстрее в соответствии с это отвечать.

Это было полезно?

Решение

Я не думаю, что тест сбалансирован- ваш первый код извлекает данные из курсора, а затем обновляется, тогда как второй слепо обновляет идентификатор без получения данных. Я предполагаю, что первая последовательность кода переводится в команду Fetch, за которой следует обновление, так что это два поворота команды клиента/сервера, в отличие от одного.

(Также первый код начинается с блокировки каждой строки в таблице- это вытягивает всю таблицу в буферный кэш,- хотя я думаю об этом, я сомневаюсь, что это фактически влияет на производительность, но вы не упомянули об этом)

Кроме того where current of... Работает) и обновление через основной ключ- обновление Pkey- это дополнительный поиск индекса, но если индекс огромный Это не большая деградация.

Для обновления 100 000 таких строк, я подозреваю, что большую часть времени принимается, создавая дополнительные кортежи и вставляя их или добавляя их к столу, а не определяют предыдущую кортеж, чтобы пометить его как удаленные.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top