Oracle SQL索引DATE与索引TRUNC(DATE)

时间:2017-01-09 16:20:12

标签: sql oracle performance sql-tuning

我有一个名为DEXTRACTO的表,我需要根据F_EXTRACTO列(DATE格式)BETWEEN DATE1 AND DATE2条件查询一段时间({ {1}}和DATE1可以更改)。以下是该表的一些数据:

DATE2

我想使用索引,但我不知道哪种方法更好。我应该在SQL> SELECT MIN(F_EXTRACTO), MAX(F_EXTRACTO), COUNT(1) 2 FROM DEXTRACTO 3 / MIN(F_EXTRACTO) MAX(F_EXTRACTO) COUNT(1) --------------- --------------- ---------- 03/01/2005 06/01/2017 13772806 SQL> SELECT COUNT(1) FROM DEXTRACTO WHERE F_EXTRACTO IS NULL 2 / COUNT(1) ---------- 0 SQL> 栏上使用它吗?或者我应该在F_EXTRACTO上使用索引? 我知道使用带有函数的索引并不是一个好主意,但是测试这两种方法我得到了这个......

TRUNC(F_EXTRACTO)

SQL> create index INDEX_DATE on DEXTRACTO (F_EXTRACTO) 2 / Index created SQL> create index INDEX_TRUNC on DEXTRACTO (TRUNC(F_EXTRACTO)) 2 / Index created SQL> 上测试索引:

F_EXTRACTO

SQL> explain plan for 2 2 SELECT /*+ index (dextracto INDEX_DATE) */ * 3 FROM dextracto 4 WHERE f_extracto 5 BETWEEN to_date('01/01/2005','dd/mm/yyyy') AND SYSDATE 6 / Explained SQL> select plan_table_output from table(dbms_xplan.display()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 12M| 1088M| 250K| | 1 | FILTER | | | | | | 2 | TABLE ACCESS BY INDEX ROWID| DEXTRACTO | 12M| 1088M| 250K| | 3 | INDEX RANGE SCAN | INDEX_DATE | 12M| | 36972 | --------------------------------------------------------------------------- Note ----- - 'PLAN_TABLE' is old version 13 rows selected SQL> 上测试索引:

TRUNC(F_EXTRACTO)

所以......如果我使用索引SQL> explain plan for 2 2 SELECT /*+ index (dextracto INDEX_TRUNC) */ * 3 FROM dextracto 4 WHERE TRUNC(f_extracto) 5 BETWEEN to_date('01/01/2005','dd/mm/yyyy') AND SYSDATE 6 / Explained SQL> select plan_table_output from table(dbms_xplan.display()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 32437 | 2787K| 1130 | | 1 | FILTER | | | | | | 2 | TABLE ACCESS BY INDEX ROWID| DEXTRACTO | 32437 | 2787K| 1130 | | 3 | INDEX RANGE SCAN | INDEX_TRUNC | 58387 | | 169 | ---------------------------------------------------------------------------- Note ----- - 'PLAN_TABLE' is old version 13 rows selected SQL> ,成本是250000,但如果我使用索引F_EXTRACTO,那么成本是1130.有人可以告诉我为什么这两种方法之间存在如此大的差异?如果您需要一些附加信息,请告诉我。

2 个答案:

答案 0 :(得分:3)

估计行数(12M对58387)之间的巨大差异很可能归因于过时的统计数据。我建议在添加索引后收集统计信息(例如,使用DBMS_STATS.gather_table_stats)。

此外,EXPLAIN PLAN并不保证该计划是实际使用的计划。我宁愿运行查询,然后使用dbms_xplan.display_cursor检查实际执行计划。查看v$sql / v$sqlarea视图的执行细节也很有意义。

答案 1 :(得分:3)

  

我想使用索引,但我不知道哪种方法更好。

您最终使用索引访问表中的所有14M行(如示例所示)。 收集统计信息后,无需提示即可重新尝试解释计划,并且您可以使用索引访问的低成本访问FULL TABLE SCAN。  从成本INDEX / FTS的比率,您可以估计值通过索引访问的表的部分。

要访问最多几个月,INDEX ACCESS可能更有效,但超过某个阈值FULL SCAN会更好(检查解释计划和执行 - 这可能会产生不同的结果)。

在您的使用案例中,我没有看到使用FBI的任何好处。负面是非确定性的顺序,仅支持每日间隔的粒度。