Oracle Avg按组排序不正确

时间:2019-01-04 19:52:57

标签: sql oracle oracle12c

在Oracle 12.2的group by子句中的聚合函数上使用order by时,我们收到的结果排序不正确。在使用它之后,我们发现该查询仅在以某些方式用词组表达时才有效(请参见下文)。

这是我们的问题:

1)为什么按Avg排序很挑剔?查询是否基于某些已记录的逻辑/限制而按预期运行?是否与底层数据类型为number(16)而没有小数位数有关?

2)为什么在查询4中使用别名却使查询3无效?

3)为什么按持续时间递增排序时查询工作更好?它未在下面显示,但查询2在使用asc时仍然有效,即使它在desc中也不起作用。查询1不适用于asc。

在以下示例中,持续时间是一个数字(16)。

查询1:平均功能按功能排序

select
    name,
    avg(duration)
from table1
join table2 on table1.table2_id = table2.id
where duration is not null
group by name
order by avg(duration) desc

-- Query 1 result (wrong)
(some name) 1224417.83471074
(some name) 33568438.1548673
(some name) 3928150.12809406
(some name) 1434939.13464658
(some name) 269338.574638521

查询2:平均功能按别名排序

-- Query 2: order by avg alias
select
    name,
    avg(duration) avg
from table1
join table2 on table1.table2_id = table2.id
where duration is not null
group by name
order by avg desc

-- Query 2 result (wrong)
-- See query 1 result

-- Note: For some reason this query works correctly when ordered asc

查询3:平均功能,按功能进行转换

select
    name,
    to_number(avg(duration))
from table1
join table2 on table1.table2_id = table2.id
where duration is not null
group by name
order by to_number(avg(duration)) desc

-- Query 3 result (wrong)
-- See query 1 result

查询4:具有别名转换顺序的平均功能

select
    name,
    to_number(avg(duration)) avg
from table1
join table2 on table1.table2_id = table2.id
where duration is not null
group by name
order by avg desc

-- Query 4 results (correct)
(some name) 562654936
(some name) 498804314
(some name) 263681023
(some name) 245531731
(some name) 188103278
-- the values with decimals show up later in the right order

查询5和查询6:具有/不具有在外部查询中排序的平均功能

select * from (
    select
        name,
        to_number(avg(duration)) avg -- works without to_number as well
    from table1
    join table2 on table1.table2_id = table2.id
    where duration is not null
    group by name
) order by avg desc

-- Query 5 & 6 results (correct)
-- See query 4 results

2 个答案:

答案 0 :(得分:1)

我猜要获得正确的输出结果,您需要已经进行了聚合,但是这里发生的是在按您进行聚合的顺序再次分组之后完成聚合时,因此即使已经完成的聚合也可以再次开始聚合它的别名是使用外部查询最有效的方法是:首先在汇总后最终确定输出,然后在外部查询中像select col1,col2 from (select col,agg(..) from table group by col) order by col2那样进行排序,这将限制为仅对接收到的输出进行排序,而不会再次进行聚合和排序。

答案 1 :(得分:0)

我们已将其追溯到我们认为是Oracle优化器中的错误。当优化器选择使用称为VW_GBC_5的视图时,就会发生这种情况。请遵守以下说明计划:

有问题

-- This produces incorrect result set ordering
select 
    /*+ qb_name(m) place_group_by(@m) */ 
    name,
    avg(duration)
from table1
join table2 on table1.table2_id = table2.id
where duration is not null
group by name
order by avg(duration) desc;

-------------------------------------------------------------------------------------------------
| Id  | Operation              | Name           | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |                | 35540 |  3366K|       |  9433   (1)| 00:00:01 |
|   1 |  SORT ORDER BY         |                | 35540 |  3366K|  3800K|  9433   (1)| 00:00:01 |
|   2 |   HASH GROUP BY        |                | 35540 |  3366K|  3800K|  9433   (1)| 00:00:01 |
|*  3 |    HASH JOIN           |                | 35540 |  3366K|       |  7852   (1)| 00:00:01 |
|   4 |     VIEW               | VW_GBC_5       | 35540 |  1145K|       |  7510   (2)| 00:00:01 |
|   5 |      HASH GROUP BY     |                | 35540 |   416K|       |  7510   (2)| 00:00:01 |
|*  6 |       TABLE ACCESS FULL| TABLE1         |  1225K|    14M|       |  7461   (1)| 00:00:01 |
|   7 |     TABLE ACCESS FULL  | TABLE2         | 38955 |  2434K|       |   342   (1)| 00:00:01 |
-------------------------------------------------------------------------------------------------

没有问题

-- This produces correct result set ordering
select 
    /*+ qb_name(m) no_place_group_by(@m) */ 
    name,
    avg(duration)
from table1
join table2 on table1.table2_id = table2.id
where duration is not null
group by name
order by avg(duration) desc;

-----------------------------------------------------------------------------------------------
| Id  | Operation            | Name           | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                | 38412 |  2850K|       | 25624   (1)| 00:00:02 |
|   1 |  SORT ORDER BY       |                | 38412 |  2850K|    98M| 25624   (1)| 00:00:02 |
|   2 |   HASH GROUP BY      |                | 38412 |  2850K|    98M| 25624   (1)| 00:00:02 |
|*  3 |    HASH JOIN         |                |  1225K|    88M|  2896K|  9345   (1)| 00:00:01 |
|   4 |     TABLE ACCESS FULL| TABLE2         | 38955 |  2434K|       |   342   (1)| 00:00:01 |
|*  5 |     TABLE ACCESS FULL| TABLE1         |  1225K|    14M|       |  7461   (1)| 00:00:01 |
-----------------------------------------------------------------------------------------------

解决方法

  1. 重写查询(请参阅原始问题)

  2. 禁用_simple_view_merging

    更改会话集“ _simple_view_merging” = false;

  3. 切换到其他优化器版本

    更改会话集optimizer_features_enable = '12 .1.0.2';

  4. 使用no_place_group_by优化器提示