4

我目前正在部署基于 OFBiz 的 ERP 正在使用的数据库是 Oracle 10g Enterprise

最大的问题之一是一些oracle性能问题,分析ofbiz日志,如下查询:

SELECT DISTINCT ORDER_ID, ORDER_TYPE_ID, ORDER_NAME, EXTERNAL_ID,
 SALES_CHANNEL_ENUM_ID, ORDER_DATE, ENTRY_DATE, VISIT_ID, STATUS_ID, CREATED_BY, 
 FIRST_ATTEMPT_ORDER_ID, CURRENCY_UOM, SYNC_STATUS_ID, BILLING_ACCOUNT_ID, 
 ORIGIN_FACILITY_ID, WEB_SITE_ID, PRODUCT_STORE_ID, TERMINAL_ID, TRANSACTION_ID, 
 AUTO_ORDER_SHOPPING_LIST_ID, NEEDS_INVENTORY_ISSUANCE, IS_RUSH_ORDER, INTERNAL_CODE, 
 REMAINING_SUB_TOTAL, GRAND_TOTAL, LAST_UPDATED_STAMP, LAST_UPDATED_TX_STAMP, CREATED_STAMP, 
CREATED_TX_STAMP, RECIBIR_BODEGAL, RECEPCIONADA_BODEGAL, FECHA_RECEPCION_BODEGAL FROM 
ERP.ORDER_HEADER WHERE ((STATUS_ID = :v0 OR STATUS_ID = :v1 OR STATUS_ID = :v2) AND 
(ORDER_TYPE_ID = :v3)) ORDER BY ORDER_DATE DESC

很慢。我们已经测试了在没有 DISTINCT 的情况下执行查询,大约需要 30 秒。表中有 4.000.000 多个寄存器。PK 字段 orderId 和几乎所有其他字段都有索引

带有 DISTINCT 的解释计划是:

SELECT STATEMENT () (null)
 SORT (ORDER BY)    (null)
  HASH (UNIQUE) (null)
   TABLE ACCESS (FULL)  ORDER_HEADER

并且没有 DISTINCT 是:

SELECT STATEMENT () (null)
 SORT (ORDER BY)    (null)
  TABLE ACCESS (FULL)   ORDER_HEADER

关于调整 oracle 以提高此类查询的性能的任何想法?重写查询非常困难,因为它是由ofbiz自动生成的,所以我认为解决方案是关于调整oracle

提前致谢

编辑:我使用 tkprof 分析了查询,正如 Rob van Wijk 和 haffax 所建议的那样,结果如下

********************************************************************************

SELECT DISTINCT ORDER_ID, ORDER_TYPE_ID, ORDER_NAME, EXTERNAL_ID,
 SALES_CHANNEL_ENUM_ID, ORDER_DATE, ENTRY_DATE, VISIT_ID, STATUS_ID, CREATED_BY, 
 FIRST_ATTEMPT_ORDER_ID, CURRENCY_UOM, SYNC_STATUS_ID, BILLING_ACCOUNT_ID, 
 ORIGIN_FACILITY_ID, WEB_SITE_ID, PRODUCT_STORE_ID, TERMINAL_ID, TRANSACTION_ID, 
 AUTO_ORDER_SHOPPING_LIST_ID, NEEDS_INVENTORY_ISSUANCE, IS_RUSH_ORDER, INTERNAL_CODE, 
 REMAINING_SUB_TOTAL, GRAND_TOTAL, LAST_UPDATED_STAMP, LAST_UPDATED_TX_STAMP, CREATED_STAMP, 
CREATED_TX_STAMP, RECIBIR_BODEGAL, RECEPCIONADA_BODEGAL, FECHA_RECEPCION_BODEGAL FROM 
ERP.ORDER_HEADER WHERE STATUS_ID = 'ORDER_COMPLETED' ORDER BY ORDER_DATE DESC

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.03       0.01          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      9.10     160.81      66729      65203         37          50
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      9.14     160.83      66729      65203         37          50

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 58  

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  db file scattered read                       8178        0.28        146.55
  direct path write temp                       2200        0.04          4.22
  direct path read temp                          36        0.14          2.01
  SQL*Net more data to client                     3        0.00          0.00
  SQL*Net message from client                     1        3.36          3.36
********************************************************************************

所以看来问题是“数据库文件分散读取”,关于如何调整 oracle 以减少此事件中的等待的任何想法?

跟进新的 tkprof 结果,这次关闭会话:

********************************************************************************

SELECT DISTINCT ORDER_ID, ORDER_TYPE_ID, ORDER_NAME, EXTERNAL_ID,
 SALES_CHANNEL_ENUM_ID, ORDER_DATE, ENTRY_DATE, VISIT_ID, STATUS_ID, CREATED_BY,
 FIRST_ATTEMPT_ORDER_ID, CURRENCY_UOM, SYNC_STATUS_ID, BILLING_ACCOUNT_ID,
 ORIGIN_FACILITY_ID, WEB_SITE_ID, PRODUCT_STORE_ID, TERMINAL_ID, TRANSACTION_ID,
 AUTO_ORDER_SHOPPING_LIST_ID, NEEDS_INVENTORY_ISSUANCE, IS_RUSH_ORDER, INTERNAL_CODE,
 REMAINING_SUB_TOTAL, GRAND_TOTAL, LAST_UPDATED_STAMP, LAST_UPDATED_TX_STAMP, CREATED_STAMP,
