提示FIRST_ROWS(n)没有为Order by子句提供优化结果

时间:2016-08-01 07:24:49

标签: sql oracle11g optimizer-hints

我们在一个包含大约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的子句时,例如creationtime(该表几乎是该表中每一行的唯一值),此查询将需要很长时间才能返回所有列。

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列,结果以某种方式变得更快。

P.S。每周在此表上运行收集统计信息,但每小时推送一次数据。此表上仅运行INSERT语句,此表上未运行DELETEUPDATE个查询。

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

2 个答案:

答案 0 :(得分:0)

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

当您添加order by子句时,必须先找到所有数据才能订购。必须满足所有连接条件,并且所有嵌套循环/合并等都已完成,然后整个结果集必须按照您指定的顺序排序,然后 any < / em>行可以返回。

如果您订购的列已编入索引并且优化器正在使用(或可以使用)该索引来识别驱动表中的行,那么可能它可以合并排序,但你不能依赖它,因为优化者可以随着数据和统计数据的变化而改变计划。

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

答案 1 :(得分: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 |
--------------------------------------------------------------------------------------------------------------

如果你看到,它在成本,所涉及的行,临时空间的使用(后来甚至没有使用)以及最后的时间上有明显的区别。

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

感谢。