Поддерживает ли Python подготовленные операторы MySQL?

Ранее я работал над проектом PHP, где подготовленные операторы ускоряли запросы SELECT на 20%.

Мне интересно, работает ли это на Python? Кажется, я не могу найти ничего, что конкретно говорит, что это делает или НЕ делает.


person rubayeet    schedule 22.12.2009    source источник
comment
См. stackoverflow.com/a/2425500/20774 для прямого ответа. TLDR «нет»   -  person James McMahon    schedule 20.06.2013
comment
Спасибо @JamesMcMahon. Не могли бы вы отправить свой комментарий в качестве ответа?   -  person rubayeet    schedule 21.06.2013
comment
Готово, см. stackoverflow.com/a/17237567/20774.   -  person James McMahon    schedule 24.06.2013
comment
Я проверил в питоне и? не работает (mysql.connector.errors.ProgrammingError: не все параметры использовались в операторе SQL), но% работает отлично.   -  person alireza    schedule 30.09.2013
comment
возможный дубликат Поддерживает ли модуль MySQLdb подготовленные операторы?   -  person acrosman    schedule 26.11.2014
comment
@acrosman Учитывая, что второй вопрос был на 3 месяца позже этого, я предлагаю вам отметить его здесь.   -  person rubayeet    schedule 27.11.2014


Ответы (7)


Прямой ответ: нет.

ответ Джошперри является хорошим объяснением того, что он делает вместо этого.

Из eugene y ответ на аналогичный вопрос,

Проверьте Комментарии к пакету MySQLdb:

«Параметризация» выполняется в MySQLdb путем экранирования строк, а затем слепой интерполяции их в запрос вместо использования API MYSQL_STMT. В результате строки Unicode должны пройти через два промежуточных представления (закодированная строка, экранированная закодированная строка), прежде чем они будут получены базой данных.

Так что ответ таков: нет, это не так.

person James McMahon    schedule 21.06.2013
comment
Когда вы говорите, что python этого не делает, это не совсем правильно. Модуль MySQLdb не поддерживает подготовленные операторы, но наш SQL поддерживает. launchpad.net/oursql - person underrun; 19.06.2014
comment
Я не уверен, должен ли я чувствовать себя неприглядно по этому поводу или нет. С одной стороны, я чувствую, что мне немного промыли мозги из-за использования подготовленных операторов (исходя из php/pdo). С другой стороны, ввод экранируется, что, очевидно, важно, и mysqldb, похоже, превосходит большинство тестов, которые я гуглил... Думаю, мне интересно, почему это не так; Я полагаю, есть веская причина? - person Darragh Enright; 28.06.2015

Большинство языков предоставляют способ делать общие параметризованные операторы, Python ничем не отличается. Когда используется параметризованный запрос, базы данных, поддерживающие подготовку операторов, делают это автоматически.

В python параметризованный запрос выглядит так:

cursor.execute("SELECT FROM tablename WHERE fieldname = %s", [value])

Конкретный стиль параметризации может отличаться в зависимости от вашего драйвера, вы можете импортировать свой модуль db, а затем выполнить print yourmodule.paramstyle.

Из PEP-249:

парамстиль

       String constant stating the type of parameter marker
       formatting expected by the interface. Possible values are
       [2]:

           'qmark'         Question mark style, 
                           e.g. '...WHERE name=?'
           'numeric'       Numeric, positional style, 
                           e.g. '...WHERE name=:1'
           'named'         Named style, 
                           e.g. '...WHERE name=:name'
           'format'        ANSI C printf format codes, 
                           e.g. '...WHERE name=%s'
           'pyformat'      Python extended format codes, 
                           e.g. '...WHERE name=%(name)s'
