Oracle group需要花费大量时间

时间:2015-10-14 16:53:36

标签: sql oracle

我有一个需要花费大量时间的选择查询:

select  user_id, variable, round(AVG(v_Score),1) v_score 
     from TEST_1M_SCORE_V1 where clock between 1 and 12 group by user_id, variable

此表格 - TEST_1M_SCORE_V1有260,000,000行。

是否还有其他编写group by子句的方法,以便更快地运行?

表格定义:

Name          Null Type          
------------- ---- ------------- 
USER_ID             NUMBER        
CLOCK               NUMBER        
VARIABLE           VARCHAR2(255) 
V_SCORE            NUMBER    

1 个答案:

答案 0 :(得分:2)

根据数据,这是两个答案,而不是一个答案。这是您的查询:

select user_id, variable, round(AVG(v_Score), 1) as v_score 
from TEST_1M_SCORE_V1
where clock between 1 and 12
group by user_id, variable;

选项1是相对较少的行满足where条件 - 其中“相对较少”绝对不超过少数百分比。在这种情况下,TEST_1M_SCORE_V1(clock)上的索引会很有用。对于覆盖索引,您可以将其扩展到TEST_1M_SCORE_V1(clock, user_id, variable, score)。 Oracle需要为group by完成所有工作,但只需要处理较少的数据。

选项2是当更多行满足where条件时。在这种情况下,您希望Oracle对group by执行完整索引扫描。问题是where条款。一种方法是使用基于函数的索引将其合并到索引中。但是,这是非常具体的(它适用于1和12但不适用于1和11)。

相反,请将查询写为:

select user_id, variable,
       round(AVG(case when clock between 1 and 12 then v_Score end), 1) as v_score 
from TEST_1M_SCORE_V1
group by user_id, variable
having sum(case when clock between 1 and 12 then 1 else 0 end) > 0;

having子句可能没有必要,具体取决于您对user_id / variable组合的关注程度avg() NULL TEST_1M_SCORE_V1(user_id, variable, clock, v_score)。 )

此查询等同于原始查询。它似乎做了更多的工作,但这项工作针对索引扫描进行了高度优化:group by。这个想法是Oracle可以按顺序读取索引,同时执行group by和计算。它永远不需要在原始数据集中查找数据,也不需要使用基于散列或排序的算法处理set deadlock_priority high; -- could also try "10" instead of "high" (5) alter database dbname set multi_user; -- can also add "with rollback immediate"