1

我对使用 FULL TABLE SCAN 的查询有疑问。

当这个查询在我们的 UAT 环境中运行时,它使用 TABLE ACCESS BY INDEX ROWID,但在 prod 中它使用 FULL TABLE SCAN。UAT 运行得比 PROD 好得多。

我们在 prod 和 uat 中具有相同的表和索引结构。

我已经尝试重建和重新创建索引,但使用了相同的解释计划。

表和索引静态也进行了更新。

你能帮我让这个查询使用 INDEX 访问而不是 FUll 表访问吗?

请参阅下面我们的产品和 uat 的解释计划。

解释计划产品
==================================================== ====================

SQL> 解释计划
选择 ASV_ODC_BRANCH.CODE、ASV_ODC_BRANCH.DESCRIPTION、ASV_ODC_BRANCH.BRSTN、DEB.VIEW_DORMANT.ACCTNO 作为 DORMANT_ACCT,
DEB.VIEW_DORMANT.SHORTNAME 作为 DORMANT_NAME,DEB.VIEW_DORMANT.OPID_ENTRY,DEB.CUSTOMER.CUSTOMERNO,
DEB.CUSTOMER.TIME_STAMP_ENTRY
FROM ASV_ODC_BRANCH、DEB.VIEW_DORMANT、DEB.CUSTOMER
WHERE trim(ASV_ODC_BRANCH.CODE) = decode(SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 3, 1) || SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 7, 1), '29',
SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 4, 3), SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 3, 3)) 和
DEB.VIEW_DORMANT.ACCTNO = DEB.CUSTOMER.CUSTOMERNO AND (DEB.VIEW_DORMANT.ACCTNO = :Xacct)
ORDER BY ASV_ODC_BRANCH.CODE, DORMANT_ACCT;

解释。


计划表输出 | 身份证 | 操作 | 姓名 | 行 | 字节 | 成本 (%CPU)|
| 0 | 选择声明 | | 3 | 489 | 3601 (2)|
| 1 | 排序方式 | | 3 | 489 | 3601 (2)|
| 2 | 哈希连接 | | 3 | 489 | 3600 (2)|
| 3 | 合并加入笛卡尔| | 1 | 90 | 3595 (2)|
| 4 | 嵌套循环 | | 1 | 66 | 3592 (2)|
| 5 | **表访问已满** | 帐户 | 1 | 56 | 3590 (2)|
| 6 | 按索引 ROWID 访问表| 扩展1 | 1 | 10 | 2 (0)|
| 7 | 索引唯一扫描 | PKEXT10 | 1 | | 1 (0)|
| 8 | 缓冲区排序 | | 1 | 24 | 3593 (2)|
| 9 | 按索引 ROWID 访问表| 客户 | 1 | 24 | 3 (0)|
| 10 | 索引范围扫描 | UXCUST1 | 1 | | 2 (0)|
| 11 | 表访问完全 | ASV_ODC_BRANCH | 第334章 24382 | 5 (0)|                                                                                                                                                                                    

**解释计划 UAT**
==================================================== =====================================

SQL> 解释计划
选择 ASV_ODC_BRANCH.CODE、ASV_ODC_BRANCH.DESCRIPTION、ASV_ODC_BRANCH.BRSTN、DEB.VIEW_DORMANT.ACCTNO 作为 DORMANT_ACCT,
DEB.VIEW_DORMANT.SHORTNAME 作为 DORMANT_NAME,DEB.VIEW_DORMANT.OPID_ENTRY,DEB.CUSTOMER.CUSTOMERNO,
DEB.CUSTOMER.TIME_STAMP_ENTRY
FROM ASV_ODC_BRANCH、DEB.VIEW_DORMANT、DEB.CUSTOMER
WHERE trim(ASV_ODC_BRANCH.CODE) = decode(SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 3, 1) || SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 7, 1), '29',
SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 4, 3), SUBSTR(DEB.VIEW_DORMANT.ACCTNO, 3, 3)) 和
DEB.VIEW_DORMANT.ACCTNO = DEB.CUSTOMER.CUSTOMERNO AND (DEB.VIEW_DORMANT.ACCTNO = :Xacct)
ORDER BY ASV_ODC_BRANCH.CODE, DORMANT_ACCT;

解释。

SQL> /

PLAN_TABLE_OUTPUT

