Sql 聚合视图中的Oracle索引使用情况
背景如下: 版本: Oracle 8i(不要因为我过时而恨我。我们正在升级!) 下面是一个立即返回的查询:Sql 聚合视图中的Oracle索引使用情况,sql,oracle,optimization,plsql,indexing,Sql,Oracle,Optimization,Plsql,Indexing,背景如下: 版本: Oracle 8i(不要因为我过时而恨我。我们正在升级!) 下面是一个立即返回的查询: SQL> select to_char(trunc(day,'HH'),'DD-MON-YYYY HH24') day, 2 avg(decode(stone,-9999,null,stone)) stone, 3 avg(decode(simpson,-9999,null,simpson)) simpson, 4 avg(decode(oxychem,-9999,null,o
SQL> select to_char(trunc(day,'HH'),'DD-MON-YYYY HH24') day,
2 avg(decode(stone,-9999,null,stone)) stone,
3 avg(decode(simpson,-9999,null,simpson)) simpson,
4 avg(decode(oxychem,-9999,null,oxychem)) oxychem,
5 avg(decode(praxair,-9999,null,praxair)) praxair
6 from IDcpdata
7 where day between
8 to_date('14-jun-2009 0','dd-mon-yyyy hh24') and
9 to_date('14-jun-2009 13','dd-mon-yyyy hh24')
10 group by trunc(day,'HH');
当我基于该查询创建一个视图时,如果没有where子句,则针对该视图的带有where子句的查询将无法使用该视图。直接SQL查询版本中使用了高选择性索引。全表扫描需要20分钟
create or replace view theview as
select TRUNC(day,'HH') day,
avg(decode(stone,-9999,null,stone)) stone,
avg(decode(simpson,-9999,null,simpson)) simpson,
avg(decode(oxychem,-9999,null,oxychem)) oxychem,
avg(decode(praxair,-9999,null,praxair)) praxair
from IDcpdata group by TRUNC(day,'HH');
SQL> select * from theview
2 where day between
3 to_date('14-jun-2009 0','dd-mon-yyyy hh24') and
4 to_date('14-jun-2009 13','dd-mon-yyyy hh24');
我在视图、查询和两者中尝试了INDEX()提示。我尝试了全局索引提示,指定了基础表的完全限定名。我也试过合并
在我看来,Oracle应该能够使用索引,因为内联SQL可以。我就是不知道该怎么强迫它。我肯定是我,不是神谕,我只是没看见而已
提前感谢您的建议 您的视图查询在
TRUNC(day,'HH')
上过滤,而不是在day
上过滤
由于您将视图定义为将TRUNC(day,'HH')返回为day
,因此它是BETWEEN
子句应用到的截断的day值,不可搜索
在TRUNC(day,'HH')上创建索引:
更新:
这适用于我的Oracle 10g XE
:
CREATE TABLE t_group (id INT NOT NULL PRIMARY KEY, day DATE NOT NULL)
/
INSERT
INTO t_group
SELECT level, TRUNC(SYSDATE) - level
FROM dual
CONNECT BY
level <= 100
/
CREATE INDEX ix_group_truncday ON t_group (TRUNC(day, 'HH'))
/
CREATE VIEW v_group AS
SELECT TRUNC(day, 'HH') AS day
FROM t_group
GROUP BY
TRUNC(day, 'HH')
/
EXPLAIN PLAN FOR
SELECT *
FROM v_group
WHERE day BETWEEN TO_DATE('01.08.2009', 'dd.mm.yyyy') AND TO_DATE('02.08.2009', 'dd.mm.yyyy')
/
SELECT *
FROM TABLE(DBMS_XPLAN.display)
/
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1656741214
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 2
| 1 | HASH GROUP BY | | 1 | 9 | 2
| 2 | TABLE ACCESS BY INDEX ROWID| T_GROUP | 1 | 9 | 1
|* 3 | INDEX RANGE SCAN | IX_GROUP_TRUNCDAY | 1 | | 1
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access(TRUNC(INTERNAL_FUNCTION("DAY"),'fmhh')>=TO_DATE('2009-08-01 00:00:
'yyyy-mm-dd hh24:mi:ss') AND TRUNC(INTERNAL_FUNCTION("DAY"),'fmhh'
00:00:00', 'yyyy-mm-dd hh24:mi:ss'))
17 rows selected
CREATE TABLE t_组(id INT NOT NULL主键,day DATE NOT NULL)
/
插入
进入t_组
选择级别,TRUNC(SYSDATE)-级别
来自双重
通过连接
级别=截止日期('2009-08-01 00:00:00:00:00:00:00:00:00:00:00:00:00:00)
“yyyy-mm-dd hh24:mi:ss”)和TRUNC(内部功能(“日”),“fmhh”
00:00:00',yyyy-mm-dd hh24:mi:ss'))
选定17行
在第一种情况下,WHERE子句中的“天”引用表列“天”,而不是查询结果列“天”,因此可以使用索引,但结果不包括2009年6月14日13:00:01以后的数据
在第二种情况下,WHERE子句中的“day”引用视图列“day”,该列被定义为TRUNC(day,'HH')。因此,这不能使用索引,包含2009年6月14日13:00:01以后的数据-即,这两个查询不相等
您可能希望实现这两种方法的最佳效果:
create or replace view theview as
select day,
TRUNC(day,'HH') trunc_day,
avg(decode(stone,-9999,null,stone)) stone,
avg(decode(simpson,-9999,null,simpson)) simpson,
avg(decode(oxychem,-9999,null,oxychem)) oxychem,
avg(decode(praxair,-9999,null,praxair)) praxair
from IDcpdata group by TRUNC(day,'HH');
SQL> select trunc_day, stone, simpson, oxychem, pracair
2 from theview
3 where day >= to_date('14-jun-2009 0','dd-mon-yyyy hh24')
4 and day < to_date('14-jun-2009 13','dd-mon-yyyy hh24');
create index IDcpdata_truncday_idx ON IDcpdata (TRUNC(day,'HH'));
在IDcpdata(TRUNC(day,'HH')
上构建基于函数的索引的建议是合理的。有其他基于函数的索引吗?如果不是,这也许可以解释为什么优化器不使用它
这种索引类型是在8i中引入的,因此当时的实现有点笨拙。具体来说,您需要设置一些数据库参数,否则优化器将忽略索引
ALTER SESSION SET QUERY_REWRITE_INTEGRITY = TRUSTED;
ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE;
我想你还需要用8i计算统计数据
(我要感谢谷歌和蒂姆·霍尔,他们代理了我的记忆力衰退)。没错,因为这就是我想要的聚合。我将其向下移动到视图中,因此我认为优化器会发现仍然可以使用索引。你是说我的查询应该是SQL>从视图2中选择*,其中trunc(day,'HH')介于3到_日期('2009年6月14日0','dd-mon-yyyyyh24')和4到_日期('2009年6月14日13','dd-mon-yyyyyyyh24');或者我就是不能提出一个可行的观点?谢谢<代码>@Ian
:是。在本例中,day
应该是从表中返回的原始day
。我创建了确切的索引,但没有使用它。即使有暗示!在查询中包含日期会导致该日期未按截断的日期分组。您的示例无法编译,因为DAY未包含在GROUP BY子句中。@Ian
:对,我没有注意到您查询中的GROUP BY
。看到这篇文章更新了。@Tony:我也考虑过,但它不会编译:day不是你的create view语句中的聚合。是的,我也是。问题是我希望数据按小时聚合,包括查询中未截断的日期,需要将其包含在group by子句中。您是对的!唯一真正的问题是为什么它不使用我的函数索引,一旦我意识到通过将聚合推到视图中,我就不能再使用基值上的索引了。那些神秘的甲骨文咒语释放了功能索引的力量,我很高兴。非常感谢。
create index IDcpdata_truncday_idx ON IDcpdata (TRUNC(day,'HH'));
ALTER SESSION SET QUERY_REWRITE_INTEGRITY = TRUSTED;
ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE;