2012-06-27 4 views
10

मेरे पास 1.5 मिलियन पंक्तियों वाली एक तालिका है। मैं एक क्वेरी चलाता हूं जो कॉलम में गैर-दोहराने वाले मान वाले रिकॉर्ड प्राप्त करता है। मैं एक ऐसा व्यवहार देख रहा हूं जिसमें इंडेक्स बनाने के बाद क्वेरी का प्रदर्शन घट जाता है। मैंने आंकड़ों को इकट्ठा करने के लिए 100% अनुमान प्रतिशत (गणना मोड) के साथ dbms_stats का भी उपयोग किया ताकि ओरेकल 11 जी सीबीओ क्वेरी प्लान के लिए एक अधिक सूचित निर्णय लेता है, लेकिन यह क्वेरी निष्पादन समय में सुधार नहीं करता है।इंडेक्स बनने के बाद क्वेरी धीमी गति से निष्पादित होती है और dbms_stats गणना का उपयोग किया जाता है

SQL> desc tab3; 
Name     Null? Type 
---------------------------------------------- 
COL1       NUMBER(38) 
COL2       VARCHAR2(100) 
COL3       VARCHAR2(36) 
COL4       VARCHAR2(36) 
COL5       VARCHAR2(4000) 
COL6       VARCHAR2(4000) 
MEASURE_0      VARCHAR2(4000) 
MEASURE_1      VARCHAR2(4000) 
MEASURE_2      VARCHAR2(4000) 
MEASURE_3      VARCHAR2(4000) 
MEASURE_4      VARCHAR2(4000) 
MEASURE_5      VARCHAR2(4000) 
MEASURE_6      VARCHAR2(4000) 
MEASURE_7      VARCHAR2(4000) 
MEASURE_8      VARCHAR2(4000) 
MEASURE_9      VARCHAR2(4000) 

कॉलम measure_0 में 0.4 मिलियन अद्वितीय मूल्य हैं।

SQL> select count(*) from (select measure_0 from tab3 group by measure_0 having count(*) = 1) abc; 

    COUNT(*) 
---------- 
    403664 

निष्पादन योजना के साथ निम्नलिखित प्रश्न है, कृपया ध्यान दें कि तालिका पर कोई अनुक्रमणिका नहीं है।

SQL> set autotrace traceonly; 

SQL> SELECT * FROM (
    2  SELECT 
    3    (ROWNUM -1) AS COL1, 
    4    ft.COL1   AS OLD_COL1, 
    5    ft.COL2, 
    6    ft.COL3, 
    7    ft.COL4, 
    8    ft.COL5, 
    9    ft.COL6, 
10    ft.MEASURE_0, 
11    ft.MEASURE_1, 
12    ft.MEASURE_2, 
13    ft.MEASURE_3, 
14    ft.MEASURE_4, 
15    ft.MEASURE_5, 
16    ft.MEASURE_6, 
17    ft.MEASURE_7, 
18    ft.MEASURE_8, 
19    ft.MEASURE_9 
20  FROM tab3 ft 
21  WHERE MEASURE_0 IN 
22  (
23    SELECT MEASURE_0 
24    FROM tab3 
25    GROUP BY MEASURE_0 
26    HAVING COUNT(*) = 1 
27  ) 
28 ) ABC WHERE COL1 >= 0 AND COL1 <=449; 

450 rows selected. 

Elapsed: 00:00:01.90 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 3115757351 

