【问题标题】:SQL Why don't use PK index?SQL 为什么不用PK索引?
【发布时间】:2016-07-28 14:47:06
【问题描述】:

我有这个复杂的 SQL 查询:

  SELECT f1 (d1.prdecdde),
         f2 (d1.prdecdde),
         f3 (d1.prdecdde),
         f4 (1, d1.prdecdde, d1.prdenpol),
         d1.prdeisin,
         f6 (d1.prdecdde, a.POLIRCTB),
         NVL (a.poliagtb, a.poliagta),
         d1.prdedtpr,
         prdeticu
    FROM (  SELECT prdecdde,
                   prdenpol,
                   prdeano,
                   SUM (NVL (prdeval, 0)) valantes,
                   NULL valdepois,
                   prdedtpr,
                   prdeticu,
                   prdeisin
              FROM stat_pro_det
             WHERE     prdedprv = '20151101'
                   AND prdecdde IN (700,
                                    100,
                                    610,
                                    600,
                                    710,
                                    900,
                                    910)
                   AND prdeval > 0
          GROUP BY prdecdde,
                   prdenpol,
                   prdeano,
                   prdedtpr,
                   prdeticu,
                   prdeisin
          UNION ALL
            SELECT prdecdde,
                   prdenpol,
                   prdeano,
                   NULL,
                   SUM (NVL (prdeval, 0)) valdepois,
                   prdedtpr,
                   prdeticu,
                   prdeisin
              FROM stat_pro_det
             WHERE     prdedprv = '20160727'
                   AND prdecdde IN (700,
                                    100,
                                    610,
                                    600,
                                    710,
                                    900,
                                    910)
                   AND prdeval > 0
          GROUP BY prdecdde,
                   prdenpol,
                   prdeano,
                   prdedtpr,
                   prdeticu,
                   prdeisin) d1,
         sgss.dtpoli a
   WHERE a.policdde = d1.prdecdde AND a.polinpol = d1.prdenpol
  HAVING SUM (NVL (d1.valdepois, 0) - NVL (d1.valantes, 0)) <> 0
GROUP BY d1.prdecdde,
         d1.prdenpol,
         d1.prdeano,
         a.polirctb,
         a.poliagta,
         a.poliagtb,
         d1.prdedtpr,
         d1.prdeticu,
         d1.prdeisin;

dtpoli 表的主键是这样的:

CREATE UNIQUE INDEX SGSS.PK_DTPOLI ON SGSS.DTPOLI
(POLICDDE, POLINPOL)

这里是解释计划:

Plan hash value: 1960385779

--------------------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name            | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |                 | 19403 |  1705K|       |   113K  (1)| 00:00:05 |
|*  1 |  FILTER                            |                 |       |       |       |            |          |
|   2 |   HASH GROUP BY                    |                 | 19403 |  1705K|    38M|   113K  (1)| 00:00:05 |
|*  3 |    HASH JOIN                       |                 |   388K|    33M|    23M|   111K  (1)| 00:00:05 |
|   4 |     TABLE ACCESS FULL              | DTPOLI          |   618K|    16M|       |  6561   (7)| 00:00:01 |
|   5 |     VIEW                           |                 |   388K|    22M|       |   103K  (1)| 00:00:05 |
|   6 |      UNION-ALL                     |                 |       |       |       |            |          |
|   7 |       HASH GROUP BY                |                 |   194K|  9304K|    13M| 52044   (1)| 00:00:03 |
|   8 |        INLIST ITERATOR             |                 |       |       |       |            |          |
|*  9 |         TABLE ACCESS BY INDEX ROWID| STAT_PRO_DET    |   194K|  9304K|       | 50003   (1)| 00:00:02 |
|* 10 |          INDEX RANGE SCAN          | STAT_PRO_DET_03 |   198K|       |       |   790   (2)| 00:00:01 |
|  11 |       HASH GROUP BY                |                 |   193K|  9264K|    13M| 51818   (1)| 00:00:03 |
|  12 |        INLIST ITERATOR             |                 |       |       |       |            |          |
|* 13 |         TABLE ACCESS BY INDEX ROWID| STAT_PRO_DET    |   193K|  9264K|       | 49784   (1)| 00:00:02 |
|* 14 |          INDEX RANGE SCAN          | STAT_PRO_DET_03 |   197K|       |       |   783   (2)| 00:00:01 |
--------------------------------------------------------------------------------------------------------------

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

   1 - filter(SUM(NVL("D1"."VALDEPOIS",0)-NVL("D1"."VALANTES",0))<>0)
   3 - access("POLICDDE"="D1"."PRDECDDE" AND "POLINPOL"="D1"."PRDENPOL")
   9 - filter("PRDEVAL">0)
  10 - access("PRDEDPRV"='20151101' AND ("PRDECDDE"=100 OR "PRDECDDE"=600 OR "PRDECDDE"=610 OR 
              "PRDECDDE"=700 OR "PRDECDDE"=710 OR "PRDECDDE"=900 OR "PRDECDDE"=910))
  13 - filter("PRDEVAL">0)
  14 - access("PRDEDPRV"='20160727' AND ("PRDECDDE"=100 OR "PRDECDDE"=600 OR "PRDECDDE"=610 OR 
              "PRDECDDE"=700 OR "PRDECDDE"=710 OR "PRDECDDE"=900 OR "PRDECDDE"=910))

