首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >'extract(year from sysdate)‘的速度

'extract(year from sysdate)‘的速度
EN

Stack Overflow用户
提问于 2012-07-20 08:24:39
回答 2查看 2.1K关注 0票数 2

我有两个问题:

代码语言:javascript
复制
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‘,而在另一个代码中,我实现了extract(从sysdate开始的年份)。

我只能想象Oracle正在为它检查的每个记录计算提取(Year from sysdate),而我只是想不出如何让它计算一次并将其用作变量。搜索并没有给我我想要的答案。所以我来找SO.com的魔术师。如何正确使用

代码语言:javascript
复制
extract(year from sysdate)

作为一个变量?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-20 15:18:35

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

代码语言:javascript
复制
where asq.aps_yr = extract(year from sysdate)

你可以从第二个解释计划中看到。这本身可能不是问题所在;可能会让它慢下来的是,这样做是将计划从index range scan更改为针对aim_student_qstp1index skip scan。真正的不同之处在于,在快速版本中,您将asq.aps_yr与字符串('2012')进行比较,在第二个版本中,它是一个数字(2012),并且-正如在explain计划中所示-这会导致它执行to_number(asq.aps_yr)操作,从而停止使用您预期的索引。

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

代码语言:javascript
复制
where asq.aps_yr = to_char(&this_year)

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

代码语言:javascript
复制
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=2012 ( termout更改只是使实际的检索不可见,并且verify在使用替换时停止通知您;两者都是如此,这样您就不会在脚本中获得额外的输出),并将您的查询更改为:

代码语言:javascript
复制
where asq.aps_yr = '&this_year'

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

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

代码语言:javascript
复制
var this_year varchar2(4);
set feedback off;
exec :this_year := extract(year from sysdate);

..。然后你的查询就是:

代码语言:javascript
复制
where asq.aps_yr = :this_year

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

票数 3
EN

Stack Overflow用户

发布于 2012-07-20 09:02:35

我怀疑差异是由于从日期中提取年份造成的。我非常确定Oracle只提取一次年份,因为它在第二种情况下使用了一个变量。

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

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11571225

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档