------------------------------------------------------------------------------------ 
| Id | Operation    | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT  |   | 1243 | 28M| 717K (1)| 02:23:29 | 
|* 1 | VIEW     |   | 1243 | 28M| 717K (1)| 02:23:29 | 
| 2 | COUNT     |   |  |  |   |   | 
|* 3 | HASH JOIN   |   | 1243 | 30M| 717K (1)| 02:23:29 | 
| 4 |  VIEW    | VW_NSO_1 | 1686K| 3219M| 6274 (2)| 00:01:16 | 
|* 5 |  FILTER    |   |  |  |   |   | 
| 6 |  HASH GROUP BY  |   |  1 | 3219M| 6274 (2)| 00:01:16 | 
| 7 |  TABLE ACCESS FULL| TAB3  | 1686K| 3219M| 6196 (1)| 00:01:15 | 
| 8 |  TABLE ACCESS FULL | TAB3  | 1686K| 37G| 6211 (1)| 00:01:15 | 
------------------------------------------------------------------------------------ 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter("COL1">=0 AND "COL1"<=449) 
    3 - access("MEASURE_0"="MEASURE_0") 
    5 - filter(COUNT(*)=1) 

Note 
----- 
    - dynamic sampling used for this statement (level=2) 


Statistics 
---------------------------------------------------------- 
     354 recursive calls 
      0 db block gets 
     46518 consistent gets 
     45122 physical reads 
      0 redo size 
     43972 bytes sent via SQL*Net to client 
     715 bytes received via SQL*Net from client 
     31 SQL*Net roundtrips to/from client 
      0 sorts (memory) 
      0 sorts (disk) 
     450 rows processed 

क्वेरी 1.90 सेकंड लेता है। यदि मैं फिर से क्वेरी चलाता हूं तो यह 1.66 सेकंड लेता है। पहले रन में अधिक समय क्यों लगता है?

इसे गति देने के लिए मैंने क्वेरी में उपयोग किए गए दो कॉलम पर इंडेक्स बनाए।

SQL> create index ind_tab3_orgid on tab3(COL1); 

Index created. 

Elapsed: 00:00:01.68 
SQL> create index ind_tab3_msr_0 on tab3(measure_0); 

Index created. 

Elapsed: 00:00:01.83 

जब मैं पहली बार इस के बाद आप क्वेरी निकाल दिया यह एक काली सेकण्ड लगे वापस आने के लिए। जबकि बाद के रनों ने इसे 2.9 सेकंड में खरीदा। पहले भाग में ओरेकल इतना समय क्यों लेता है, क्या यह गर्म हो रहा है या कुछ .. मुझे परेशान करता है!

यह योजना जब यह लेता 2.9 seconds-

450 rows selected. 

Elapsed: 00:00:02.92 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 240271480 

------------------------------------------------------------------------------------------------- 
| Id | Operation      | Name   | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |    | 1243 | 28M| 711K (1)| 02:22:15 | 
|* 1 | VIEW       |    | 1243 | 28M| 711K (1)| 02:22:15 | 
| 2 | COUNT      |    |  |  |   |   | 
| 3 | NESTED LOOPS    |    |  |  |   |   | 
| 4 |  NESTED LOOPS    |    | 1243 | 30M| 711K (1)| 02:22:15 | 
| 5 |  VIEW      | VW_NSO_1  | 1686K| 3219M| 6274 (2)| 00:01:16 | 
|* 6 |  FILTER     |    |  |  |   |   | 
| 7 |  HASH GROUP BY   |    |  1 | 3219M| 6274 (2)| 00:01:16 | 
| 8 |   TABLE ACCESS FULL  | TAB3   | 1686K| 3219M| 6196 (1)| 00:01:15 | 
|* 9 |  INDEX RANGE SCAN   | IND_TAB3_MSR_0 | 1243 |  |  2 (0)| 00:00:01 | 
| 10 |  TABLE ACCESS BY INDEX ROWID| TAB3   | 1243 | 28M| 44 (0)| 00:00:01 | 
------------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter("COL1">=0 AND "COL1"<=449) 
    6 - filter(COUNT(*)=1) 
    9 - access("MEASURE_0"="MEASURE_0") 

Note 
----- 
    - dynamic sampling used for this statement (level=2) 


