Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL绑定参数会影响性能吗?_Sql_Sql Server_Oracle_Postgresql - Fatal编程技术网

SQL绑定参数会影响性能吗?

SQL绑定参数会影响性能吗?,sql,sql-server,oracle,postgresql,Sql,Sql Server,Oracle,Postgresql,假设我有一个名为Projects的表,其中有一个名为Budget的列,其中有一个标准的B树索引。该表有50000个项目,其中只有1%的项目预算超过一百万。如果我运行SQL查询: SELECT * From Projects WHERE Budget > 1000000; 计划者将使用预算上的索引范围扫描从堆表中获取行。但是,如果我使用查询: SELECT * From Projects WHERE Budget > 50; SELECT * From Projects WHERE

假设我有一个名为
Projects
的表,其中有一个名为
Budget
的列,其中有一个标准的B树索引。该表有50000个项目,其中只有1%的项目预算超过一百万。如果我运行SQL查询:

SELECT * From Projects WHERE Budget > 1000000;
计划者将使用
预算
上的索引范围扫描从堆表中获取行。但是,如果我使用查询:

SELECT * From Projects WHERE Budget > 50;
SELECT * From Projects WHERE Budget > :budget;
规划器很可能会对表进行顺序扫描,因为它知道该查询最终将返回大部分或所有行,并且没有理由将索引的所有页面加载到内存中

现在,假设我运行查询:

SELECT * From Projects WHERE Budget > 50;
SELECT * From Projects WHERE Budget > :budget;
其中
:budget
是传递到我的数据库中的绑定参数。从我读到的内容来看,上面的查询将被缓存,并且不能推断出基数数据。事实上,大多数数据库只会假定分布是均匀的,缓存的查询计划将反映这一点。这让我很惊讶,通常当你读到绑定参数的好处时,它是关于防止SQL注入攻击的

显然,如果生成的查询计划相同,这可能会提高性能,因为不必编译新计划,但如果
:budget
的值差异很大,这也可能会影响性能

我的问题:为什么在生成和缓存查询计划之前绑定参数没有被解析?现代数据库是否应该努力为查询生成最佳计划,这应该意味着查看每个参数的值并获得准确的索引统计数据

注意:这个问题可能不适用于mySql,因为mySql不缓存SQL计划。然而,我感兴趣的是为什么Postgres、Oracle和MS SQL上会出现这种情况

这让我很惊讶,通常当你读到绑定参数的好处时,它是关于防止SQL注入攻击的

不要将参数化查询准备好的语句混淆。两者都提供了参数化,但prepared语句提供了查询计划的额外缓存

为什么在生成和缓存查询计划之前不解析绑定参数

因为有时候生成查询计划是一个昂贵的步骤。准备好的报表允许您分摊查询计划的成本

但是,如果您只需要SQL注入保护,请不要使用准备好的语句。使用参数化查询

例如,在PHP中,您可以使用来执行参数化查询,而无需缓存查询计划;同时,和用于缓存已准备语句的计划,然后执行它


编辑:

对于Oracle,具体取决于

相当一段时间以来(至少9i),Oracle一直支持绑定变量窥视。这意味着在第一次执行查询时,优化器会查看绑定变量的值,并根据第一个绑定变量的值对其基数进行估计。在大多数查询的执行都将有绑定变量值返回相似大小的结果的情况下,这是有意义的。如果99%的查询使用较小的预算值,则第一次执行很可能使用较小的值,因此缓存的查询计划将适用于较小的绑定变量值。当然,这意味着当您指定一个大的绑定变量值时(或者,更糟糕的是,如果您运气好,第一次执行时使用的是一个大的值),您将得到比最佳查询计划更少的查询计划


如果您使用的是11g,Oracle可以使用。这允许优化器为单个查询维护多个查询计划,并根据绑定变量值选择适当的计划。不过,随着时间的推移,这可能会变得相当复杂。如果您有一个包含N个绑定变量的查询,那么优化器必须弄清楚如何将该N维空间划分为不同绑定变量值的不同查询计划,以便弄清楚何时以及是否为一组新的绑定变量值重新优化查询,以及何时只需重复使用以前的计划。为了避免在生产日产生这些成本,许多工作最终在夜间维护时段完成。但这也带来了一些问题,比如DBA希望给数据库多大的自由度来随时间发展计划,而DBA希望控制多大的计划,以便数据库不会突然开始选择一个糟糕的计划,导致一些主要系统在随机的一天慢下来爬行。

也许我没有抓住要点,但是,如果db必须知道绑定值才能决定优化/执行计划,那么这不是一个困难的解析吗?
规划者将[…]知道该查询最终将返回大部分或所有行
-这是真的吗?这些数据库是否维护某种索引值的柱状图,以便在考虑查找值的情况下做出决策?@AndreKR-正确。大多数现代数据库都会保留表基数的统计信息。是的,但在执行查询之前,您需要知道有多少行
Budget>1000000
将比
Budget>50
返回。@AndreKR-正确。通常,它存储统计信息,例如不同值的数量、最常见的值、数据的直方图和相关性(相对于表中的位置)。你应该检查一下-它详细地讨论了这类事情。啊,然后,如果参数值可能导致完全不同的执行计划(比如不使用索引扫描一百万行),那么似乎应该由开发人员使用参数化查询而不是准备好的语句了。。我相信这回答了我的问题!我说Postgres永远不会缓存执行计划,除非您特别使用
PREPARE
关键字,对吗?我相信您的客户端库中的某些方法会导致executi