كيفية تحسين الأداء في أوراكل باستخدام SELECT DISTINCT

StackOverflow https://stackoverflow.com/questions/1051593

  •  20-08-2019
  •  | 
  •  

سؤال

وأنا أعمل حاليا في نشر نظام تخطيط موارد المؤسسات أوفبيز مقرها قاعدة البيانات المستخدمة هي أوراكل 10g المؤسسة

واحدة من أكبر القضايا هي بعض مشاكل الأداء أوراكل، وتحليل سجلات أوفبيز، الاستعلام التالي:

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 وتقريبا في كل ميدان آخر

ووشرح خطة مع 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

وأية أفكار حول أوراكل ضبط لتحسين أداء هذا النوع من الأسئلة؟ من الصعب جدا إعادة كتابة الاستعلام ليتم إنشاؤها تلقائيا من قبل أوفبيز لذلك أعتقد أن الحل هو حول أوراكل ضبط

وشكرا مقدما

وتحرير: I تحليل الاستعلام باستخدام tkprof، على النحو الذي اقترحه روب فان 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
********************************************************************************

وهكذا يبدو أن المشكلة تكمن في "ملف ديسيبل مبعثرة قراءة '، أي أفكار لكيفية ضبط أوراكل من أجل الحد من الانتظار في هذا الحدث؟

ومتابعة مع نتيجة 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
********************************************************************************
هل كانت مفيدة؟

المحلول

وإذا كان الفرق بين الاستعلامات اثنين لا يستهان به، من شأنه أن يكون من المستغرب. أذكر لكم أن الاستعلام دون DISTINCT يستغرق حوالي 30 ثانية. وكم من الوقت الذي الاستعلام مع DISTINCT تأخذ؟

هل تظهر لك إخراج tkprof الاستعلام مع DISTINCT، بعد تتبع الدورة مع "تغيير" 10046 أثر السياق اسم إلى الأبد، ومستوى 8 "جلسة مجموعة الأحداث"، وقطع بعد انتهاء الاستعلام؟ وبهذه الطريقة يمكننا أن نرى أين هو في الواقع تنفق الوقت وإذا كان ينتظر شيئا ( "مسار مباشر قراءة مؤقت" ربما؟)

والتحيات، روب.


والمتابعة، بعد أن تم نشر الملف tkprof:

وأرى أنك تمكنت من الحصول على إخراج tkprof، ولكن للأسف لم تقم بفصل جلسة العمل الخاصة بك قبل إنشاء ملف tkprof. الآن، وقد ترك المؤشر مفتوحا وأنه فشل في إرسال STAT # الأسطر إلى ملف التتبع الخاص بك. هذا هو السبب في أنك لم يكن لديك عملية مصدر خطة / صف في ملف tkprof الخاص بك. وسيكون لطيفا إذا كان يمكنك تكرار هذه العملية، إذا كان اقتراح يتحول أدناه إلى أن تكون القمامة.

وهناك تكهنات القليل من جانبي: أعتقد أن DISTINCT يكاد يكون عدم المرجع لأنك اختيار العديد من الأعمدة. إذا كان هذا صحيحا، ثم المسند الخاص بك "حيث STATUS_ID = 'ORDER_COMPLETED" انتقائي جدا، وسوف تستفيد من وجود فهرس على هذا العمود. بعد إنشاء الفهرس، تأكد من تحليلها بشكل صحيح، وربما حتى مع الرسم البياني على إذا قيم البيانات هي منحرفة. وستكون النتيجة النهائية ستكون خطة مختلفة لهذا الاستعلام، بدءا من SCAN INDEX RANGE، تليها ACCESS TABLE BY ROWID، مما يؤدي إلى استعلام سريع جدا.

وبعد إنشاء فهرس، هل يمكن أن يكون الجدول تحليل إعادة، بما في ذلك رسوم بيانية باستخدام هذا البيان:

وdbms_stats.gather_table_stats إكسيك ([مالك]، [TABLE_NAME]، سلسلة => صحيح، method_opt => 'FOR ALL SIZE INDEXED الأعمدة')

والتحيات، روب.

نصائح أخرى

ومنذ كنت أمر النتائج وفقا لorder_date من المهم أن يكون لديك مؤشر الهابطة على هذا المجال. أقول أيضا أوراكل التي ترغب في استخدام هذا المؤشر. وضع الحقل order_date أولا في الاستعلام واستخدام تلميح مثل

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

ووليس كثيرا عن وجود مؤشرات، وإنما على وشك قول أوراكل لاستخدامها. أوراكل هي من الصعب إرضاءه جدا عن المؤشرات. يمكنك الحصول على أفضل النتائج عند اختيار المؤشرات وفقا لطلبات البحث الأكثر أهمية. إذا كنت في شك، تتبع استعلام . بهذه الطريقة يمكنك أن ترى في أي جزء من أوراكل الاستعلام تنفق معظم وقتهم وعما إذا كان لديك مؤشرات يتم اختيار فعليا حتى أم لا. للبحث عن المفقودين لا تقدر بثمن عندما تقاتل مشاكل الأداء.

هل أعلن ORDER_ID كما PK باستخدام KEY القيد الأولية؟ لأنه إذا أتوقع محسن إلى الاعتراف بأن DISTINCT لا لزوم له في هذا الاستعلام وتحسين ذلك. بدون القيد، فإنه لن أعلم أنه لا لزوم له وهكذا سوف تنفق جهد لا لزوم لها وكبير في "إزالة الإدخالات المكررة" النتائج.

ومحاولة لتعطيل التجزئة التجميع:

select /*+ no_use_hash_aggregation*/ distinct ...

http://oracle-randolf.blogspot.com/2011/ 01 / التجزئة-aggregation.html

عند استكشاف التطبيقات حيث لا أملك السيطرة على SQL أجد أن حزمة dbms_sqltune يوفر الكثير من الوقت. انظر http://download.oracle.com/docs /cd/B28359_01/appdev.111/b28419/d_sqltun.htm ، ونعم، للأسف يجب أن تكون مرخصة لاستخدامها.

وهناك إجراءات في هذه الحزمة لتشغيل تحليل ضبط ضد sql_id محددة في مجموعة مشتركة أو مستودع AWR. سيحتوي تحليل توصيات الفهرسة إذا كان هناك أي تحسينات ليكون مع فهارس إضافية. الأهم من ذلك، محلل قد يكتشف مسار وصول محسن أنه يمكن تنفيذ مع ما يدعو أوراكل الملف SQL - وهذا هو عبارة عن مجموعة من التلميحات التي سيتم تخزينها واستخدامها كلما يتم تنفيذ هذا sql_id. يحدث هذا دون الحاجة إلى تلميحات أن تكون مشفرة في بيان SQL، وهناك أيضا خيار لتفعل ما يمكن ان يخطر لك مطابقة كما غامض إذا كان التطبيق يولد القيم الحرفية في البيان بدلا من المتغيرات مأزق.

وبالطبع يجب أن لا تكون هذه الأداة بديلا لفهم تطبيق وانها هياكل البيانات، ولكن القراءة من خلال الإخراج الذي يفصل مسار تنفيذ خطة أفضل (إن وجدت) يمكن أن يكون التعليمية.

وأوراكل يتم الوصول إلى جدول كامل في كل مرة تقوم فيها بتشغيل الاستعلام (الجدول ACCESS (FULL)). إنشاء INDEX على الأعمدة STATUS_ID وORDER_TYPE_ID

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

وسوف يساعد كثيرا، خاصة إذا كان هناك عدة قيم مختلفة من STATUS_ID وORDER_TYPE_ID في الجدول ORDER_HEADER.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top