2 回答

TA贡献1794条经验 获得超8个赞
这些差异可能很微妙,有时很重要,有时实际上根本不存在。
一般来说,准备好的语句 1. 与服务器一起准备(SQL 解析,生成执行计划等),2. 使用附加参数执行,然后 3. 关闭。它可以让你重用相同的 SQL,每次传入不同的参数,它可以帮助防止 SQL 注入,可以提供一些性能增强(驱动程序/协议特定,YMMV)并防止重复步骤,如执行计划生成和 SQL 解析上面的准备步骤。
对于编写源代码的人来说,准备好的语句可能比连接字符串并将它们发送到数据库服务器更方便。
该DB.Query()
方法将 SQL 作为字符串,以及零个或多个参数(如Exec()
, 或QueryRow()
)。没有附加参数的 SQL 字符串将准确查询您编写的内容。但是,如果提供了一个带有占位符和附加参数的 SQL 字符串,则会在后台为您完成准备好的语句。
该DB.Prepare()
方法显式执行一个准备好的语句,然后您将参数传递给该语句,如:stmt.Exec(...args)
.
就两者之间的差异以及为什么要使用其中之一而言,有几件事值得考虑。
您可以DB.Query()
不带参数使用。这可能非常有效,因为它可以绕过准备好的语句必须经过的准备 --> 执行 --> 关闭序列。
您还可以在查询字符串中将其与其他参数和占位符一起使用,它会在我上面提到的封面下执行准备好的语句。这里的潜在问题是,当您进行大量查询时,每个查询都会产生一个幕后准备好的语句。由于涉及额外的步骤,因此每次执行该查询时它都会重新准备、执行和关闭,因此效率可能相当低。
使用显式准备好的语句,您可以避免这种低效率,因为您尝试重用之前准备的 SQL,可能带有不同的参数。
但这并不总是如您所料...由于由 db/sql 管理的底层连接池,您的“数据库连接”是相当虚拟的。该DB.Prepare()
方法将针对特定连接准备语句,然后在执行时尝试取回相同的连接,但如果该连接不可用,它将简单地抓取一个可用的连接并重新准备并针对该连接执行。如果您一遍又一遍地使用相同的准备好的语句,那么您可能会在不知不觉中一遍又一遍地准备它。当您处理繁忙的交通时,这显然主要是暴露出来的。
所以很明显,你在什么情况下使用取决于你的具体用例,但我希望上面的细节足以帮助你澄清,你可以在每种情况下做出最好的决定。
更新
鉴于 OP 中的更新,当查询只需要执行一次时基本上没有区别,因为带有参数的查询是在幕后作为准备好的语句完成的。
使用直接方法,例如DB.Query()
及其类似物,而不是显式使用准备好的语句,因为它会导致源代码更简单。
由于在这种情况下,出于安全原因使用准备好的语句,因此可能值得努力通过其他方式处理安全问题并改用明文查询,因为它会提高性能。但是,除非有足够的流量(或预计流量在未来会大幅增长)以减轻服务器上的负载,否则任何收益都可能无关紧要。再次归结为现实世界的用例。
对于任何对准备好的语句和直接明文查询之间的差异的一些指标感兴趣的人,这里有一篇很好的文章(它也很好地解释了上述大部分内容)。

TA贡献1871条经验 获得超13个赞
这在一定程度上取决于您使用的驱动程序,以及您的数据库软件是否支持未准备的查询。
Prepare 连接到数据库并创建一个准备好的语句,绑定到该数据库连接。执行时,它会检查该连接是否仍然可用,如果不可用,则创建一个新连接,重新准备函数,然后运行它。
编辑:注意,如果您一次只有一个例程连接到数据库,并且您使用不同的参数一遍又一遍地运行相同的查询,那么 Prepare 可以更快,因为它将查询存储在数据库端。但是,其他例程的连接劫持否定了这一点,如果您只使用一次查询,则完全不会从 Prepare 中获得任何好处。
查询根据驱动程序执行两件事之一。如果Conn
驱动返回的类型Open()
也有Query()
方法,因此支持直接查询,则sql.Query()
直接调用该方法,并返回其结果。如果Conn
没有方法,则准备一个语句,然后执行它。Query()
sql.Query()
例如,pq
PostgreSQL (github.com/lib/pq) 的驱动程序有一个Query()
方法。这个方法像sql
包一样准备和执行,但也有一个替代方法:如果查询没有参数,它使用simpleQuery
接口执行,包说明这个接口比准备和执行周期快得多。
- 2 回答
- 0 关注
- 429 浏览
添加回答
举报