我有一个名为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.有人可以告诉我为什么这两种方法之间存在如此大的差异?如果您需要一些附加信息,请告诉我。
答案 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的任何好处。负面是非确定性的顺序,仅支持每日间隔的粒度。