据我所知,prepared语句(主要)是一种数据库功能,允许您将参数与使用此类参数的代码分离.例子:

PREPARE fooplan (int, text, bool, numeric) AS
    INSERT INTO foo VALUES($1, $2, $3, $4);
EXECUTE fooplan(1, 'Hunter Valley', 't', 200.00);

参数化查询替代了手动字符串插值,因此

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

我们可以做到

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

现在,似乎大部分预准备语句都用在数据库语言中,参数化查询主要用在连接到数据库的编程语言中,尽管我看到了这条规则的例外情况.

问题是,询问预准备语句和参数化查询之间的区别会带来很多念力.诚然,他们的目的是相同的,但他们的方法似乎截然不同.然而,有sources个表明两者是相同的.MySQLdb和Mental copg2似乎支持参数化查询,但不支持预准备语句(例如,MySQLdb为here,sqlalChemy组中为TODO list for postgres driversthis answer).实际上,有一个gist实现了一个支持预准备语句的mental copg2游标,最小explanation个实现了这个游标.还有一种方法是在mental copg2中对游标对象进行子类化,以手动提供准备好的语句.

我想得到以下问题的权威答案:

  • 预准备语句和参数化查询之间有意义的区别吗?这在实践中重要吗?如果使用参数化查询,是否需要担心预准备语句?

  • 如果存在差异,那么Python生态系统中预准备语句的当前状态如何?哪些数据库适配器支持预准备语句?

推荐答案

  • 准备好的语句:对数据库上预先解释的查询 routine 的引用,准备接受参数

  • 参数化查询:由代码进行的查询,通过这种方式,您可以在某些SQL中传递具有占位符值的值,通常是?%s或类似的值.

这里的困惑似乎源于(显然)在直接获取准备好的语句对象的能力和将值传递给"参数化查询"方法的能力之间缺乏区别,后者的行为非常类似于...因为它是一个,或者至少为你制造了一个.

例如:SQLite3库的C接口有很多处理prepared statement objects的工具,但是Python api几乎没有提到它们.您不能随时准备一条语句并多次使用它.相反,您可以使用sqlite3.executemany(sql, params),它获取SQL代码,创建一条准备好的语句internally,然后在循环中使用该语句来处理您给出的迭代表中的每个参数元组.

Python中的许多其他SQL库的行为都是相同的.使用预准备语句对象可能非常痛苦,并且可能导致模棱两可,而且在像Python这样的语言中,相对于原始执行速度而言,它们非常倾向于清晰和轻松,它们实际上不是最好的 Select .从本质上讲,如果您发现自己必须对一个复杂的SQL查询进行数十万或数百万次调用,而该查询每次都会被重新解释,那么您可能应该采取不同的做法.无论如何,有时人们希望能够直接访问这些对象,因为如果您在数据库服务器中保留相同的预准备语句,则不必反复解释相同的SQL代码;大多数情况下,这将从错误的方向解决问题,并且您将在其他地方或通过重构代码获得更大的节省.*

一般来说,也许更重要的是准备好的语句和参数化查询保持数据清洁并与SQL代码分离的方式.This is vastly preferable to string formatting!您应该将这样或那样的参数化查询和预准备语句视为the only way to pass variable data from your application into the database.如果您try 以其他方式构建SQL语句,它不仅运行速度明显变慢,而且您将容易受到other problems的攻击.

*e.g., by producing the data that is to be fed into the DB in a generator function then using 100 to insert it all at once from the generator, rather than calling 101 each time you loop.

TL;DR

A parametrized query is a single operation which generates a prepared statement internally, then passes in your parameters and executes.

很多人都看到了这个答案!我还想澄清的是,许多数据库引擎也有预准备语句的概念,可以使用明文查询语法显式构造该语句,然后在客户端会话的整个生命周期内重用该语句(例如,在postgres中).有时,您可以控制是否缓存查询计划,以节省更多时间.一些框架自动使用这些(我见过Rails的ORM积极地这样做),当准备的查询有形式的排列时,有时有用,有时有害.

另外,如果您想 Select ,参数化查询不会always在幕后使用预准备语句;如果可能,它们应该这样做,但有时只是格式化参数值.这里的"预准备语句"和"参数化查询"之间的真正区别在于您使用的API的形状.

Database相关问答推荐

删除Postgres中的JSONB列并在不停机的情况下回收空间

Postgres pg_dump 每次都以不同的顺序转储数据库

TSQL - 表值函数中的 If..Else 语句 - 无法通过

某些网站不允许在密码中使用句点是否有原因?

在 SQL Server 中存储属性的最佳模式是什么?

将实体框架中的字符串列映射到枚举

是否可以在ORDER BY子句之后放置任何可能造成安全风险的内容?

设置默认数据库连接 Rails

PHP + SQL Server - 如何设置连接字符集?

Windows 环境下无法识别 postgres 'psql' 命令

为什么有人需要内存数据库?

在默认路径下使用脚本创建数据库?

Mysql用户创建脚本

在数据库中使用数组是不好的设计吗?

使用多个数据库模式的 JPA

如何将 Android 手机上的 SQLite 数据库与服务器上的 MySQL 数据库同步?

可以将 SQLAlchemy 配置为非阻塞吗?

Google 的 Bigtable 与关系数据库

有哪些不同类型的索引,每种索引的好处是什么?

遍历数据库中的每条记录 - Ruby on Rails / ActiveRecord