CREATED_TX_STAMP, RECIBIR_BODEGAL, RECEPCIONADA_BODEGAL, FECHA_RECEPCION_BODEGAL FROM
ERP.ORDER_HEADER WHERE STATUS_ID = 'ORDER_COMPLETED' ORDER BY ORDER_DATE DESC

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.03       0.01          0          0          0           0
Execute      2      0.00       0.00          0          0          0           0
Fetch        1      8.23      47.66      66576      65203         31          50
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      8.26      47.68      66576      65203         31          50

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 58 

Rows     Row Source Operation
-------  ---------------------------------------------------
     50  SORT ORDER BY (cr=65203 pr=66576 pw=75025 time=47666679 us)
3456659   TABLE ACCESS FULL ORDER_HEADER (cr=65203 pr=65188 pw=0 time=20757300 us)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  db file scattered read                       8179        0.14         34.96
  direct path write temp                       2230        0.00          3.91
  direct path read temp                          52        0.14          0.84
  SQL*Net more data to client                     3        0.00          0.00
  SQL*Net message from client                     1     1510.62       1510.62
********************************************************************************
4

6 回答 6

3

尝试禁用哈希聚合:

select /*+ no_use_hash_aggregation*/ distinct ...

http://oracle-randolf.blogspot.com/2011/01/hash-aggregation.html

于 2012-09-17T04:22:42.297 回答
2

由于您要根据order_date该字段的降序索引对结果进行排序,这一点很重要。还要告诉 oracle 你希望使用这个索引。将order_date字段首先放在查询中并使用类似的提示

SELECT /*+ index(HEADERS IDX_ORDER_DATE_DESC) */ ... 
FROM ERP.ORDER_HEADER HEADERS
WHERE ...
ORDER BY ORDER_DATE DESC

与其说是拥有索引,不如说是告诉 oracle 使用它们。Oracle 对索引非常挑剔。当您根据最重要的查询选择索引时,您将获得最佳结果。如果有疑问,请跟踪查询。通过这种方式,您可以查看查询的哪一部分 Oracle 花费的时间最多,以及您的索引是否实际被拾取。在解决性能问题时,跟踪是无价的。

于 2009-06-26T23:19:47.037 回答
1

ORDER_ID 是否使用 PRIMARY KEY 约束声明为 PK?因为如果是这样,我希望优化器能够认识到 DISTINCT 在此查询中是多余的并对其进行优化。没有约束,它不会知道它是多余的,因此会花费不必要的和相当大的努力来“重复”结果。

于 2009-06-27T12:56:55.987 回答
1

如果这两个查询之间的差异很大,那将是令人惊讶的。您提到没有 DISTINCT 的查询大约需要 30 秒。使用 DISTINCT 查询需要多长时间?

在使用“alter session set events '10046 trace name context forever, level 8'”跟踪会话并在查询完成后断开连接后,您能否使用 DISTINCT 显示查询的 tkprof 输出?通过这种方式,我们可以看到实际花费的时间以及它是否在等待某些东西(也许是“直接路径读取临时”?)

问候,罗布。


后续,在 tkprof 文件发布后:

我看到您设法获得了 tkprof 输出,但不幸的是,您在创建 tkprof 文件之前没有断开会话。现在,光标处于打开状态,并且无法将 STAT# 行写入跟踪文件。这就是为什么您的 tkprof 文件中没有计划/行源操作的原因。如果下面的建议被证明是垃圾,如果您可以重复该过程,那就太好了。

我的一点猜测:我认为 DISTINCT 几乎是无操作的,因为您选择了这么多列。如果这是真的,那么您的谓词“WHERE STATUS_ID = 'ORDER_COMPLETED'”是非常有选择性的,并且您将受益于在该列上建立索引。创建索引后,请确保正确分析它,甚至可能使用直方图显示数据值是否偏斜。最终结果将是此查询的不同计划,从 INDEX RANGE SCAN 开始,然后是 TABLE ACCESS BY ROWID,从而导致非常快速的查询。

创建索引后,您可以使用以下语句重新分析表,包括直方图:

exec dbms_stats.gather_table_stats([owner],[table_name],cascade=>true,method_opt=>'FOR ALL INDEXED COLUMNS SIZE')

问候,罗布。

于 2009-06-27T22:55:42.040 回答
0

在对我无法控制 SQL 的应用程序进行故障排除时,我发现 dbms_sqltune 包可以节省大量时间。请参阅http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28419/d_sqltun.htm,是的,不幸的是,您应该获得使用它的许可。

此包中有一些过程可针对共享池或 AWR 存储库中的特定 sql_id 运行调整分析。如果要对附加索引进行任何改进,分析将包含索引建议。更重要的是,分析器可能会发现一个改进的访问路径,它可以使用 Oracle 所谓的 SQL 配置文件来实现 - 这是一组提示,将在执行此 sql_id 时存储和使用。这种情况不需要在 SQL 语句中编码提示,如果您的应用程序在语句中生成文字值而不是绑定变量,那么还有一个选项可以执行您认为模糊匹配的操作。

当然,此工具不应该替代理解应用程序及其数据结构,但通读详细说明更好计划(如果找到)执行路径的输出可能具有教育意义。

于 2009-06-28T12:37:52.510 回答
-1

每次您运行查询 ( TABLE ACCESS (FULL) ) 时,Oracle 都会访问整个表。在 STATUS_ID 和 ORDER_TYPE_ID 列上创建索引

CREATE INDEX ERP.ORDER_HEADER_I1 ON ERP.ORDER_HEADER ( STATUS_ID, ORDER_TYPE_ID );

会有很大帮助,特别是如果 ORDER_HEADER 表中有几个不同的 STATUS_ID 和 ORDER_TYPE_ID 值。

于 2009-06-27T18:16:43.383 回答