Statistics 
---------------------------------------------------------- 
      0 recursive calls 
      0 db block gets 
    660054 consistent gets 
     22561 physical reads 
      0 redo size 
     44358 bytes sent via SQL*Net to client 
     715 bytes received via SQL*Net from client 
     31 SQL*Net roundtrips to/from client 
      0 sorts (memory) 
      0 sorts (disk) 
     450 rows processed 

मैं समय उम्मीद कर रहा था की तुलना में जब तालिका गैर अनुक्रमित था कम हो रहा है। तालिका के अनुक्रमित संस्करण को गैर अनुक्रमित संस्करण की तुलना में परिणामों को लाने के लिए अधिक समय क्यों लगता है? अगर मैं गलत नहीं हूं तो यह इंडेक्स रॉयड द्वारा टेबल एक्सेस है जो समय ले रहा है। क्या मैं टेबल एक्सेस का उपयोग करने के लिए ऑरैकल लागू कर सकता हूं?

तब मैंने टेबल पर आंकड़े एकत्र किए ताकि सीबीओ गणना विकल्प के साथ योजना में सुधार करे। तो अब आंकड़े सटीक होंगे।

SQL> EXECUTE dbms_stats.gather_table_stats (ownname=>'EQUBE67DP', tabname=>'TAB3',estimate_percent=>null,cascade=>true); 

PL/SQL procedure successfully completed. 

Elapsed: 00:01:02.47 
SQL> set autotrace off; 
SQL> select COLUMN_NAME,NUM_DISTINCT,SAMPLE_SIZE,HISTOGRAM,LAST_ANALYZED from dba_tab_cols where table_name = 'TAB3' ; 

COLUMN_NAME     NUM_DISTINCT SAMPLE_SIZE HISTOGRAM  LAST_ANALYZED 
------------------------------ ------------ ----------- --------------- --------- 
COL1        1502257  1502257 NONE   27-JUN-12 
COL2          0    NONE   27-JUN-12 
COL3          1  1502257 NONE   27-JUN-12 
COL4          0    NONE   27-JUN-12 
COL5        1502257  1502257 NONE   27-JUN-12 
COL6        1502257  1502257 NONE   27-JUN-12 
MEASURE_0       405609  1502257 HEIGHT BALANCED 27-JUN-12 
MEASURE_1       128570  1502257 NONE   27-JUN-12 
MEASURE_2       1502257  1502257 NONE   27-JUN-12 
MEASURE_3       185657  1502257 NONE   27-JUN-12 
MEASURE_4        901  1502257 NONE   27-JUN-12 
MEASURE_5        17  1502257 NONE   27-JUN-12 
MEASURE_6        2202  1502257 NONE   27-JUN-12 
MEASURE_7        2193  1502257 NONE   27-JUN-12 
MEASURE_8        21  1502257 NONE   27-JUN-12 
MEASURE_9        27263  1502257 NONE   27-JUN-12 

मैं फिर से क्वेरी

450 rows selected. 

Elapsed: 00:00:02.95 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 240271480 

------------------------------------------------------------------------------------------------- 
| Id | Operation      | Name   | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |    | 31M| 718G| 8046 (2)| 00:01:37 | 
|* 1 | VIEW       |    | 31M| 718G| 8046 (2)| 00:01:37 | 
| 2 | COUNT      |    |  |  |   |   | 
| 3 | NESTED LOOPS    |    |  |  |   |   | 
| 4 |  NESTED LOOPS    |    | 31M| 62G| 8046 (2)| 00:01:37 | 
| 5 |  VIEW      | VW_NSO_1  | 4057 | 7931K| 6263 (2)| 00:01:16 | 
|* 6 |  FILTER     |    |  |  |   |   | 
| 7 |  HASH GROUP BY   |    |  1 | 20285 | 6263 (2)| 00:01:16 | 
| 8 |   TABLE ACCESS FULL  | TAB3   | 1502K| 7335K| 6193 (1)| 00:01:15 | 
|* 9 |  INDEX RANGE SCAN   | IND_TAB3_MSR_0 |  4 |  |  2 (0)| 00:00:01 | 
| 10 |  TABLE ACCESS BY INDEX ROWID| TAB3   | 779K| 75M|  3 (0)| 00:00:01 | 
------------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - filter("COL1">=0 AND "COL1"<=449) 
    6 - filter(COUNT(*)=1) 
    9 - access("MEASURE_0"="MEASURE_0") 


