2

我有一个这样的查询...

SELECT cust_num, year,credit_cust FROM
(SELECT cust_num, year,credit_cust,
ROW_NUMBER () OVER(PARTITION BY cust_num, year ORDER BY credit_cust DESC) rnk
FROM credit_cust PARTITION (YEAR_2010)
)
WHERE rnk=1

执行此查询时,托管数据库的服务器的 CPU 使用率至少增加 35%。当 CPU 使用率有时会达到 100% 时,这确实涉及服务器负载高的情况。

要求:

数据如下...

Cust_num  Year    Credit_cust
  456     2010       Y
  456     2010       N
  456     2009       N
  456     2009       N

我希望查询只返回下面给出的记录......

Cust_num  Year    Credit_cust
  456     2010       Y
  456     2009       N

注意:我使用 ROW_NUMBER() 作为 GROUP BY 子句的解决方法。如前所述,我认为它只是导致 CPU 使用率高的 GROUP BY 子句

备用查询:(CPU 使用率也超过 35%)

SELECT   cust_num, YEAR, MAX (credit_cust)
    FROM credit_cust PARTITION (year_2010)
GROUP BY cust_num, YEAR


Server : Sun OS 5.10
Database : Oracle 11g (11.2.0.2.0 -64bit)

表结构credit_cust如下...

CREATE TABLE CREDIT_CUST
(
  CUST_NUM          NUMBER,
  YEAR     NUMBER,
  CREDIT_CUST  CHAR(1)
)
TABLESPACE PARTITION_01
PARTITION BY RANGE (YEAR) 
SUBPARTITION BY HASH (CUST_NUM)
(  
  PARTITION YEAR_2009 VALUES LESS THAN (2010)
    SUBPARTITIONS 16 STORE IN (PARTITION_01,PARTITION_02,PARTITION_03,PARTITION_04,PARTITION_05,PARTITION_06,
                               PARTITION_01,PARTITION_02,PARTITION_03,PARTITION_04,PARTITION_05,PARTITION_06,
                               PARTITION_01,PARTITION_02,PARTITION_03,PARTITION_04),  
  PARTITION YEAR_2010 VALUES LESS THAN (2011)
    SUBPARTITIONS 1 STORE IN (PARTITION_01))
PARALLEL ( DEGREE 16 INSTANCES 1 );

请告诉我为什么会出现这个问题。让我知道是否需要更多详细信息。

解释计划:

PLAN_TABLE_OUTPUT

Plan hash value: 3927595547

----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                           | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |    TQ  |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                                |    29M|  1179M|       |  3937   (3)| 00:00:01 |       |       |        |      |            |
|   1 |  PX COORDINATOR                |                                |       |       |       |            |          |       |       |        |      |            |
|   2 |   PX SEND QC (RANDOM)          | :TQ10001                       |    29M|  1179M|       |  3937   (3)| 00:00:01 |       |       |  Q1,01 | P->S | QC (RAND)  |
|*  3 |    VIEW                        |                                |    29M|  1179M|       |  3937   (3)| 00:00:01 |       |       |  Q1,01 | PCWP |            |
|*  4 |     WINDOW SORT PUSHED RANK    |                                |    29M|   364M|   674M|  3937   (3)| 00:00:01 |       |       |  Q1,01 | PCWP |            |
|   5 |      PX RECEIVE                |                                |    29M|   364M|       |  3937   (3)| 00:00:01 |       |       |  Q1,01 | PCWP |            |
|   6 |       PX SEND HASH             | :TQ10000                       |    29M|   364M|       |  3937   (3)| 00:00:01 |       |       |  Q1,00 | P->P | HASH       |
|*  7 |        WINDOW CHILD PUSHED RANK|                                |    29M|   364M|       |  3937   (3)| 00:00:01 |       |       |  Q1,00 | PCWP |            |
|   8 |         PX BLOCK ITERATOR      |                                |    29M|   364M|       |    34   (3)| 00:00:01 |     1 |     1 |  Q1,00 | PCWC |            |
|*  9 |          TABLE ACCESS FULL     | CREDIT_CUST                    |    29M|   364M|       |    34   (3)| 00:00:01 |   228 |   228 |  Q1,00 | PCWP |            |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------

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

   3 - filter("RNK"=1)
   4 - filter(ROW_NUMBER() OVER ( PARTITION BY "CUST_NUM","YEAR" ORDER BY INTERNAL_FUNCTION("CREDIT_CUST") DESC )<=1)
   7 - filter(ROW_NUMBER() OVER ( PARTITION BY "CUST_NUM","YEAR" ORDER BY INTERNAL_FUNCTION("CREDIT_CUST") DESC )<=1)
   9 - filter("YEAR"=2010)

Note
-----
   - dynamic sampling used for this statement (level=5)
4

2 回答 2

1

由于并行性,此查询使用大量 CPU。该表设置为DEGREE 16。默认情况下,您的查询将使用 16 或 32 个并行服务器,具体取决于它们是否正在排序。

分区选项和查询执行计划在这里没有直接关系。即使它们不正确,“坏”查询通常也不会每秒消耗大量资源。

有许多可能的解决方案,具体取决于您要禁用并行性的级别。以下是一些常见的解决方案:

  1. 声明级别/*+ no_parallel(credit_cust) */
  2. 会话级别alter session disable parallel query;
  3. 对象级别alter table cust parallel 1;
  4. 系统级alter system set parallel_max_servers = 0;

但是在你改变任何东西之前要仔细考虑。如果使用不当,其中一些解决方案可能是灾难性的。您需要很好地了解并行性、系统资源以及系统的使用方式。像往常一样,一个好的起点是手册

于 2013-01-23T06:06:03.530 回答
1

我有两个建议:

  1. 正确分区表。您有一个分区子分区和另一个不分区(单个子分区)。一个分区中的年数并不明显。我将按年使用年度分区,并按 cust 上的哈希使用子分区(每个分区 8 或 16 个子分区。如果表很大并且您有很多处理器,则为 16。)

  2. 您的查询将返回 2007 年、2008 年、2009 年、2010 年客户的结果。您确定要四年吗?如果你只想要 2010,你应该year = 2010where子句中指定,并且不需要在 analitic 函数中按年份分区,这有助于排序(消耗 CPU 和 TEMP 空间)。

查询就像:

SELECT cust_num, year,credit_cust 
FROM
  (SELECT cust_num, year,credit_cust,
   ROW_NUMBER () OVER(PARTITION BY cust_num ORDER BY credit_cust DESC) rnk
   FROM credit_cust
   WHERE YEAR=2010
   )
WHERE rnk=1;

一般来说,最好选择带有 where 子句的分区而不是指定分区名称(也更容易)

于 2013-01-22T13:19:59.660 回答