2012-07-20 28 views
1

的速度,我有两个疑问:“提取物(从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 = '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) 

作为变量?

回答

2

使用查询&this_year导致extract(year from sysdate)的替代,所以第二个查询实际上有:

where asq.aps_yr = extract(year from sysdate) 

您可以从第二个解释计划看。这本身可能不是问题;可能放缓的是,这样做是将计划从index range scan更改为index skip scan而不是aim_student_qstp1。真正的区别是,在你比较asq.aps_yr为一个字符串('2012')快速版本,在第二个它是一个数字(2012),以及 - 在解释计划也表明 - 这是导致它做to_number(asq.aps_yr)这是停止正在使用的索引。如果您想查询运行前一次计算,然后把它作为一个变量,至少有两种方式(在SQL

where asq.aps_yr = to_char(&this_year) 

你可以在你的代码通过使得解决这个问题* 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=2012(在termout改变只是使实际的检索无形的,以及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中有一个隐式转换来设置它。

+0

嘿伙伴 - 对不起,我没有更早发布 - 我兼职工作。今天是我本周回来的第一天,这是我第一次尝试。它的工作方式非常魅力,完全符合我的要求 - 因此我将其标记为我接受的答案,因为另一个很有帮助,但并未完全涵盖我所寻找的内容。 – nebffa 2012-07-23 23:17:49

+0

@AlexPoole。 。 。非常好的解释! – 2012-07-24 14:50:56

2

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

的差异是由于通过查询所使用的执行路径。您需要发布执行计划才能真正发现差异。使用显式常量可为优化程序提供有关选择最佳查询计划的更多信息。

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

+0

哇,检查计划是有趣的,虽然它还没有解决我的问题,但它正是我试图学习的东西(长期有用的工具)的类型。谢谢。 [快速计划](http://img833.imageshack.us/img833/4052/fastplan.png)和[慢速计划](http://img687.imageshack.us/img687/3623/slowplan.png) 您是对的,显然两者之间存在巨大差异。现在我的问题是......我如何从这里解决问题? – nebffa 2012-07-20 02:10:19

+0

我想我正在寻找的是如何将提取(从sysdate中提取)作为CONSTANT提供给Oracle。在开始优化其查询之前。 我们可以使用'2012',但是这个查询和我正在创建的许多其他数据将在这里使用数年。我在今年年底完成了这项工作,如果我可以创建这些查询以便始终工作而无需创建额外的工作 - 那将非常棒。另外,学习非常有趣 – nebffa 2012-07-20 02:16:02

+0

请问另一个问题,包括查询计划,表结构和大小。你有一个关于性能的非常具体的问题,但是你问了一个非常普遍的问题。 – 2012-07-20 02:22:41