سؤال

إليكم إخراج TKPROF لاستعلام يعمل ببطء شديد (تحذير: انه طويل :-) ):

SELECT mbr_comment_idn, mbr_crt_dt, mbr_data_source, mbr_dol_bl_rmo_ind, mbr_dxcg_ctl_member, mbr_employment_start_dt, mbr_employment_term_dt, mbr_entity_active, mbr_ethnicity_idn, mbr_general_health_status_code, mbr_hand_dominant_code, mbr_hgt_feet, mbr_hgt_inches, mbr_highest_edu_level, mbr_insd_addr_idn, mbr_insd_alt_id, mbr_insd_name, mbr_insd_ssn_tin, mbr_is_smoker, mbr_is_vip, mbr_lmbr_first_name, mbr_lmbr_last_name, mbr_marital_status_cd, mbr_mbr_birth_dt, mbr_mbr_death_dt, mbr_mbr_expired, mbr_mbr_first_name, mbr_mbr_gender_cd, mbr_mbr_idn, mbr_mbr_ins_type, mbr_mbr_isreadonly, mbr_mbr_last_name, mbr_mbr_middle_name, mbr_mbr_name, mbr_mbr_status_idn, mbr_mpi_id, mbr_preferred_am_pm, mbr_preferred_time, mbr_prv_innetwork, mbr_rep_addr_idn, mbr_rep_name, mbr_rp_mbr_id, mbr_same_mbr_ins, mbr_special_needs_cd, mbr_timezone, mbr_upd_dt, mbr_user_idn, mbr_wgt, mbr_work_status_idn 
FROM (SELECT /*+ FIRST_ROWS(1) */ mbr_comment_idn, mbr_crt_dt, mbr_data_source, mbr_dol_bl_rmo_ind, mbr_dxcg_ctl_member, mbr_employment_start_dt, mbr_employment_term_dt, mbr_entity_active, mbr_ethnicity_idn, mbr_general_health_status_code, mbr_hand_dominant_code, mbr_hgt_feet, mbr_hgt_inches, mbr_highest_edu_level, mbr_insd_addr_idn, mbr_insd_alt_id, mbr_insd_name, mbr_insd_ssn_tin, mbr_is_smoker, mbr_is_vip, mbr_lmbr_first_name, mbr_lmbr_last_name, mbr_marital_status_cd, mbr_mbr_birth_dt, mbr_mbr_death_dt, mbr_mbr_expired, mbr_mbr_first_name, mbr_mbr_gender_cd, mbr_mbr_idn, mbr_mbr_ins_type, mbr_mbr_isreadonly, mbr_mbr_last_name, mbr_mbr_middle_name, mbr_mbr_name, mbr_mbr_status_idn, mbr_mpi_id, mbr_preferred_am_pm, mbr_preferred_time, mbr_prv_innetwork, mbr_rep_addr_idn, mbr_rep_name, mbr_rp_mbr_id, mbr_same_mbr_ins, mbr_special_needs_cd, mbr_timezone, mbr_upd_dt, mbr_user_idn, mbr_wgt, mbr_work_status_idn, ROWNUM AS ora_rn 
FROM (SELECT mbr.comment_idn AS mbr_comment_idn, mbr.crt_dt AS mbr_crt_dt, mbr.data_source AS mbr_data_source, mbr.dol_bl_rmo_ind AS mbr_dol_bl_rmo_ind, mbr.dxcg_ctl_member AS mbr_dxcg_ctl_member, mbr.employment_start_dt AS mbr_employment_start_dt, mbr.employment_term_dt AS mbr_employment_term_dt, mbr.entity_active AS mbr_entity_active, mbr.ethnicity_idn AS mbr_ethnicity_idn, mbr.general_health_status_code AS mbr_general_health_status_code, mbr.hand_dominant_code AS mbr_hand_dominant_code, mbr.hgt_feet AS mbr_hgt_feet, mbr.hgt_inches AS mbr_hgt_inches, mbr.highest_edu_level AS mbr_highest_edu_level, mbr.insd_addr_idn AS mbr_insd_addr_idn, mbr.insd_alt_id AS mbr_insd_alt_id, mbr.insd_name AS mbr_insd_name, mbr.insd_ssn_tin AS mbr_insd_ssn_tin, mbr.is_smoker AS mbr_is_smoker, mbr.is_vip AS mbr_is_vip, mbr.lmbr_first_name AS mbr_lmbr_first_name, mbr.lmbr_last_name AS mbr_lmbr_last_name, mbr.marital_status_cd AS mbr_marital_status_cd, mbr.mbr_birth_dt AS mbr_mbr_birth_dt, mbr.mbr_death_dt AS mbr_mbr_death_dt, mbr.mbr_expired AS mbr_mbr_expired, mbr.mbr_first_name AS mbr_mbr_first_name, mbr.mbr_gender_cd AS mbr_mbr_gender_cd, mbr.mbr_idn AS mbr_mbr_idn, mbr.mbr_ins_type AS mbr_mbr_ins_type, mbr.mbr_isreadonly AS mbr_mbr_isreadonly, mbr.mbr_last_name AS mbr_mbr_last_name, mbr.mbr_middle_name AS mbr_mbr_middle_name, mbr.mbr_name AS mbr_mbr_name, mbr.mbr_status_idn AS mbr_mbr_status_idn, mbr.mpi_id AS mbr_mpi_id, mbr.preferred_am_pm AS mbr_preferred_am_pm, mbr.preferred_time AS mbr_preferred_time, mbr.prv_innetwork AS mbr_prv_innetwork, mbr.rep_addr_idn AS mbr_rep_addr_idn, mbr.rep_name AS mbr_rep_name, mbr.rp_mbr_id AS mbr_rp_mbr_id, mbr.same_mbr_ins AS mbr_same_mbr_ins, mbr.special_needs_cd AS mbr_special_needs_cd, mbr.timezone AS mbr_timezone, mbr.upd_dt AS mbr_upd_dt, mbr.user_idn AS mbr_user_idn, mbr.wgt AS mbr_wgt, mbr.work_status_idn AS mbr_work_status_idn 
FROM mbr JOIN mbr_identfn ON mbr.mbr_idn = mbr_identfn.mbr_idn 
WHERE mbr_identfn.mbr_idn = mbr.mbr_idn AND mbr_identfn.identfd_type = :identfd_type_1 AND mbr_identfn.identfd_number = :identfd_number_1 AND mbr_identfn.entity_active = :entity_active_1) 
WHERE ROWNUM <= :ROWNUM_1) 
WHERE ora_rn > :ora_rn_1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse     9936      0.46       0.49          0          0          0           0
Execute   9936      0.60       0.59          0          0          0           0
Fetch     9936    329.87     404.00          0  136966922          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    29808    330.94     405.09          0  136966922          0           0