Statistics 
---------------------------------------------------------- 
      0 recursive calls 
      0 db block gets 
    660054 consistent gets 
     22561 physical reads 
      0 redo size 
     44358 bytes sent via SQL*Net to client 
     715 bytes received via SQL*Net from client 
     31 SQL*Net roundtrips to/from client 
      0 sorts (memory) 
      0 sorts (disk) 
     450 rows processed 

भाग गया इस बार क्वेरी 2.9 सेकंड में वापस आ गया है (कभी कभी यह 3.9 सेकंड भी लिया)।

मेरा लक्ष्य क्वेरी निष्पादन समय जितना संभव हो कम से कम करना है। लेकिन इंडेक्स जोड़ने या आंकड़ों की गणना करने के बाद क्वेरी समय बढ़ रहा है। यह क्यों हो रहा है और इंडेक्स को रखकर मैं कैसे सुधार कर सकता हूं?

+0

निष्पादन योजना ** ** ** सूचकांक क्या है? –

+2

क्वेरी को पहली बार चलाने में अधिक समय क्यों लगता है? एक बात के लिए, यह ऑटोट्रेस द्वारा रिपोर्ट की गई 254 रिकर्सिव एसक्यूएल कॉल है। सेमेन्टिक्स के लिए क्वेरी को पार्स करने के लिए किए जाने वाले सभी काम (संदर्भित वस्तुओं और नाम मौजूद हैं और क्या आपके पास उनके पास विशेषाधिकार हैं), और उसके बाद निष्पादन योजना तैयार करने के लिए काम (कौन से इंडेक्स उपलब्ध हैं, लागत अनुमानित करें विभिन्न संभावित योजनाओं के)। उस पहले निष्पादन पर वहां बहुत भारी भारोत्तोलन किया जा रहा है। – spencer7593

+2

आपकी दूसरी क्वेरी पर, जो 2 9 सेकेंड पहले रन लेता है, संभवतः शारीरिक पढ़ता है ... ओरेकल डिस्क से ब्लॉक प्राप्त कर रहा है और बफर कैश भर रहा है। (ऑटोट्रेस इस का एक सारांश दिखाएगा, एक कार्यक्रम 10046 ट्रेस में सभी प्रतीक्षाों के लिए विवरण होगा।) – spencer7593

उत्तर

11

सबसे पहले, मुझे बोली Tom Kyte करते हैं:

सिर्फ और
से अधिक

अपने आप से कहा, "पूर्ण स्कैन बुराई नहीं हैं, अनुक्रमित अच्छा नहीं कर रहे हैं"
"पूर्ण स्कैन कर रहे हैं रखने के बुराई नहीं, इंडेक्स अच्छे नहीं हैं "
" पूर्ण स्कैन बुरा नहीं हैं, इंडेक्स अच्छे नहीं हैं "
" पूर्ण स्कैन बुरा नहीं हैं, इंडेक्स अच्छे नहीं हैं "
" पूर्ण स्कैन ई नहीं हैं विल, अनुक्रमित वे जादुई चांदी की गोली नहीं हैं (अच्छा नहीं कर रहे हैं "
" पूर्ण स्कैन बुराई नहीं हैं, अनुक्रमित अच्छा नहीं कर रहे हैं "

इंडेक्स हमेशा प्रदर्शन में सुधार नहीं होगा, के रूप में अगर ऐसी बात कभी अस्तित्व में :)

अब आप क्यों पूछ रहे हैं यह आपके सूचकांक के साथ अधिक समय लेता है।

  • पूर्ण तालिका स्कैन के साथ: 46,518 लगातार हो जाता है अपने सूचकांक के साथ
  • : 660,054 लगातार हो जाता है

