to_char和to_date之间的性能差异

时间:2013-12-15 18:56:43

标签: sql oracle10g

我在Oracle 10g上有简单的SQL查询..我想知道这些查询之间的区别:

select * from employee where id = 123 and 
          to_char(start_date, 'yyyyMMdd') >= '2013101' and 
          to_char(end_date, 'yyyyMMdd') <= '20121231';

select * from employee where id = 123 and 
          start_date >= to_date('2013101', 'yyyyMMdd') and 
          end_date <= to_date('20121231', 'yyyyMMdd');

问题: 1.这些查询是否相同? start_date,end_date是索引日期列。 2.一个人比另一个好吗?

请告诉我。谢谢。

3 个答案:

答案 0 :(得分:2)

后者几乎肯定会更快。

  • 它避免了列值的数据类型转换。
  • Oracle会更好地估算两个日期之间可能值的数量,而不是两个代表日期的字符串。

请注意,根据您给出的数字,两者都不会返回任何行,因为下限可能意图高于上限。你也错过了2013101的数字。

答案 1 :(得分:2)

WHERE子句中转换,转换或转换为表达式(即“NVL”,“COALESCE”等)时,最大缺陷之一 CBO将无法在该列上使用索引。我稍微修改了你的例子以显示差异:

SQL> create table t_test as
  2    select * from all_objects;
Table created
SQL> create index T_TEST_INDX1 on T_TEST(CREATED, LAST_DDL_TIME);
Index created

为我们的实验创建了表格和索引。

SQL> execute dbms_stats.set_table_stats(ownname => 'SCOTT',
                                        tabname => 'T_TEST',
                                        numrows => 100000,
                                        numblks => 10000);
PL/SQL procedure successfully completed

我们正在让CBO认为我们的桌子很大。

SQL> explain plan for
  2  select *
  3    from t_test tt
  4   where tt.owner = 'SCOTT'
  5     and to_char(tt.last_ddl_time, 'yyyyMMdd') >= '20130101'
  6     and to_char(tt.created, 'yyyyMMdd') <= '20121231';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2796558804
----------------------------------------------------------------------------
| Id  | Operation         | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |        |     3 |   300 |  2713   (1)| 00:00:33 |
|*  1 |  TABLE ACCESS FULL| T_TEST |     3 |   300 |  2713   (1)| 00:00:33 |
----------------------------------------------------------------------------

使用全表扫描,这对于大桌子来说是昂贵的。

SQL> explain plan for
  2  select *
  3    from t_test tt
  4   where tt.owner = 'SCOTT'
  5     and tt.last_ddl_time >= to_date('20130101', 'yyyyMMdd')
  6     and tt.created <= to_date('20121231', 'yyyyMMdd');
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1868991173
-------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              |     3 |   300 |     4   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS BY INDEX ROWID| T_TEST       |     3 |   300 |     4   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T_TEST_INDX1 |     8 |       |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

请注意,现在它是指数范围扫描,成本显着降低。

SQL> drop table t_test;
Table dropped

最后清洁。

答案 2 :(得分:0)

用于输出(显示)目的使用to_char

用于“日期”处理(插入,更新,比较等)使用to_date

我没有任何性能链接可以共享,但在上面使用to_date查询应该运行得更快!

虽然to_char将首先投射日期然后进行比较,但它需要将其解析为日期类型。性能损失会很小。

使用to_date时,它不需要先进行强制转换,它将直接使用日期类型。