【发布时间】:2011-07-18 06:00:39
【问题描述】:
情况
我的查询执行计划在 Oracle 11.2.0.2.0 中针对大量数据进行中型查询时遇到了一些问题。为了加快速度,我引入了一个范围过滤器,大致如下:
PROCEDURE DO_STUFF(
org_from VARCHAR2 := NULL,
org_to VARCHAR2 := NULL)
-- [...]
JOIN organisations org
ON (cust.org_id = org.id
AND ((org_from IS NULL) OR (org_from <= org.no))
AND ((org_to IS NULL) OR (org_to >= org.no)))
-- [...]
如您所见,我想使用可选的组织编号范围来限制organisations 的JOIN。客户端代码可以调用DO_STUFF,有(应该很快)或没有(非常慢)限制。
麻烦
问题是,PL/SQL 会为上述org_from 和org_to 参数创建绑定变量,这是我在大多数情况下所期望的:
-- [...]
JOIN organisations org
ON (cust.org_id = org.id
AND ((:B1 IS NULL) OR (:B1 <= org.no))
AND ((:B2 IS NULL) OR (:B2 >= org.no)))
-- [...]
解决方法
仅在这种情况下,当我只内联值时,我测量查询执行计划要好得多,即当 Oracle 执行的查询实际上类似于
-- [...]
JOIN organisations org
ON (cust.org_id = org.id
AND ((10 IS NULL) OR (10 <= org.no))
AND ((20 IS NULL) OR (20 >= org.no)))
-- [...]
“很多”是指快 5-10 倍。请注意,查询很少执行,即每月一次。所以我不需要缓存执行计划。
我的问题
如何在 PL/SQL 中内联值?我知道EXECUTE IMMEDIATE,但我更愿意让PL/SQL 编译我的查询,而不是进行字符串连接。
我只是测量了巧合发生的事情还是我可以假设内联变量确实更好(在这种情况下)?我问的原因是因为我认为绑定变量会迫使 Oracle 设计一个通用执行计划,而内联值将允许分析非常具体的列和索引统计信息。所以我可以想象这不仅仅是巧合。
我错过了什么吗?除了变量内联(注意我也尝试了很多提示,但我不是该领域的专家),也许还有一种完全其他的方法可以实现查询执行计划的改进?
【问题讨论】:
-
我很确定这是一个巧合。所有查询都是“编译”的,我完全确定我遵循您所询问的“内联变量”。绑定变量是 Oracle 告诉“获取共享池中的值”的方式。
-
@Sathya,我会更新我的问题。 “内联”是指“内联”,即变量不再是变量,而是 SQL 语句的常量
-
您是否真的获得了与绑定变量和硬编码值一致的不同查询计划?或者您的性能差异可能是由于“慢”查询将一堆数据读取到缓存(数据库、操作系统或 SAN)中,以便“快速”查询从更快的读取中受益?什么版本的甲骨文?假设
ORGANIZATIONS中的NO列是唯一键是否安全?NO列的统计信息准确吗? -
@Justin 是的,计划是一致的。我测量了 1、2、1、2、1、2 等。我还检查了各种绑定值。使用绑定变量,我得到一些全表扫描,而使用硬编码值,计划看起来好多了。版本是 11.2.0.2.0。
NO独一无二,统计准确。 -
@Justin,以防万一,问题不在
organisations表内。那个只有大约 550 条记录。每个组织在涉及完整查询的各种其他表中都有 10 万多条记录
标签: oracle plsql sql-execution-plan bind-variables