दूसरे शब्दों में: ओरेकल अधिक पढ़ने कार्रवाई जवाब बहुत सरल है पूर्ण अनुक्रमणिका स्कैन के साथ आपकी अनुक्रमणिका के साथ। यह इसलिए होता है क्योंकि:

  1. पूरी तालिका स्कैन (एक समय में कई ब्लॉक) थोक संचालन कर रहे हैं पढ़ता है और इसलिए डेटा
  2. कभी कभी के बहुत पढ़ने के लिए जब आप एक सूचकांक आप अंत पढ़ने से पढ़ा एक कारगर तरीका हैं सटीक उसी डेटा ब्लॉक एक से अधिक बार ब्लॉक।

क्यों अनुकूलक इस स्पष्ट रूप से गैर-कुशल इंडेक्स का उपयोग करने के लिए चुना है, इस वजह से esimate_percent=100 और यहां तक ​​कि के साथ पूर्ण हिस्टोग्राम (जो आप MEASURE_0 स्तंभ पर एकत्र किया), कुछ डेटा वितरण अभी भी मज़बूती से व्यक्त नहीं किया जा सकता अनुकूलक के सरल विश्लेषण से। विशेष रूप से, क्रॉस-कॉलम और क्रॉस-टेबल निर्भरता विश्लेषक द्वारा अच्छी तरह से समझ में नहीं आती है। इससे गलत अनुमान सामने आते हैं, जिससे खराब योजना पसंद होती है।

संपादित करें: यह सीबीओ के काम परिकल्पना के लिए बिल्कुल भी काम नहीं कर रहे लगता है इस आत्म में शामिल होने के (अपने पिछले क्वेरी 31 मिलियन पंक्तियों की उम्मीद है, जबकि केवल 450 का चयन किया जाता!)। यह काफी परेशान है क्योंकि तालिका में केवल 1.5 एम पंक्तियां हैं। आप ओरेकल का किस संस्करण का उपयोग कर रहे हैं?

मुझे लगता है कि आप आप स्वयं में शामिल होने को हटा सकते हैं और इसलिए विश्लेषण की मदद से क्वेरी प्रदर्शन में सुधार है कि मिल जाएगा:

SELECT * FROM (
    SELECT (ROWNUM -1) AS COL1, ABC.* 
    FROM (
     SELECT 
       ft.COL1 AS OLD_COL1, 
       [...], 
       COUNT(*) OVER (PARTITION BY MEASURE_O) nb_0 
     FROM tab3 ft 
    ) ABC 
    WHERE nb_0 = 1 
     AND ROWNUM - 1 <= 449 
    ) v 
WHERE COL1 >= 0; 

तुम भी पूछ रहे थे क्यों पहली बार एक प्रश्न चलाया जाता है सामान्य रूप में अधिक समय लगता है। ऐसा इसलिए है क्योंकि काम पर कैश हैं। डेटाबेस स्तर पर एसजीए है जहां सभी ब्लॉक पहले डिस्क से कॉपी किए जाते हैं और फिर कई बार पढ़ा जा सकता है (पहली बार एक ब्लॉक पूछताछ हमेशा एक शारीरिक पढ़ा जाता है)।फिर कुछ प्रणालियों में एक स्वतंत्र सिस्टम कैश भी होता है जो हाल ही में पढ़ा गया है तो डेटा तेज़ी से वापस कर देगा।

आगे पढ़ने के लिए:

+0