Misses in library cache during parse: 0
Optimizer mode: FIRST_ROWS
Parsing user id: 36  (JIVA_DEV)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  VIEW  (cr=102 pr=0 pw=0 time=2180 us)
      0   COUNT STOPKEY (cr=102 pr=0 pw=0 time=2163 us)
      0    NESTED LOOPS  (cr=102 pr=0 pw=0 time=2152 us)
      0     INDEX SKIP SCAN IDX_MBR_IDENTFN (cr=102 pr=0 pw=0 time=2140 us)(object id 341053)
      0     TABLE ACCESS BY INDEX ROWID MBR (cr=0 pr=0 pw=0 time=0 us)
      0      INDEX UNIQUE SCAN PK_CLAIMANT (cr=0 pr=0 pw=0 time=0 us)(object id 334044)


Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   MODE: HINT: FIRST_ROWS
      0   VIEW
      0    COUNT (STOPKEY)
      0     NESTED LOOPS
      0      INDEX   MODE: ANALYZED (SKIP SCAN) OF 'IDX_MBR_IDENTFN' 
                 (INDEX (UNIQUE))
      0      TABLE ACCESS   MODE: ANALYZED (BY INDEX ROWID) OF 'MBR' 
                 (TABLE)
      0       INDEX   MODE: ANALYZED (UNIQUE SCAN) OF 'PK_CLAIMANT' 
                  (INDEX (UNIQUE))

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

بناءً على قراءتي لأوراكل توثيق Skip Scans, ، يكون فحص SKIP مفيدًا للغاية عندما يكون للعمود الأول من الفهرس عدد منخفض من القيم الفريدة. الشيء هو أن الفهرس الأول لهذا العمود لديه عدد كبير من التفرد. إذن ، هل أنا محق في افتراض أن فحص التخطي هو الشيء الخطأ الذي يجب القيام به هنا؟ أيضا ، أي نوع من الفحص ينبغي هل تفعل؟ هل يجب أن أفعل المزيد من التلميح لهذا الاستعلام؟

تعديل: أود أن أشير أيضًا إلى أن الاستعلام الذي يستخدم فيه البند الأعمدة في IDX_MBR_IDENTFN وليس هناك أعمدة غير ما في هذا الفهرس. بقدر ما أستطيع أن أقول ، أنا لا أتخطى أي أعمدة.

تحرير 2: لقد فعلت بعض الأشياء لتسريع هذا الاستعلام. بادئ ذي بدء ، أزلت الترحيل. كما اتضح ، فإن هذا الاستعلام لا يعيد سوى صف واحد على أي حال. ثانيا ، أضفت أ LEADING تلميح للتأكد من أن الجداول يتم الاستعلام عنها بالترتيب الصحيح. ثالثًا ، أزلت المكررة mbr_idn فاعل. أخيرًا ، لقد صنعت IDX_MBR_IDENTFN فريدة من نوعها. إجمالاً ، هذا يجعل تحسين الأداء شديدًا (على الرغم من أنه لا يزال أغلى استعلام أقوم بتشغيله):

