我目前正在部署基于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的EXPLAIN PLAN是:
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
********************************************************************************
所以看来问题是'db file scattered read',如何调整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
********************************************************************************
答案 0 :(得分: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使用它们。甲骨文对指数非常挑剔。根据最重要的查询选择索引时,您可以获得最佳结果。如果有疑问,trace a query。通过这种方式,您可以看到oracle查询的哪个部分花费的时间最多,以及您的索引是否实际被拾取。在解决性能问题时,跟踪是非常宝贵的。
答案 1 :(得分:1)
使用PRIMARY KEY约束将ORDER_ID声明为PK吗?因为如果是这样的话,我希望优化者能够认识到DISTINCT在这个查询中是多余的,并将其优化出来。如果没有这种限制,它就不会知道它是多余的,因此将在“重复删除”结果方面花费不必要的大量努力。
答案 2 :(得分:1)
如果两个查询之间的差异很大,那就太令人惊讶了。您提到没有DISTINCT的查询大约需要30秒。使用DISTINCT的查询需要多长时间?
在使用“alter session set events'10046跟踪名称上下文永远,级别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')
此致 罗布。
答案 3 :(得分:1)
尝试禁用哈希聚合:
select /*+ no_use_hash_aggregation*/ distinct ...
http://oracle-randolf.blogspot.com/2011/01/hash-aggregation.html
答案 4 :(得分: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语句中对提示进行编码,如果应用程序在语句中生成文字值而不是绑定变量,那么还可以选择执行模糊匹配。
当然,这个工具不应该替代理解应用程序及其数据结构,但是阅读详细说明更好计划(如果找到)的执行路径的输出可能具有教育意义。
答案 5 :(得分:-1)
每次运行查询时,Oracle都在访问整个表(TABLE ACCESS(FULL))。 在STATUS_ID和ORDER_TYPE_ID列上创建INDEX
CREATE INDEX ERP.ORDER_HEADER_I1 ON ERP.ORDER_HEADER ( STATUS_ID, ORDER_TYPE_ID );
会有很多帮助,特别是如果ORDER_HEADER表中有几个不同的STATUS_ID和ORDER_TYPE_ID值。