2

我有两个疑问:

with tmp as (
select asy.aim_student_id, ast.aim_test, asq.response
  from aim_student_test ast
  join aim_student_qst asq on (asq.aps_yr = ast.aps_yr and asq.aim_test = ast.aim_test and asq.aim_id = ast.aim_id)
  join aim_student_yr asy on (asy.aps_yr = ast.aps_yr and asy.aim_student_yr_id = ast.aim_student_yr_id)
    where asq.aps_yr = '2012'
    and asq.qst_num = 1)
select aim_student_id, aim_test, response  
  from tmp
  where response is null
  -- execution-time: 0.032 seconds


define this_year = extract(year from sysdate)
with tmp as (
select asy.aim_student_id, ast.aim_test, asq.response
  from aim_student_test ast
  join aim_student_qst asq on (asq.aps_yr = ast.aps_yr and asq.aim_test = ast.aim_test and asq.aim_id = ast.aim_id)
  join aim_student_yr asy on (asy.aps_yr = ast.aps_yr and asy.aim_student_yr_id = ast.aim_student_yr_id)
    where asq.aps_yr = &this_year
    and asq.qst_num = 1)
select aim_student_id, aim_test, response  
  from tmp
  where response is null
  -- execution-time: 82.202 seconds

唯一的区别是,在一个我使用“2012”,另一个我实现提取(从 sysdate 开始的年份)。

我只能想象 Oracle 正在计算它检查的每条记录的提取(从 sysdate 开始的年份),而我只是不知道如何让它计算一次并将其用作变量。搜索并没有返回我所寻求的答案......所以我来到了 SO.com 的魔术师。如何正确使用

extract(year from sysdate)

作为变量?

4

2 回答 2

3

在查询中使用&this_year会导致string extract(year from sysdate)的替换,因此第二个查询实际上具有:

where asq.aps_yr = extract(year from sysdate)

您可以从第二个解释计划中看到。这本身可能不是问题。可能会放慢速度的是,这样做会将计划从 anindex range scan更改为index skip scanagainst aim_student_qstp1。真正的区别在于,在快速版本中,您要与asq.aps_yr字符串'2012'(按您的预期使用。2012to_number(asq.aps_yr)

您可以通过以下方式在代码中解决此问题:

where asq.aps_yr = to_char(&this_year)

如果要在查询运行前计算一次,然后将其用作变量,至少有两种方法(在 SQL*Plus/SQL Developer 中)。坚持使用替换变量,您可以使用column命令而不是define

column tmp_this_year new_value this_year
set termout off
select extract(year from sysdate) as tmp_this_year from dual;
set termout on
set verify off

...这使得&this_year=2012termout更改只是使实际检索不可见,并且verify停止它告诉您何时使用替换;两者都这样您就不会在脚本中获得额外的输出),并将您的查询更改为:

where asq.aps_yr = '&this_year'

...因此该值被视为字符串,因此to_char()不必要。

或者您可以使用绑定变量:

var this_year varchar2(4);
set feedback off;
exec :this_year := extract(year from sysdate);

...然后您的查询有:

where asq.aps_yr = :this_year

请注意,在这种情况下,您不需要引号,因为绑定变量已经定义为字符串 -exec设置它的隐式转换。

于 2012-07-20T07:18:35.337 回答
2

我怀疑差异是由于从日期中提取年份。我很确定甲骨文只会提取一次年份,因为它在第二种情况下使用了一个变量。

不同之处在于查询使用的执行路径。您需要发布执行计划才能真正看到差异。使用显式常量可以为优化器提供更多信息以选择最佳查询计划。

例如,如果数据是按年份分区的,那么在固定年份的情况下,Oracle 可以确定哪个分区有数据。在第二种情况下,Oracle 可能无法将该值识别为常量,并且需要读取所有数据分区。这只是可能发生的情况的一个示例——我不确定 Oracle 在这种情况下会做什么。

于 2012-07-20T01:02:34.793 回答