SELECT /*+ LEADING (mbr_identfn, mbr) */ mbr.comment_idn AS mbr_comment_idn, mbr.crt_dt AS mbr_crt_dt, mbr.data_source AS mbr_data_source, mbr.dol_bl_rmo_ind AS mbr_dol_bl_rmo_ind, mbr.dxcg_ctl_member AS mbr_dxcg_ctl_member, mbr.employment_start_dt AS mbr_employment_start_dt, mbr.employment_term_dt AS mbr_employment_term_dt, mbr.entity_active AS mbr_entity_active, mbr.ethnicity_idn AS mbr_ethnicity_idn, mbr.general_health_status_code AS mbr_general_health_status_code, mbr.hand_dominant_code AS mbr_hand_dominant_code, mbr.hgt_feet AS mbr_hgt_feet, mbr.hgt_inches AS mbr_hgt_inches, mbr.highest_edu_level AS mbr_highest_edu_level, mbr.insd_addr_idn AS mbr_insd_addr_idn, mbr.insd_alt_id AS mbr_insd_alt_id, mbr.insd_name AS mbr_insd_name, mbr.insd_ssn_tin AS mbr_insd_ssn_tin, mbr.is_smoker AS mbr_is_smoker, mbr.is_vip AS mbr_is_vip, mbr.lmbr_first_name AS mbr_lmbr_first_name, mbr.lmbr_last_name AS mbr_lmbr_last_name, mbr.marital_status_cd AS mbr_marital_status_cd, mbr.mbr_birth_dt AS mbr_mbr_birth_dt, mbr.mbr_death_dt AS mbr_mbr_death_dt, mbr.mbr_expired AS mbr_mbr_expired, mbr.mbr_first_name AS mbr_mbr_first_name, mbr.mbr_gender_cd AS mbr_mbr_gender_cd, mbr.mbr_idn AS mbr_mbr_idn, mbr.mbr_ins_type AS mbr_mbr_ins_type, mbr.mbr_isreadonly AS mbr_mbr_isreadonly, mbr.mbr_last_name AS mbr_mbr_last_name, mbr.mbr_middle_name AS mbr_mbr_middle_name, mbr.mbr_name AS mbr_mbr_name, mbr.mbr_status_idn AS mbr_mbr_status_idn, mbr.mpi_id AS mbr_mpi_id, mbr.preferred_am_pm AS mbr_preferred_am_pm, mbr.preferred_time AS mbr_preferred_time, mbr.prv_innetwork AS mbr_prv_innetwork, mbr.rep_addr_idn AS mbr_rep_addr_idn, mbr.rep_name AS mbr_rep_name, mbr.rp_mbr_id AS mbr_rp_mbr_id, mbr.same_mbr_ins AS mbr_same_mbr_ins, mbr.special_needs_cd AS mbr_special_needs_cd, mbr.timezone AS mbr_timezone, mbr.upd_dt AS mbr_upd_dt, mbr.user_idn AS mbr_user_idn, mbr.wgt AS mbr_wgt, mbr.work_status_idn AS mbr_work_status_idn 
FROM mbr JOIN mbr_identfn ON mbr.mbr_idn = mbr_identfn.mbr_idn 
WHERE mbr_identfn.identfd_type = :identfd_type_1 AND mbr_identfn.identfd_number = :identfd_number_1 AND mbr_identfn.entity_active = :entity_active_1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse    10102      0.45       0.42          0          0          0           0
Execute  10102      0.44       0.52          0          0          0           0
Fetch    10102      1.60       1.81          0     218121          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    30306      2.50       2.75          0     218121          0           0

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 36  (JIVA_DEV)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  NESTED LOOPS  (cr=3 pr=0 pw=0 time=96 us)
      0   TABLE ACCESS BY INDEX ROWID MBR_IDENTFN (cr=3 pr=0 pw=0 time=88 us)
      0    INDEX UNIQUE SCAN UK_CLM_IDFN (cr=3 pr=0 pw=0 time=77 us)(object id 334118)
      0   TABLE ACCESS BY INDEX ROWID MBR (cr=0 pr=0 pw=0 time=0 us)
      0    INDEX UNIQUE SCAN PK_CLAIMANT (cr=0 pr=0 pw=0 time=0 us)(object id 334044)


Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   MODE: ALL_ROWS
      0   NESTED LOOPS
      0    TABLE ACCESS   MODE: ANALYZED (BY INDEX ROWID) OF 
               'MBR_IDENTFN' (TABLE)
      0     INDEX   MODE: ANALYZED (UNIQUE SCAN) OF 'UK_CLM_IDFN' (INDEX 
                (UNIQUE))
      0    TABLE ACCESS   MODE: ANALYZED (BY INDEX ROWID) OF 'MBR' (TABLE)

      0     INDEX   MODE: ANALYZED (UNIQUE SCAN) OF 'PK_CLAIMANT' (INDEX 
                (UNIQUE))
