假设我有一个用标准 B-Tree 索引调用Projects
的列调用的表。Budget
该表有 50,000 个项目,其中只有 1% 的预算超过一百万。如果我运行 SQL 查询:
SELECT * From Projects WHERE Budget > 1000000;
规划器将使用索引范围扫描Budget
从堆表中获取行。但是,如果我使用查询:
SELECT * From Projects WHERE Budget > 50;
规划器很可能会对表进行顺序扫描,因为它知道这个查询最终会返回大部分或所有行,并且没有理由将索引的所有页面加载到内存中。
现在,假设我运行查询:
SELECT * From Projects WHERE Budget > :budget;
:budget
传递到我的数据库的绑定参数在哪里。根据我的阅读,上面的查询将被缓存,并且无法推断出任何有关基数的数据。事实上,大多数数据库只是假设分布均匀,缓存的查询计划将反映这一点。这让我感到惊讶,因为通常当您阅读绑定参数的好处时,它的主题是防止 SQL 注入攻击。
显然,如果生成的查询计划相同,这可以提高性能,因为不必编译新计划,但如果 的值变化很大,也会损害性能。:budget
我的问题:为什么在生成和缓存查询计划之前没有解析绑定参数?现代数据库不应该努力为查询生成最佳计划,这应该意味着查看每个参数的值并获得准确的索引统计信息吗?
注意:这个问题可能不适用于 mySql,因为 mySql 不缓存 SQL 计划。但是,我对为什么 Postgres、Oracle 和 MS SQL 会出现这种情况很感兴趣。