धन्यवाद, मैं निश्चित रूप से टॉम Kyte के qoute दिमाग में रखना होगा :)। मैं ओरेकल 11 जी का उपयोग कर रहा हूँ। मैं एसक्यूएल प्रोफाइल पर पढ़ता हूं, दुर्भाग्य से मुझे नहीं लगता कि एसक्यूएल प्रोफाइल मेरी समस्या का समाधान कर सकते हैं। एसक्यूएल प्रोफाइल उन प्रश्नों पर लागू होते हैं जिनकी भविष्यवाणी नहीं बदली है, मैंने जो प्रश्न यहां उल्लेख किया है वह बदल जाएगा (अंतिम फ़िल्टर 'COL1> = 0 और COL1 <= 449'' COL1> = 400000 और COL1 <= 400449' जैसा कुछ भी हो सकता है)। मैंने गतिशील नमूना संकेत का उपयोग करने की कोशिश की लेकिन मुझे यकीन नहीं है कि मैं इसे सही कर रहा हूं। मैंने 'टैब 3' पर दूसरे चयन में एक गतिशील नमूना स्तर 3 संकेत दिया, लेकिन इसका कोई प्रभाव नहीं पड़ा। – rirhs

+0

मैंने आपके द्वारा लिखी गई क्वेरी को चलाने की कोशिश की, इसे वापस पाने में लगभग 14 सेकंड लगते हैं। – rirhs

+0

(1) आप बाइंड वैरिएबल का उपयोग कर सकते हैं :) और (2) क्या आपने एनालिटिक्स के साथ क्वेरी की कोशिश की है? वैसे भी मुझे नहीं लगता कि इस मामले में इंडेक्स का उपयोग सहायक होगा: आप मूल रूप से 'MEASURE_0'' पर एक फ़िल्टर के साथ पूरी तालिका के माध्यम से पेजिंग कर रहे हैं जो पंक्तियों में से लगभग आधे का चयन करेगा। जब मजबूत मजबूतता होती है तो इंडेक्स बहुत अच्छा होता है, फ़िल्टर कमजोर होने पर इतना अधिक नहीं होता है। –

3

यह कोड कैसे प्रदर्शित करता है?

SELECT ROWNUM - 1  AS col1 
,  ft.col1   AS old_col1 
,  ft.col2 
,  ft.col3 
,  ft.col4 
,  ft.col5 
,  ft.col6 
,  ft.measure_0 
,  ft.measure_1 
,  ft.measure_2 
,  ft.measure_3 
,  ft.measure_4 
,  ft.measure_5 
,  ft.measure_6 
,  ft.measure_7 
,  ft.measure_8 
,  ft.measure_9 
FROM tab3 ft 
WHERE NOT EXISTS (SELECT NULL 
        FROM tab3 ft_prime 
        WHERE ft_prime.measure_0 = ft.measure_0 
        AND ft_prime.ROWID <> ft.ROWID) 
AND ROWNUM <= 450; 
+0

यह क्वेरी वास्तव में अच्छी तरह से प्रदर्शन करती है, यह 0.04 सेकंड में वापस आई, लेकिन मैंने जिस प्रश्न का उल्लेख किया है वह बदल जाएगा (अंतिम फ़िल्टर 'COL1> = 0 और COL1 <= 44 9' 'COL1> = 400000 और COL1 <= 400449' जैसी कुछ भी हो सकती है)। तो मैंने इस क्वेरी को निर्दिष्ट करने के चयन के साथ अपनी क्वेरी को घेर लिया, और परिणाम 1.6 सेकंड में मिला, जो पिछली क्वेरी के साथ क्या हो रहा है उससे बेहतर है। धन्यवाद! – rirhs

+0

@shri: आप आंतरिक क्वेरी में ऊपरी रेंज फ़िल्टर 'ROWNUM <= 450' को दे सकते हैं, इससे ओरेकल को पता चलेगा कि अधिकतम 450 पंक्तियों की आवश्यकता है। अतिरिक्त फ़िल्टर 'COL1> = 0' को पाठ्यक्रम की बाहरी क्वेरी में होना चाहिए। इसे देखें [पेजिनेशन ऑप्टिमाइज़ेशन पर चर्चा] (http://asktom.oracle.com/pls/asktom/f?p=100:11TP:::P11_QUESTION_ID:127412348064)। –

संबंधित मुद्दे