هل كانت مفيدة؟

المحلول

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

حاول إنشاء فهرس منفصل على العمود الذي يعد جزءًا من IDX_MBR_IDENTFN وتستخدم في استفسارك.


على سبيل المثال ، إذا your_table يشبه هذا:

id  status
1   0
2   0
3   0
4   1

ولديك فهرس مركب على (id, status), ، الاستعلام Select * From your_table Where status = 1 من المحتمل أن تستخدم الفهرس ، ولكن من أجل العثور على الصفوف الصحيحة ، يتعين عليه قراءة كل صف من الفهرس (المعرف 1 إلى 4) والتحقق من status.


تحديث: يمكن أن يحسن الفهرس التالي الأداء أكثر قليلاً ، ولكن سيتعين عليك المحاولة إذا كان ذلك يساعد حقًا:

mbr_identfn( identfd_type, identfd_number, entity_active, mbr_idn )

هذا يمكن أن يساعد حتى لتجنب التلميح.

نصائح أخرى

أود أن أحول تركيزي بعيدًا عن فحص تخطي.

يوضح لك مقتطف TKPROF أن أولويتك الأولى يجب أن تكون تقليل عدد المرات التي تصدر فيها هذا البيان. تقوم حاليًا بتنفيذ هذا البيان 9936 مرة. ويستغرق كل تنفيذ فقط 405/9936 ثانية. بسرعة معقولة. ولكن ليس إذا قمت بتنفيذها 9936 مرة.

لذلك هذا البيان متأكد تقريبًا داخل بنية حلقة. في كل تكرار ، يمكنك تقديم مجموعة معلمة إدخال مختلفة (: identfd_type_1 ،: identfd_number_1 ،: entity_active_1 ،: rownum_1 ،: ora_rn_1). أعد كتابة هذه الحلقة لتنفيذ هذا البيان مرة واحدة للمجموعة بأكملها ، وربما ستكون مشكلة الأداء الخاصة بك شيئًا من الماضي. إذا لم يكن كذلك ، يرجى نشر إخراج TKPROF الجديد.

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

قد يساعد ذلك إذا حددت ما هي الأعمدة في الفهارس (PK_CLAIMANT و IDX_MBR_IDEDFN) ، وبأي ترتيب.

أظن أنها مشكلة نوع البيانات. إذا ، على سبيل المثال ، mbr_identfn.identfd_type هو العمود الرئيسي للفهرس وهو رقمي ، ولكن الخاص بك: identfd_type_1 هو متغير الحرف (أو العكس) يصبح غير قابل للاستخدام. ومع ذلك ، إذا كان هناك أنواع قليلة ، فيمكن استخدام الفهرس مع فحص تخطي.

يمكنك أيضًا تحديد المسند "mbr.mbr_idn = mbr_identfn.mbr_idn" في كل من الفقرة وفقرة الانضمام.

لشرح فحص Skip ... يبدو أن هذا الجزء الأصلي ذو الصلة من الاستعلام:

WHERE mbr_identfn.mbr_idn = mbr.mbr_idn
  AND mbr_identfn.identfd_type = :identfd_type_1
  AND mbr_identfn.identfd_number = :identfd_number_1
  AND mbr_identfn.entity_active = :entity_active_1

إذا بدأ التنفيذ بـ mbr_identfn ، فلن يكون لدينا بعد قيمة لـ MBR_IDN للبحث في الفهرس ؛ هذا يعني أننا لا نستطيع إجراء فحص فريد أو على نطاق. ولكن لدينا قيم معطاة (كمتغيرات ربط) للأعمدة الثلاثة الأخرى من الفهرس ، حتى نتمكن من إجراء فحص تخطي. تختار Oracle القيام بذلك من أجل تجنب الوصول إلى الجدول الأساسي على الإطلاق ، وهو ما يبدو معقولًا.

ما هو المفتاح الأساسي لـ MBR_identfn؟ هل هو MBR_IDN وحده؟

أعتقد أنه يجب أن يكون لديك فهرس منفصل على mbr_identfn مع بعض أو كل التعريف IdentFD_Type و IdentFd_Number و entity_active باعتباره الأعمدة الرائدة. هذا من شأنه أن يسمح بإجراء نطاق أو فحص فريد بدلاً من فحص تخطي.

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