Oracle SQL 索引 DATE 与索引 TRUNC(DATE)
Oracle SQL Index DATE vs Index TRUNC(DATE)
我有一个名为DEXTRACTO
的Table,需要根据F_EXTRACTO
列查询一段时间(为DATE
格式)具有 BETWEEN DATE1 AND DATE2
条件(DATE1
和 DATE2
可以更改)。这是 table:
的一些数据
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>
所以...如果我使用索引 F_EXTRACTO
成本是 250000,但如果我使用索引 TRUNC(F_EXTRACTO)
成本是 1130。有人能告诉我为什么两者之间存在如此大的差异两种方法?如果您需要一些其他信息,请告诉我。
估计行数(12M 与 58387)之间的巨大差异很可能是由于过时的统计数据造成的。我建议在添加索引后收集统计信息(例如,使用 DBMS_STATS.gather_table_stats
)。
此外,EXPLAIN PLAN
不保证计划就是实际使用的计划。我宁愿 运行 查询,然后用 dbms_xplan.display_cursor
检查实际执行计划。查看 v$sql
/v$sqlarea
视图以了解执行细节也很有意义。
I want to use an index but I don't know wich approach is better.
您肯定不会使用索引访问table中的所有1400万行(如您的示例所示)。
收集统计信息后,在没有提示的情况下重试解释计划,您将看到 FULL TABLE SCAN
以比索引访问更低的成本进行访问。
根据成本 INDEX / FTS 的比率,您可以估计 table 中值得通过索引访问的部分。
要访问长达几个月的时间,INDEX ACCESS 可能更有效,但高于某个阈值时,FULL SCAN 会更好(同时检查解释计划和执行 - 这可能会产生不同的结果)。
在您的用例中,我看不到使用 FBI 有任何好处。不利的一面是不确定的顺序,仅支持每日间隔的粒度。
我有一个名为DEXTRACTO
的Table,需要根据F_EXTRACTO
列查询一段时间(为DATE
格式)具有 BETWEEN DATE1 AND DATE2
条件(DATE1
和 DATE2
可以更改)。这是 table:
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>
所以...如果我使用索引 F_EXTRACTO
成本是 250000,但如果我使用索引 TRUNC(F_EXTRACTO)
成本是 1130。有人能告诉我为什么两者之间存在如此大的差异两种方法?如果您需要一些其他信息,请告诉我。
估计行数(12M 与 58387)之间的巨大差异很可能是由于过时的统计数据造成的。我建议在添加索引后收集统计信息(例如,使用 DBMS_STATS.gather_table_stats
)。
此外,EXPLAIN PLAN
不保证计划就是实际使用的计划。我宁愿 运行 查询,然后用 dbms_xplan.display_cursor
检查实际执行计划。查看 v$sql
/v$sqlarea
视图以了解执行细节也很有意义。
I want to use an index but I don't know wich approach is better.
您肯定不会使用索引访问table中的所有1400万行(如您的示例所示)。
收集统计信息后,在没有提示的情况下重试解释计划,您将看到 FULL TABLE SCAN
以比索引访问更低的成本进行访问。
根据成本 INDEX / FTS 的比率,您可以估计 table 中值得通过索引访问的部分。
要访问长达几个月的时间,INDEX ACCESS 可能更有效,但高于某个阈值时,FULL SCAN 会更好(同时检查解释计划和执行 - 这可能会产生不同的结果)。
在您的用例中,我看不到使用 FBI 有任何好处。不利的一面是不确定的顺序,仅支持每日间隔的粒度。