0

我们在一个大约有 50 列的表中有大约 800 万条记录,我们需要非常快速地查看少量记录,因此我们为此目的使用 FIRST_ROWS(10) 提示,并且它的工作速度非常快。

SELECT /*+ FIRST_ROWS(10) */ ABC.view_ABC.ID, ABC.view_ABC.VERSION, ABC.view_ABC.M_UUID, ABC.view_ABC.M_PROCESS_NAME FROM ABC.view_ABC

但是,当我们放置 ORDER BY 子句时,例如创建时间(这几乎是该表中每一行的唯一值),此查询将需要很长时间才能返回所有列。

SELECT /*+ FIRST_ROWS(10) */ ABC.view_ABC.ID, ABC.view_ABC.VERSION, ABC.view_ABC.M_UUID, ABC.view_ABC.M_PROCESS_NAME FROM ABC.view_ABC ORDER BY ABC.view_ABC.CREATIONTIME DESC

我注意到的一件事是;如果我们为某个列(例如 VERSION)放置一个 ORDER BY,它对多行具有相同的值,它会提供更好的结果。

对于此表中的列这样的任何唯一列,这ORDER BY都不能有效地工作ID

另一件值得考虑的事情是;如果我们减少要获取的列数,例如 3 列而不是 50 列,结果会以某种方式更快地出现。

PS 收集统计信息每周在此表上运行,但数据每小时推送一次。只有INSERT语句在此表上运行,没有DELETEUPDATE查询在此表上运行。

此外,还有一个没有创建此表的简单视图,上述查询正在同一视图上运行。

4

2 回答 2

0

此列 ( ) 上有一个多列索引CREATION_TIME,不知何故 oracle 提示优化器未使用此索引。

但是在同一张表上还有另一列 ( TERMINATION_TIME),它本身有一个索引。ORDER BY所以我们使用相同的查询,但在子句中使用这个索引列。

以下是 ORDER BY 子句中使用 CREATION_TIME 的第一个查询的解释计划,该子句是多列索引的一部分。

-------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name                           | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                                |  7406K|   473M|       |   308K  (1)| 01:01:40 |
|   1 |  SORT ORDER BY     |                                |  7406K|   473M|   567M|   308K  (1)| 01:01:40 |
|   2 |   TABLE ACCESS FULL| Table_ABC                      |  7406K|   473M|       |   189K  (1)| 00:37:57 |
-------------------------------------------------------------------------------------------------------------

而这个是用 TERMINATION_TIME 作为 ORDER BY 子句的。

--------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name                           | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                                |    10 |   670 |    10   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TABLE_ABC                      |  7406K|   473M|    10   (0)| 00:00:01 |
|   2 |   INDEX FULL SCAN DESCENDING| XGN620150305000000             |    10 |       |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------------

如果您看到,它在成本、涉及的行数、临时空间的使用(甚至在以后的情况下都没有使用)以及最后的时间方面存在明显差异。

现在查询响应时间要好得多。

谢谢。

于 2016-08-04T13:18:23.433 回答
0

如果没有order by子句,优化器可以执行视图隐藏的任何连接操作,并在有数据时立即开始返回数据。提示正在更改它访问基础表的方式,例如,它执行嵌套循环连接而不是合并连接 - 这将允许它快速找到第一个匹配的行;但总体上返回所有数据的效率可能较低。您的提示是告诉优化器您希望它优先考虑返回的第一批行的速度而不是整个查询的速度。

添加order by子句时,必须先找到所有数据,然后才能对其进行排序。必须满足所有连接条件并完成所有嵌套循环/合并等,然后必须按照您指定的顺序对整个结果集进行排序,然后才能返回任何行。

如果您要排序的列被索引并且优化器正在使用(或可以使用)该索引来识别驱动表中的行,那么它可能会将其合并到排序中,但您不能依赖在这一点上,优化器可以随着数据和统计数据的变化而改变计划。

您可能会发现查看各种查询的执行计划很有用,无论是否有提示,以了解优化器在每种情况下都在做什么,包括它在步骤链中执行排序操作的位置,以及类型它正在做的连接。

于 2016-08-01T09:12:05.007 回答