вопрос о переменных привязки postgresql

Я смотрел на вопрос и решил попробовать использовать переменные связывания. Я использую

sql = 'insert into abc2 (interfield,textfield) values (%s,%s)'
a = time.time()
for i in range(10000):
    #just a wrapper around cursor.execute
    db.executeUpdateCommand(sql,(i,'test'))

db.commit()

и

sql = 'insert into abc2 (intfield,textfield) values (%(x)s,%(y)s)'
for i in range(10000):
    db.executeUpdateCommand(sql,{'x':i,'y':'test'})

db.commit()

глядя на время, необходимое для двух наборов, выше кажется, что нет большой разницы во времени. На самом деле, второй занимает больше времени. Может ли кто-нибудь исправить меня, если я где-то ошибся? с помощью psycopg2.

3 ответов


запросы эквивалентны в Postgresql.

Bind-это язык oracle. При использовании он сохранит план запроса, поэтому следующее выполнение будет немного быстрее. prepare делает то же самое в Postgres.

http://www.postgresql.org/docs/current/static/sql-prepare.html

psycopg2 поддерживает внутреннюю "привязку", а не prepare с cursor.executemany() и cursor.execute()

(но не называйте это привязкой к людям pg. Назовите это подготовкой, или они могут не знаю, что вы имеете в виду:)



ВАЖНОЕ ОБНОВЛЕНИЕ : Я видел источник всех библиотек python для подключения к PostgreSQL в портах FreeBSD и могу сказать, что только py-postgresql делает реальные подготовленные заявления! Но это только Python 3+.

также py-pg_queue-забавный lib, реализующий официальный протокол DB (python 2.4+)


вы пропустили ответ на этот вопрос о подготовленные операторы, чтобы использовать как можно больше. "Привязанные переменные" лучше форма этого, давайте посмотрим:

sql_q = 'insert into abc (intfield, textfield) values (?, ?)'  # common form 
sql_b = 'insert into abc2 (intfield, textfield) values (:x , :y)' # should have driver and db support

таким образом, ваш тест должен быть следующим:

sql = 'insert into abc2 (intfield, textfield) values (:x , :y)'
for i in range (10000):
    cur.execute(sql, x=i, y='test')

или такой:

def _data(n):
    for i in range (n):
         yield (i, 'test')
sql = 'insert into abc2 (intfield, textfield) values (? , ?)'    
cur.executemany(sql, _data(10000))

и так далее.

обновление: Я только что нашел интерес reciple как прозрачно заменить SQL-запросы подготовленными и с использованием %(name) s


насколько я знаю, psycopg2 никогда не поддерживал привязку параметров на стороне сервера ("переменные привязки" на языке Oracle). Текущие версии PostgreSQL поддерживают его на уровне протокола, используя подготовленные операторы, но только несколько библиотек соединителей используют его. The Postgres wiki заметки здесь. Вот некоторые разъемы, которые вы можете попробовать: (я не использовал их себя.)

пока вы используете вызовы DB-API, вам, вероятно, следует рассмотреть курсор.executemany () вместо многократного вызова курсора.выполнять.)(

кроме того, привязка параметров к их запросу на сервере (вместо соединителя) не всегда будет быстрее в PostgreSQL. Примечание этот FAQ запись.