Mik*_*sen 5 sql sql-server oracle postgresql
假设我有一个名为Projects带有Budget标准B-Tree索引的列的表.该表有50,000个项目,其中只有1%的预算超过一百万.如果我运行SQL查询:
SELECT * From Projects WHERE Budget > 1000000;
Run Code Online (Sandbox Code Playgroud)
规划器将使用索引范围扫描Budget来从堆表中获取行.但是,如果我使用查询:
SELECT * From Projects WHERE Budget > 50;
Run Code Online (Sandbox Code Playgroud)
规划人员很可能会对表执行顺序扫描,因为它会知道此查询最终会返回大多数或所有行,并且没有理由将索引的所有页面加载到内存中.
现在,假设我运行查询:
SELECT * From Projects WHERE Budget > :budget;
Run Code Online (Sandbox Code Playgroud)
哪个:budget绑定参数传递到我的数据库.根据我的阅读,上面的查询将被缓存,并且不能推断基数的数据.事实上,大多数数据库只是假设均匀分布,缓存的查询计划将反映出这一点.这让我感到惊讶,因为通常当你读到绑定参数的好处时,它就是防止SQL注入攻击的主题.
显然,如果生成的查询计划相同,这可以提高性能,因为不需要编译新计划,但如果值变化很大,也可能会损害性能:budget.
我的问题:为什么在生成和缓存查询计划之前未解析绑定参数?现代数据库是否应该努力为查询生成最佳计划,这应该意味着查看每个参数的值并获得准确的索引统计信息?
注意:此问题可能不适用于mySql,因为mySql不缓存SQL计划.但是,我对Postgres,Oracle和MS SQL的情况感兴趣.
对于Oracle,具体取决于它.
在相当长的时间内(至少9i),Oracle支持绑定变量查看.这意味着第一次执行查询时,优化器会查看绑定变量的值,并将其基数估计值基于第一个绑定变量的值.在大多数查询执行将具有返回类似大小结果的绑定变量值的情况下,这是有意义的.如果99%的查询使用的是较小的预算值,则第一次执行很可能会使用较小的值,因此缓存的查询计划将适用于小的绑定变量值.当然,这意味着当你指定一个大的绑定变量值时(或者更糟糕的是,如果你运气好并且第一次执行的值很大),你将获得不太理想的查询计划.
如果您使用11g,Oracle可以使用自适应游标共享.这允许优化器为单个查询维护多个查询计划,并根据绑定变量值选择适当的计划.但是,随着时间的推移,这会变得相当复杂.如果您有一个带有N绑定变量的查询,优化器必须弄清楚如何将该N维空间划分为不同的绑定变量值的不同查询计划,以便确定何时以及是否为新的查询重新优化查询绑定变量值的集合以及何时简单地重用早期计划.许多工作最终在夜间维护窗口期间完成,以避免在生产日期间产生这些费用.但是,这也带来了DBA希望数据库随着时间的推移有多大的自由度以及DBA想要控制计划的程度,以便数据库不会突然开始选择导致某些主要系统的糟糕计划的问题.在随机的一天慢慢爬行.
这让我感到惊讶,因为通常当你读到绑定参数的好处时,它就是防止SQL注入攻击的主题.
不要将参数化查询与预准备语句混淆.两者都提供参数化,但是准备好的语句提供了查询计划的额外缓存.
为什么在生成和缓存查询计划之前未解析绑定参数?
因为有时候生成查询计划是一个昂贵的步骤.准备好的语句允许您分摊查询计划的成本.
但是,如果您要查找的只是SQL注入保护,请不要使用预准备语句.使用参数化查询.
例如,在PHP中,您可以使用http://php.net/pg_query_params执行参数化查询而不缓存查询计划; 同时http://php.net/pg_prepare和http://php.net/pg_execute用于缓存预准备语句的计划,然后执行它.
| 归档时间: |
|
| 查看次数: |
4380 次 |
| 最近记录: |