【问题标题】:Oracle- performing view- creating index on join tableOracle-在连接表上执行视图创建索引
【发布时间】:2020-10-15 14:27:05
【问题描述】:

我需要执行这个视图:

  SELECT BMITEMCART, BMITEMXDSC, BMITEMCSTATO, 
  CASE 
  WHEN SCRECEXCONF = '2'  THEN 'CONFORME'
  WHEN SCRECEXCONF = '3'  THEN 'NON CONFORME'
  WHEN SCRECEXCONF = '4'  THEN 'PRESUNTO CONFORME'
  WHEN SCRECEXCONF = '5'  THEN 'NON APPLICABILE'
  ELSE '???????'
  END AS CERTIF
, BMITEMCTIPART
FROM PROD.BMITEM
LEFT OUTER JOIN PROD.SCRECE
             ON SCRECECCODART  = BMITEMCART AND
                SCRECENIDCERT  = 8          AND
                SCRECETFINE   IS NULL       AND
                SCRECEDFNVAL  IS NULL;

我读到在连接表上创建索引会有所帮助。 我应该如何在连接表 SCRECE 上创建索引?我应该在 SCRECECCODART 列上创建一个索引,在 SCRECENIDCERT 列上创建一个索引,在 SCRECETFINE 列上创建一个索引,在 SCRECEDFNVAL 列上创建一个索引,还是其他什么?

提前谢谢你。

【问题讨论】:

  • 这取决于列中不同值的数量及其用法。您可以在具有较少不同值的列上创建 BITMAP 索引,您可以在其他列组合上创建 B-Tree 索引。
  • 请注意,根据您提供的信息几乎没有可以推荐。您必须至少将 alias 添加到我们可以看到源表的连接谓词中的列。连接两侧的行数也是相关的。如需进一步建议,请参阅here,需要什么信息。
  • 这条建议@Tejash 应该总是伴随着“永远不要在大量更新的表上使用 BITMAP 索引!”的警告

标签: oracle performance indexing view


【解决方案1】:

你应该接受那些一般性的建议索引是好的,全表扫描是不好的!要小心。

它总是取决于使用的上下文。

我重新编写您的示例,删除不相关的部分并使用中性列名

我还添加了 alias 来限定列,因此可以清楚地从哪个表中获取列。

SELECT a.id, a.col1, a.col2, a.col3,
       b.col4
FROM a
LEFT OUTER JOIN b
             ON a.id  = b.fk_id AND
                b.col1 = 8 AND
                b.col2 IS NULL  AND
                b.col3 IS NULL 
            

请注意,在连接中,您选择表 A 中的所有行 - 这意味着 没有用于访问表 A 的索引会有所帮助。您必须全面扫描表并处理所有行。

您将看到 HASH JOIN 作为已使用的连接操作,如果您连接大型数据集,这是首选选项。

查看here如何获取查询的执行计划。

------------------------------------------------------------------------------
| Id  | Operation             | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |      | 10000 |  1044K|    25   (4)| 00:00:01 |
|*  1 |  HASH JOIN RIGHT OUTER|      | 10000 |  1044K|    25   (4)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL   | B    |     2 |   110 |    16   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL   | A    | 10000 |   507K|     8   (0)| 00:00:01 |
------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - access("A"."ID"="B"."FK_ID"(+))
   2 - filter("B"."COL3"(+) IS NULL AND "B"."COL2"(+) IS NULL AND 
              "B"."COL1"(+)=8)
          
          

如果您将表 A 中已处理的行限制为一个非常小的数字,例如使用带有附加 WHERE 条件的相同查询,则会出现不同的情况。

您将使用 嵌套循环 连接和索引访问来仅获取所需的行。

SELECT a.id, a.col1, a.col2, a.col3,
       b.col4
FROM a
LEFT OUTER JOIN b
             ON a.id  = b.fk_id AND
                b.col1 = 8 AND
                b.col2 IS NULL  AND
                b.col3 IS NULL 
where a.id = 8   --<<<< here you select only a few rows

现在您可以从定义索引中获利

  • 使用WHERE 谓词访问表A
  • 使用join 列访问表B

在我们的例子中是

create index a_idx on a (id);
create index b_idx on b (fk_id,col1, col2, col3);

您应该期望的执行计划将是嵌套循环外部连接

--------------------------------------------------------------------------------------
| Id  | Operation                    | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |       |     2 |   214 |     4   (0)| 00:00:01 |
|   1 |  NESTED LOOPS OUTER          |       |     2 |   214 |     4   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| A     |     1 |    52 |     2   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | A_IDX |     1 |       |     1   (0)| 00:00:01 |
|   4 |   TABLE ACCESS BY INDEX ROWID| B     |     2 |   110 |     2   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN          | B_IDX |     1 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   3 - access("A"."ID"=8)
   5 - access("B"."FK_ID"(+)=8 AND "B"."COL1"(+)=8 AND "B"."COL2"(+) IS NULL 
              AND "B"."COL3"(+) IS NULL)
       filter("B"."COL3"(+) IS NULL)   

                 

【讨论】:

  • 亲爱的 Marmite,非常感谢您的回答。澄清一下:在您在答案中编写的第一个查询(没有 where 子句的查询)中,在 b (fk_id,col1, col2, col3) 上创建索引 b_idx 是没有用的,不是吗?
  • 是的,如果您需要从表中选择所有数据,完整扫描索引访问更好。
猜你喜欢
  • 2015-08-11
  • 2011-10-23
  • 1970-01-01
  • 1970-01-01
  • 2020-06-02
  • 2023-03-16
  • 2017-11-03
  • 2011-08-13
  • 1970-01-01
相关资源
最近更新 更多