我必须选择当天的日志记录,执行开始日期和结束日期之间的差异超过40分钟。
/opt/
但是这个查询给了我一个错误。
ORA-00932:数据类型不一致:预期NUMBER为DATE
答案 0 :(得分:3)
使用
EXECUTION_ENDED_DATE - EXECUTION_START_DATE > interval '40' minute
此外,重写此条件
TRUNC(EXECUTION_START_DATE)=TRUNC(SYSDATE)
进入这个
EXECUTION_START_DATE >= TRUNC(SYSDATE) and EXECUTION_START_DATE < TRUNC(SYSDATE)+1
因为前一个条件阻止Oracle在EXECUTION_START_DATE列上使用索引并带来全表扫描
<强> ----------------
编辑
---------------- 强>
INTERVAL
子句仅适用于时间戳算术
如果查询返回ORA-00932: inconsistent datatypes: expected NUMBER got INTERVAL DAY TO SECOND
,则将条件更改为:
EXECUTION_ENDED_DATE - EXECUTION_START_DATE > 40/1440
其中“魔术”号码1440是一天中的分钟数(24 * 60)。
你能否详细说明为什么它阻止oracle使用索引。
看一个简单的例子。首先,让我们创建一个充满随机数据的测试dable:
CREATE TABLE IW_MASTER_LOG AS
SELECT sysdate - 500*dbms_random.value as EXECUTION_START_DATE,
t.*
FROM all_objects t;
SELECT count(*) FROM IW_MASTER_LOG;
COUNT(*)
----------
74130
接下来在EXECUTION_START_DATE
列上创建一个索引:
CREATE INDEX my_execution_index ON IW_MASTER_LOG( EXECUTION_START_DATE );
最后刷新表和索引统计信息:
exec DBMS_STATS.gather_table_stats( user, 'IW_MASTER_LOG' );
现在检查此查询的执行计划:
EXPLAIN PLAN FOR
SELECT * FROM IW_MASTER_LOG
WHERE EXECUTION_START_DATE >= trunc( sysdate ) - 1
AND EXECUTION_START_DATE < trunc( sysdate );
SELECT * FROM table( DBMS_XPLAN.DISPLAY );
Plan hash value: 3519959109
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 149 | 18476 | 152 (0)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| IW_MASTER_LOG | 149 | 18476 | 152 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | MY_EXECUTION_INDEX | 149 | | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TRUNC(SYSDATE@!)>TRUNC(SYSDATE@!)-1)
3 - access("EXECUTION_START_DATE">=TRUNC(SYSDATE@!)-1 AND
"EXECUTION_START_DATE"<TRUNC(SYSDATE@!))
以上查询使用索引
现在为使用您的条件的查询生成计划:
EXPLAIN PLAN FOR
SELECT * FROM IW_MASTER_LOG
WHERE trunc(EXECUTION_START_DATE) = trunc( sysdate ) ;
SELECT * FROM table( DBMS_XPLAN.DISPLAY );
Plan hash value: 3290956462
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 741 | 91884 | 378 (1)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| IW_MASTER_LOG | 741 | 91884 | 378 (1)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TRUNC(INTERNAL_FUNCTION("EXECUTION_START_DATE"))=TRUNC(SYSDAT
E@!))
正如您所见,查询执行全表扫描 - trunct
函数阻止Oracle使用该索引。
As @АнатолийПредеинsogested:
您可以为此列创建索引,例如create index IW_MASTER_LOG上的id_trunc_esd(TRUNC(EXECUTION_START_DATE))
他是完全正确的,让我们检查一下他的建议:
CREATE INDEX another_index ON IW_MASTER_LOG( TRUNC(EXECUTION_START_DATE) );
exec DBMS_STATS.gather_table_stats( user, 'IW_MASTER_LOG' );
EXPLAIN PLAN FOR
SELECT * FROM IW_MASTER_LOG
WHERE trunc(EXECUTION_START_DATE) = trunc( sysdate ) ;
SELECT * FROM table( DBMS_XPLAN.DISPLAY );
Plan hash value: 1627571743
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 148 | 19536 | 142 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| IW_MASTER_LOG | 148 | 19536 | 142 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | ANOTHER_INDEX | 148 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(TRUNC(INTERNAL_FUNCTION("EXECUTION_START_DATE"))=TRUNC(SYSDATE@!))
完美 - 查询使用新索引。你可以关注АнатолийПредеин的建议
但是这个索引是有限的 - 它只能提供trunc(EXECUTION_START_DATE) = ...
条件的查询。它不能用于选择某个日期和此日期之间的行数+ 10分钟 - 我们仍然需要EXECUTION_START_DATE
列上的普通索引。如果我问我的DBA是否可以创建两个索引而不是一个索引,因为我太懒了并且在查询中重写了一个条件trunc( date )
,那么他可能会打电话给我。
答案 1 :(得分:0)
试试这个
with a as ( select sysdate sd, sysdate+(1/24/60)*39 ed from dual)
-- in with sysdate and sysdate + 39 minute
select to_char(sd,'dd.mm.yyyy hh24:mi:ss'),
to_char(ed,'dd.mm.yyyy hh24:mi:ss'),
to_number(ed-sd) *24 * 60
from a
where to_number(ed-sd) *24 * 60 < 40
在你的情况下
with IW_MASTER_LOG as (select sysdate EXECUTION_START_DATE, sysdate+(1/24/60)*41 EXECUTION_ENDED_DATE from dual )
select IW_MASTER_LOG.*
from IW_MASTER_LOG
WHERE TRUNC(EXECUTION_START_DATE)=TRUNC(SYSDATE)
AND to_number(EXECUTION_ENDED_DATE - EXECUTION_START_DATE) *24 * 60 > 40;
答案 2 :(得分:0)
WITH IW_MASTER_LOG AS
(SELECT SYSDATE AS EXECUTION_START_DATE,
SYSDATE AS EXECUTION_END_DATE
FROM DUAL
UNION ALL
SELECT SYSDATE, SYSDATE+1/24/60*30 FROM DUAL
UNION ALL
SELECT SYSDATE, SYSDATE+1/24/60*41 FROM DUAL
)
SELECT *
FROM IW_MASTER_LOG
WHERE (EXECUTION_END_DATE-EXECUTION_START_DATE)>=1/24/60*40
AND TRUNC(EXECUTION_START_DATE) = TRUNC(SYSDATE); --started today
Oracle日期表示为天数的分数,意味着什么。
1 - day
1/24 - hour
1/24/60 - minute
1/24/60*40 - 40 mins
TRUNC - 省略第二个参数返回日期。
在以下数据集
的结果中使用 WITH 子句07.15.2016 14:13:54 | 07.15.2016 14:13:54
07.15.2016 14:13:55 | 07.15.2016 14:43:55
07.15.2016 14:13:56 | 07.15.2016 14:54:56
查询仅返回最后一条记录(所需内容,因为41分钟)