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

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

SELECT * From Projects WHERE Budget > 1000000;

规划器将使用Budget上的索引范围扫描来从堆表中获取行.但是,如果我使用查询:

SELECT * From Projects WHERE Budget > 50;

规划人员很可能会对表执行顺序扫描,因为它会知道此查询最终会返回大多数或所有行,并且没有理由将索引的所有页面加载到内存中.

现在,假设我运行查询:

SELECT * From Projects WHERE Budget > :budget;

其中:预算是传递到我的数据库的绑定参数.根据我的阅读,上面的查询将被缓存,并且不能推断基数的数据.事实上,大多数数据库只是假设均匀分布,缓存的查询计划将反映出这一点.这让我感到惊讶,因为通常当你读到绑定参数的好处时,它就是防止SQL注入攻击的主题.

显然,如果生成的查询计划相同,这可以提高性能,因为新计划不必编译,但如果预算值大大变化,也可能损害性能.

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

注意:此问题可能不适用于mySql,因为mySql不缓存SQL计划.但是,我对Postgres,Oracle和MS SQL的情况感兴趣.

最佳答案

This surprised me, as usually when you read about the benefits of bind parameters it’s on the subject of preventing SQL injection attacks.

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

Why are bind parameters not resolved before the query plan is generated and cached?

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

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

例如,在PHP中,您可以使用http://php.net/pg_query_params执行参数化查询而不缓存查询计划;同时,http://php.net/pg_preparehttp://php.net/pg_execute用于缓存预准备语句的计划,然后执行它.

编辑:9.2 apparently changes the way prepared statements are planned

转载注明原文:SQL绑定参数会影响性能吗? - 代码日志