person joshperry    schedule 22.12.2009
comment
Строки автоматически экранируются (делаются безопасными запросы)? - person scippie; 07.10.2011
comment
Я думаю, вы имеете в виду автоматическое цитирование SQL, а не фактические параметризованные запросы. - person Jeremy Stein; 09.11.2012
comment
@scippie Да и нет. Хотя технически вам не нужно беспокоиться об экранировании, а запрос по своей сути безопасен, это не потому, что параметры экранируются. Причина в том, что параметры отправляются на сервер как метаданные запроса, а не в соответствии с оператором запроса, как если бы вы выполняли наивную конкатенацию строк. (Это верно, если ваша база данных поддерживает параметризованные запросы; если нет, модуль базы данных python использует надежную конкатенацию строк для их эмуляции) - person joshperry; 13.11.2012
comment
кажется, что MySQLdb отправляет каждый запрос без подготовки (также отправляет несколько простых execute внутри executemany), тогда как oursql отправляет prepare, за которым следует execute (или executemany, который только отправляет параметры/значения). launchpad.net/oursql - person type; 26.03.2013
comment
Хороший звонок @type. В этой теме рекомендуется использовать наш SQL, а не MySQLdb. MySQLdb может обрабатывать параметризованные запросы посредством интерполяции, но не поддерживает подготовленные заявления. - person driftcatcher; 13.12.2013
comment
mysql.connector.paramstyle == 'pyformat' но Подготовленные операторы.. .. может использовать стиль форматирования (%s) или qmark (?). Это отличается от неподготовленных операторов... которые могут использовать стиль параметризации формата или pyformat. Таким образом, очевидно, что неподготовленные операторы более надежны, поскольку они допускают замены %(named)s. - person Bob Stein; 20.09.2015

После беглого просмотра метода execute() объекта Cursor пакета MySQLdb (полагаю, что-то вроде пакета де-факто для интеграции с mysql) кажется, что (по крайней мере, по умолчанию) он выполняет только интерполяцию строк. и цитирование, а не фактический параметризованный запрос:

if args is not None:
    query = query % db.literal(args)

Если это не интерполяция строк, то что?

В случае executemany он фактически пытается выполнить вставку/замену как один оператор, а не выполнять его в цикле. Вот и все, никакой магии там, кажется. По крайней мере, не в его поведении по умолчанию.

РЕДАКТИРОВАТЬ: О, я только что понял, что оператор по модулю может быть переопределен, но мне захотелось обмануть и найти источник. Однако нигде не нашел переопределенного mod.

person shylent    schedule 22.12.2009

Для тех, кто просто пытается понять это, ДА вы можете использовать подготовленные операторы с Python и MySQL. Просто используйте MySQL Connector/Python из самой MySQL и создайте правильный курсор:

https://dev.mysql.com/doc/connector-python/en/index.html

https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursorprepared.html

person fromvega    schedule 13.08.2015
comment
Правильно ли я понимаю, что синтаксис более надежен (с именованными заменами), когда вы выполняете НЕ использовать так называемые подготовленные операторы? cursor = connection.cursor(); cursor.execute("SELECT * FROM t WHERE name = %(name)s", dict(name='Monty')) - person Bob Stein; 20.09.2015

Использование интерфейса SQL, предложенное Амитом, может работать, если вас интересует только производительность. Однако при этом вы теряете защиту от SQL-инъекций, которую могла бы обеспечить встроенная поддержка Python для подготовленных операторов. В Python 3 есть модули, обеспечивающие поддержку подготовленных операторов для PostgreSQL. Для MySQL «oursql», по-видимому, обеспечивает настоящую поддержку подготовленных операторов (а не подделку, как в других модулях).

person user304386    schedule 29.03.2010

Не имеет прямого отношения, но этот ответ на другой вопрос at SO включает сведения о синтаксисе "шаблонных" запросов. Я бы сказал, что автоматическое экранирование будет их самой важной особенностью...

Что касается производительности, обратите внимание на метод executemany для объектов курсора. Он объединяет несколько запросов и выполняет их все за один раз, что действительно приводит к повышению производительности.

person Michał Marczyk    schedule 22.12.2009
comment
ну, он просто запускает insert into foo (f1,f2,f3) values (f11,f12,f13),(f21,f22,f23),... и так далее (вместо того, чтобы вы выполняли эти вставки в цикле). Я не говорю, что это не увеличивает производительность. - person shylent; 22.12.2009
comment
глядя на исходный код MySQLdb, кажется, что .executemany() зацикливается только на .execute() - person type; 26.03.2013

Есть решение!

Вы можете использовать их, если поместите их в хранимую процедуру на сервере и вызовете их так из python...

cursor.callproc(Procedurename, args)

Вот хороший небольшой учебник по хранимым процедурам в mysql и python.

http://www.mysqltutorial.org/calling-mysql-stored-procedures-python/

person whoopididoo    schedule 19.02.2016