| 身份证 | 操作 | 姓名 | 行 | 字节 | 成本 (%CPU)|
| 0 | 选择声明 | | 5 | 5930 | 19 (11)|
| 1 | 排序方式 | | 5 | 5930 | 19 (11)|
| 2 | 哈希连接 | | 5 | 5930 | 18(6)|
| 3 | 合并加入笛卡尔| | 2 | 2220 | 12 (0)|
| 4 | 嵌套循环 | | 1 | 1085 | 9 (0)|
| 5 | **按索引 ROWID 访问表**| 帐户 | 1 | 57 | 7 (0)|
| 6 | 索引跳过扫描 | UXACCT2 | 1 | | 6 (0)|    
| 7 | 按索引 ROWID 访问表| 扩展1 | 1 | 1028 | 2 (0)|
| 8 | 索引唯一扫描 | PKEXT10 | 1 | | 1 (0)|
| 9 | 缓冲区排序 | | 1 | 25 | 10 (0)|
| 10 | 按索引 ROWID 访问表| 客户 | 1 | 25 | 3 (0)|
| 11 | 索引范围扫描 | UXCUST1 | 1 | | 2 (0)|
| 12 | 表访问完全 | ASV_ODC_BRANCH | 336 | 25536 | 5 (0)|

4

3 回答 3

2

The difference is in

EXPLAIN PLAN PROD

|   5 |      **TABLE ACCESS FULL**      | ACCOUNT        |     1 |    56 |  3590   (2)|

EXPLAIN PLAN UAT

|   5 |  **TABLE ACCESS BY INDEX ROWID**| ACCOUNT        |     1 |    57 |     7   (0)|
|   6 |       INDEX SKIP SCAN           | UXACCT2        |     1 |       |     6   (0)|    

How does it work?

Rather than restricting the search path using a predicate from the statement, Skip Scans are initiated by probing the index for distinct values of the prefix column. Each of these distinct values is then used as a starting point for a regular index search. The result is several separate searches of a single index that, when combined, eliminate the affect of the prefix column. Essentially, the index has been searched from the second level down.

The optimizer uses statistics to decide if a skip scan would be more efficient than a full table scan.

Optimizer considers his as an advantage over a FTS because

  1. It reduces the number of indexes needed to support a range of queries. This increases performance by reducing index maintenance and decreases wasted space associated with multiple indexes.
  2. The prefix column should be the most discriminating and the most widely used in queries. These two conditions do not always go hand in hand which makes the decision difficult. In these situations skip scanning reduces the impact of makeing the "wrong" decision.

You can consider the following

  1. Check the optimizer mode across the environments.
  2. Gather stats on all the tables used in the query. For example, if a table has not been analyzed since it was created, and if it has less than DB_FILE_MULTIBLOCK_READ_COUNT blocks under the high water mark, then the optimizer thinks that the table is small and uses a full table scan. Review the LAST_ANALYZED and BLOCKS columns in the ALL_TABLES table to examine the statistics.
  3. Though your environment is similar and code is same, optimizer is going to check on the fly and choose the best available method. So do your UAT with same data setup. Since it is a UAT (almost a preproduction in most o the companies), it should be the closest to production in terms of size.
于 2014-08-26T11:27:33.490 回答
1

据我所知, tableDEB.VIEW_DORMANT是表ACCOUNT和的视图EXTENSION1,您想使用UXACCT2前者的索引。我想这个请求中的提示应该允许你做你想做的事情,比如:

SELECT /*+ INDEX(D UXACCT2) */ ASV_ODC_BRANCH.CODE,
...
FROM ASV_ODC_BRANCH, DEB.VIEW_DORMANT D, DEB.CUSTOMER
...

PS:如果这是您管理的查询(不是由任何高级软件生成的),我建议您像我一样为您的表使用别名,这使得查询更具可读性......

于 2013-07-03T07:48:41.607 回答
0

我可以帮助您将其设置为 INDEX-ACCESS 而不是 FTS 吗?大概...

你真的想要那个吗?- 可能不是

为什么数据库的行为不同?因为您对不同的数据进行操作 - 正如您的示例所示,查询返回的行数不同,所以我什至不必询问您的生产数据和测试数据是否相同。如果您有不同的数据(索引列中的不同数量或不同值),您的 Database-Stats 将有所不同,您的索引将看起来不同,因此优化器将得出不同的查询计划!

你该怎么办?确保所有索引都是最新的,分区布置合理,所有数据库统计信息都是最新的,并且没有奇怪的调整设置(查询计划,环境设置......)然后优化器在大多数情况下会找到最好的计划 - 在许多情况下,全表扫描是更快的选择。

但是,如果您测量时间并且优化器显然采用了错误的路径,尽管它具有准确的表统计信息,您应该向 oracle 提交错误报告。

如果您有其他原因希望优化器进行索引访问:

如果您无法像 Emmanuel 提供的那样输入 Optimizer-HINT,您可以尝试 Profiles 或 Baselines,它们提供了很好的调整可能性。您可以使用不同的 WHERE-Predicates 编写自己的语句,直到您获得具有索引​​访问的计划并将其用作 SQL 配置文件并将此配置文件链接到原始语句,然后该语句将使用相同的查询计划。

于 2014-08-26T12:46:08.970 回答