【问题标题】:Oracle. Create index on a DATE column甲骨文。在 DATE 列上创建索引
【发布时间】:2025-12-29 10:15:14
【问题描述】:

我想知道在CREATION_DATE 字段中创建索引是否会对该查询有任何改进

   select TO_CHAR(CREATION_DATE, 'HH24') || ':mm' HOUR, count ('1')  MESSAGE_HOUR
        from t_hotel             
           where TO_CHAR(CREATION_DATE, 'dd/mm/yyyy') = TO_CHAR(SYSDATE, 'dd/mm/yyyy') 
group by TO_CHAR(CREATION_DATE, 'HH24') 
    order by TO_CHAR(CREATION_DATE, 'HH24') ;

【问题讨论】:

  • CREATION_DATE 是文本列吗?如果是这样,请更改您的表格设计并使其成为日期列。

标签: oracle oracle12c


【解决方案1】:

是的,您可以利用 CREATION_DATE 列上的基于函数的索引。

以下面的演示为例,我有一个表,其中有一列date 类型。

create table t_hotel  (creation_date date);
insert into t_hotel select sysdate+0.5 from dual connect by level <=100;
100 行受影响
insert into t_hotel select sysdate+0.2 from dual connect by level <=100;
100 行受影响
 explain plan for  select TO_CHAR(CREATION_DATE, 'HH24') || ':mm' HOUR, count ('1')  MESSAGE_HOUR
        from t_hotel             
           where trunc(creation_date)= trunc(sysdate) 
group by TO_CHAR(CREATION_DATE, 'HH24') 
    order by TO_CHAR(CREATION_DATE, 'HH24') ;
select * from table(dbms_xplan.display());
|计划表输出 | | :------------------------------------------------ ---------------------------------------- | |计划哈希值:353888308 | | | | -------------------------------------------------- ---------------------------------------- | | |身份证 |操作 |姓名 |行 |字节 |成本 (%CPU)|时间 | | | -------------------------------------------------- ---------------------------------------- | | | 0 |选择声明 | | 200 | 1800 | 4 (25)| 00:00:01 | | | | 1 |分组依据 | | 200 | 1800 | 4 (25)| 00:00:01 | | | |* 2 |表访问已满| T_酒店 | 200 | 1800 | 3 (0)| 00:00:01 | | | -------------------------------------------------- ---------------------------------------- | | | |谓词信息(由操作 id 标识):| | -------------------------------------------------- - | | | | 2 - 过滤器(TRUNC(INTERNAL_FUNCTION(“CREATION_DATE”))=TRUNC(SYSDATE@!)| | ) | | | |注意 | | ----- | | - 用于此语句的动态采样 (level=2) |
create index idx_cd on t_hotel(trunc(creation_date));
 explain plan for  select TO_CHAR(CREATION_DATE, 'HH24') || ':mm' HOUR, count ('1')  MESSAGE_HOUR
        from t_hotel             
           where trunc(creation_date)= trunc(sysdate) 
group by TO_CHAR(CREATION_DATE, 'HH24') 
    order by TO_CHAR(CREATION_DATE, 'HH24') ;
select * from table(dbms_xplan.display());
|计划表输出 | | :------------------------------------------------ -------------------------------------------------- | |计划哈希值:2841908389 | | | | -------------------------------------------------- -------------------------------------------------- | | |身份证 |操作 |姓名 |行 |字节 |成本 (%CPU)|时间 | | | -------------------------------------------------- -------------------------------------------------- | | | 0 |选择声明 | | 2 | 36 | 3 (34)| 00:00:01 | | | | 1 |分组依据 | | 2 | 36 | 3 (34)| 00:00:01 | | | | 2 |按索引 ROWID 访问表| T_酒店 | 2 | 36 | 2 (0)| 00:00:01 | | | |* 3 |索引范围扫描 | IDX_CD | 1 | | 1 (0)| 00:00:01 | | | -------------------------------------------------- -------------------------------------------------- | | | |谓词信息(由操作 id 标识):| | -------------------------------------------------- - | | | | 3 - 访问(TRUNC(INTERNAL_FUNCTION("CREATION_DATE"))=TRUNC(SYSDATE@!)) | | | |注意 | | ----- | | - 用于此语句的动态采样 (level=2) |

dbfiddle here

【讨论】:

  • (creation_date date); Tim 的第一条评论是该列本身不是DATE 列。即使来自 OP 问题,列的数据类型也不清楚,但查看查询看起来像 varchar
  • 如果该列是varchar2,那么我认为OP 不能将TO_CHAR 函数与数据格式化字符串一起使用。
  • 您必须在答案中输入Assumption
  • @XING,根据所提出的问题,绝对没有理由假设该列不是日期。毕竟,他们在问题标题中明确表示这是一个日期列
【解决方案2】:

1) where 子句应该以不同的方式书写。 where creation_date &gt;= trunc(sysdate) and creation_date &lt; trunc(sysdate+1)
2)您可以创建两个索引。
- 正常 create index idx_creation_date on t_hotel(creation_date); 改进 where 子句。
- 功能基础索引create index idx_creation_date_hh24 on t_hotel(TO_CHAR(CREATION_DATE, 'HH24') ); 可能会改进 group by 和 orderby 但我不确定。

【讨论】: