Oracle PARTITION BY vs GROUP BY 的解释,结果相似

Explanation of Oracle PARTITION BY vs GROUP BY for similar results

我有以下table(分数):

firstname    lastname    Mark    
------------------------------
arun         prasanth    40      
ann          antony      45      
sruthy       abc         41      
new          abc         47      
arun         prasanth    45      
arun         prasanth    49      
ann          antony      49      

并且想添加一个列,用于在具有特定列的记录多次出现时进行标记。这是结果:

firstname    lastname    Mark    MULTI_FLAG
----------------------------------------------
arun         prasanth    40      1
ann          antony      45      1
sruthy       abc         41      0
new          abc         47      0
arun         prasanth    45      1
arun         prasanth    49      1
ann          antony      49      1

我可以通过以下 GROUP BY 查询得到结果:

SELECT M1.firstname
      ,M1.lastname
      ,M1.Mark
      ,M2.MULTI_COUNT
FROM Marks  M1
JOIN (SELECT firstname, lastname, CASE WHEN COUNT (*) > 1 THEN 1 ELSE 0 END AS MULTI_COUNT
    FROM Marks
    GROUP BY firstname, lastname) M2
   ON M2.firstname = M1.firstname AND M2.lastname = M1.lastname;

或者更漂亮 PARTITION BY 查询:

SELECT
  firstname,
  lastname,
  CASE WHEN COUNT(*) OVER (PARTITION BY
     firstname,
     lastname) > 1 THEN 1 ELSE 0 END AS MULTI_FLAG
FROM
  Marks

运行 GROUP BY 查询返回类似的大 table: 34 米 56 秒 595 毫秒

运行 PARTITION BY 查询返回类似的大 table:

  1. 第一个 运行: 55 米 47 秒 851 毫秒
  2. 第二个运行:36米46秒95毫秒

我有兴趣知道:

  1. 实现我的结果的最佳方式
  2. 造成性能差异的原因。
  3. 编辑:如何阅读查询计划。

编辑: 甲骨文版本 Oracle 数据库 11g 企业版 11.2.0.3.0 版 - 64 位生产 PL/SQL 版本 11.2.0.3.0 - 生产 "CORE 11.2.0.3.0 Production" Linux 的 TNS:版本 11.2.0.3.0 - 生产 NLSRTL 版本 11.2.0.3.0 - 生产

按计划分区

PLAN_TABLE_OUTPUT
Plan hash value: 3822227444

---------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                            |   668K|    90M|       | 90429   (1)| 00:18:06 |
|   1 |  WINDOW SORT                   |                            |   668K|    90M|    98M| 90429   (1)| 00:18:06 |
|*  2 |   HASH JOIN RIGHT OUTER        |                            |   668K|    90M|       | 69340   (1)| 00:13:53 |
|   3 |    TABLE ACCESS FULL           | COUNTRY_REGION_MAPPINGS    |   177 |  4779 |       |     3   (0)| 00:00:01 |
|   4 |    NESTED LOOPS                |                            |       |       |       |            |          |
|   5 |     NESTED LOOPS               |                            |   377K|    41M|       | 69335   (1)| 00:13:53 |
|   6 |      MAT_VIEW ACCESS FULL      | PROJINFO_MAX_ITER_MVW      | 17713 |   328K|       |   782   (1)| 00:00:10 |
|*  7 |      INDEX RANGE SCAN          | Q_CLIN_ASSUM_BYCOUN_PK     |     1 |       |       |     3   (0)| 00:00:01 |
|   8 |     TABLE ACCESS BY INDEX ROWID| Q_CLINICAL_ASSUM_BYCOUNTRY |    21 |  2016 |       |     4   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access(UPPER("CRM"."COUNTRY"(+))=UPPER("QCAB"."TRIAL_COUNTRY"))
   7 - access("PMIM"."OPPORTUNITYNUM"="QCAB"."OPPORTUNITYNUM" AND "PMIM"."CONTRACTNUM"="QCAB"."CONTRACTNUM" 
              AND "PMIM"."ITERATION"="QCAB"."ITERATION")
       filter(UPPER("QCAB"."SHEET_LOC") LIKE '%COUNTRY ASSUMPTIONS%' OR UPPER("QCAB"."SHEET_LOC") LIKE 
              'INPUT%')

按计划分组

PLAN_TABLE_OUTPUT
Plan hash value: 648231064

------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                         | Name                       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |                            |   912 |  2052K|       |   226K  (1)| 00:45:22 |
|*  1 |  HASH JOIN                        |                            |   912 |  2052K|       |   226K  (1)| 00:45:22 |
|   2 |   TABLE ACCESS FULL               | COUNTRY_REGION_MAPPINGS    |   177 |  4779 |       |     3   (0)| 00:00:01 |
|*  3 |   HASH JOIN                       |                            | 89667 |   194M|    45M|   226K  (1)| 00:45:22 |
|   4 |    NESTED LOOPS                   |                            |       |       |       |            |          |
|   5 |     NESTED LOOPS                  |                            |   377K|    41M|       | 69335   (1)| 00:13:53 |
|   6 |      MAT_VIEW ACCESS FULL         | PROJINFO_MAX_ITER_MVW      | 17713 |   328K|       |   782   (1)| 00:00:10 |
|*  7 |      INDEX RANGE SCAN             | Q_CLIN_ASSUM_BYCOUN_PK     |     1 |       |       |     3   (0)| 00:00:01 |
|   8 |     TABLE ACCESS BY INDEX ROWID   | Q_CLINICAL_ASSUM_BYCOUNTRY |    21 |  2016 |       |     4   (0)| 00:00:01 |
|   9 |    VIEW                           |                            |   668K|  1377M|       | 86518   (1)| 00:17:19 |
|  10 |     HASH GROUP BY                 |                            |   668K|    72M|    80M| 86518   (1)| 00:17:19 |
|* 11 |      HASH JOIN RIGHT OUTER        |                            |   668K|    72M|       | 69340   (1)| 00:13:53 |
|  12 |       TABLE ACCESS FULL           | COUNTRY_REGION_MAPPINGS    |   177 |  2478 |       |     3   (0)| 00:00:01 |
|  13 |       NESTED LOOPS                |                            |       |       |       |            |          |
|  14 |        NESTED LOOPS               |                            |   377K|    35M|       | 69335   (1)| 00:13:53 |
|  15 |         MAT_VIEW ACCESS FULL      | PROJINFO_MAX_ITER_MVW      | 17713 |   328K|       |   782   (1)| 00:00:10 |
|* 16 |         INDEX RANGE SCAN          | Q_CLIN_ASSUM_BYCOUN_PK     |     1 |       |       |     3   (0)| 00:00:01 |
|  17 |        TABLE ACCESS BY INDEX ROWID| Q_CLINICAL_ASSUM_BYCOUNTRY |    21 |  1701 |       |     4   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("R2"."TRIAL_COUNTRY_CD"="CRM"."COUNTRY_CD" AND 
              UPPER("CRM"."COUNTRY")=UPPER("QCAB"."TRIAL_COUNTRY"))
   3 - access("R2"."OPPORTUNITYNUM"="QCAB"."OPPORTUNITYNUM" AND "R2"."ITERATION"="QCAB"."ITERATION" AND 
              "R2"."CONTRACTNUM"="QCAB"."CONTRACTNUM" AND "R2"."ASSUMPTION"="QCAB"."ASSUMPTION")
   7 - access("PMIM"."OPPORTUNITYNUM"="QCAB"."OPPORTUNITYNUM" AND "PMIM"."CONTRACTNUM"="QCAB"."CONTRACTNUM" AND 
              "PMIM"."ITERATION"="QCAB"."ITERATION")
       filter(UPPER("QCAB"."SHEET_LOC") LIKE '%COUNTRY ASSUMPTIONS%' OR UPPER("QCAB"."SHEET_LOC") LIKE 'INPUT%')
  11 - access(UPPER("CRM"."COUNTRY"(+))=UPPER("QCAB"."TRIAL_COUNTRY"))
  16 - access("PMIM"."OPPORTUNITYNUM"="QCAB"."OPPORTUNITYNUM" AND "PMIM"."CONTRACTNUM"="QCAB"."CONTRACTNUM" AND 
              "PMIM"."ITERATION"="QCAB"."ITERATION")
       filter(UPPER("QCAB"."SHEET_LOC") LIKE '%COUNTRY ASSUMPTIONS%' OR UPPER("QCAB"."SHEET_LOC") LIKE 'INPUT%')

通常,您从解析函数 count(*) 开始,这会导致紧凑 SQL.

这种方法的缺点是必须对数据进行排序(参见WINDOW SORT操作)。 GROUP BY 方法避免了 可以使用 HASH GROUP BY 排序,这可以带来更好的性能。

你的例子有点复杂,因为你不使用 table 而是一个连接三个 table 的视图 - 这个连接执行了两次,对于 GROUP BY 和对于详细数据;哪个 当然不是最优的。

所以我将从查询的解析函数版本开始(可能带有 PARALLEL 选项)。

如果你想尝试 GROUP BY lightway 版本是可能的:

1) 仅对重复的键进行分组

2) 使OUTER JOIN赋值给MULTI_FLAG

下面的执行计划示例 - 使用您的数据进行简单测试

with dups as (
select firstname,lastname  from tmp
group by firstname,lastname
having count(*) > 1)
select tmp.FIRSTNAME, tmp.LASTNAME, tmp.MARK,
case when dups.firstname is not NULL then 1 else 0 end as MULTI_FLAG
from tmp
left outer join dups on tmp.firstname = dups.firstname and tmp.lastname = dups.lastname;

您仍然需要访问您的视图两次,但最终连接会更快(尤其是如果您只有少量重复键)。

--------------------------------------------------------------------------------------
| Id  | Operation             | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |      |   105K|    26M|       |  1673   (1)| 00:00:21 |
|*  1 |  HASH JOIN RIGHT OUTER|      |   105K|    26M|    11M|  1673   (1)| 00:00:21 |
|   2 |   VIEW                |      |   105K|    10M|       |   128   (4)| 00:00:02 |
|*  3 |    FILTER             |      |       |       |       |            |          |
|   4 |     HASH GROUP BY     |      |   105K|    10M|       |   128   (4)| 00:00:02 |
|   5 |      TABLE ACCESS FULL| TMP  |   105K|    10M|       |   125   (1)| 00:00:02 |
|   6 |   TABLE ACCESS FULL   | TMP  |   105K|    15M|       |   125   (1)| 00:00:02 |
--------------------------------------------------------------------------------------