两列都是数字数据类型。使用提示 parallel(#) 我可以提高性能,但我的重点是 dtpoli PK

我找不到为什么这个查询不使用这个主键索引,而是对 DTPOLI 表使用全表扫描。是因为我有一个Group by 子句吗?我真的不明白。 有什么帮助吗? 我正在使用 Oracle 11gR2。

【问题讨论】:

  • 和表定义(可能类型不匹配)
  • 好像@sstan 提到的逻辑处理顺序错误。这会阻止这个查询工作
  • @sstan 更改 have 子句的顺序不会导致任何不同的效果。 DTPOLI 和 STAT_PRO_DET 表的两列具有相同的数据类型:Number。
  • dtpoli 中实际有多少行?该计划建议优化器认为有 618K 和超过一半(388K)将被连接匹配;所以使用索引的效率会低得多。如果您认为这些数字有误,您的统计数据是最新的吗?
  • 然后在索引中查找每一行,然后获取其匹配数据(例如poliagtb),这只会增加更多开销 - 您必须为每个匹配的行敲击磁盘两次,并且以分散的方式,而不是单个连续读取(简化一点!)全表扫描。只有从表中检索少量数据时,索引才会更有效率。

标签: sql oracle indexing


【解决方案1】:

它不使用索引,因为这样做会不太有效。如果您要从表中检索一小部分数据,则索引很有用,但是当您获取大量数据时,使用索引会更慢。

原因是在索引中找到匹配的行需要磁盘访问,才能获得索引块。这为您提供了数据记录的 ROWID,然后您需要另一个磁盘访问权限来获取该数据块。每个索引和数据块必须至少被读取一次,并且可能多次。

这些块可能在缓冲区缓存中,但您仍然会遇到两次,并且因为您会跳到索引和表的不同部分,所以您增加了事物老化的可能性 - 这这意味着即使您最终从同一个物理数据块中获取两行,您最终也可能不得不从磁盘读取两次。

全表扫描将一次性检索表的所有数据块,因此它不必读取其中任何一个两次,也没有读取索引块的额外开销。

如果您引用主键(或任何其他索引)中的列,则可能会使用全索引扫描。但是您检索的是非索引数据,例如poliagtb,因此也必须检索数据块。

您的主键正在执行参照完整性。它也可用于快速检索特定数据,但仅限于适当时。优化器在决定什么时候合适和不合适方面做得很好。

【讨论】:

  • 很好的解释!谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-20
  • 2010-10-28
  • 2013-07-25
  • 1970-01-01
  • 2011-10-19
  • 2020-03-12
  • 1970-01-01
相关资源
最近更新 更多