2012-06-27 9 views
10

1,5 milyon satırlık bir tablom var. Bir sütunda yinelenen değerleri olmayan kayıtları getiren bir sorgu çalıştırıyorum. Ben indeksleri oluşturduktan sonra sorgu performansını düşüren bir davranış gözlemliyorum. Ayrıca istatistik toplamak için 100% tahmini yüzdesi (hesaplama modu) ile dbms_stats kullandım, böylece Oracle 11g CBO sorgu planı için daha bilinçli bir karar verir, ancak sorgu yürütme süresini geliştirmez.Sorgu, dizin oluşturulduktan sonra daha yavaş yürütülür ve dbms_stats hesaplama kullanılır

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 numaralı sütunda 0,4 milyon benzersiz değer bulunmaktadır.

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

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

Aşağıdaki tabloda yürütme planı ile bir sorgu vardır, lütfen tabloda hiçbir dizin olmadığını unutmayın.

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 

sorgu 1.90 saniye kadar sürer. Sorguyu tekrar çalıştırırsam 1.66 saniye sürer. İlk çalışmada neden daha fazla zaman alıyor?

Hızlandırmak için, sorguda kullanılan iki sütunda dizinler oluşturdum. İlk kez bundan sonra sorgu kovarak

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 

geri gelmek için bir boğmaca saniye sürdü. Daha sonraki çalışmalar, 2,9 saniyede satın alınmıştır. İlk aşamada oracle neden bu kadar zaman alır, ısınıyor mu, bir şey mi? ben masa endeksli olmayan olduğundan daha düşük olduğu zaman bekliyordum 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 

aldığında

Bu

planıdır. Neden tablonun dizine eklenen sürümü sonuçları endekslenmemiş sürümden daha fazla almak için zaman alır? Yanlış olmazsa, zaman aşımına uğrayan INDEX ROWID TARA ERİŞİMİ olur. TABLE ACCESS FULL'u kullanmak için Oracle'ı uygulayabilir miyim?

Daha sonra tablodaki istatistikleri topladım ve böylece CBO, hesaplama seçeneğini kullanarak planı iyileştirir. Yani şimdi istatistikler doğru olurdu.

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 

Tekrar (bazen çok 3.9 saniye sürdü) sorgu

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 

sorgu 2.9 saniyede geri geldi bu defa koştu.

Amacım, sorgu yürütme süresini olabildiğince en aza indirmektir. Ancak indeks ekledikten sonra veya istatistik hesapladıktan sonra sorgulama süresi artmaya devam etti. Bu neden oluyor ve endeksleri tutarak bile nasıl gelişebilirim?Her şeyden

+0

Yürütme planı ** index nedir? –

+2

Sorgu için ilk çalıştırma neden daha uzun sürüyor? Bir şey için, autotrace tarafından rapor edilen 254 özyinelemeli SQL çağrıları. Sözdizimi sorgusu için ayrıştırmak için yapılması gereken tüm çalışma, semantik için (başvurulan nesneler ve isimler var ve bunlar üzerinde imtiyazlarınız var mı), ve daha sonra yürütme planını hazırlama işi (hangi endeksler kullanılabilir, tahmini maliyetler) çeşitli olası planların). Oradaki ilk infazda çok fazla ağır kaldırma var. – spencer7593

+2

İlk sorguda 29 saniye süren ikinci sorgunuzda, muhtemelen fiziksel okumalar ... Oracle diskten bloklar alıyor ve arabellek önbelleğini dolduruyor. (autotrace bunun bir özetini gösterirdi, bir olay 10046 izinin tüm beklemeler için ayrıntıları olur.) – spencer7593

cevap

11

Önce şunu Tom Kyte aktaralım:

sadece
"tam taramaları "indeksleri iyi değildir, tam taramalar kötü değildir" üzerinde ve
üzerinde

kendinize söylemeye devam değil kötülük, endeksler endeksleri "
'tam taramaları e olmayan iyi değildir, endeksler '
' tam taramalar kötü değildir iyi değildir,"
' tam taramalar kötü değildir iyi değildir vil, indeksleri onlar (sihirli gümüş kurşun değil, endeksler

endeksler hep performansını artırmak olmaz 'iyi değil "
' tam taramalar kötü değildir iyi değilse diye bir şey Şimdiye kadar var oldum :)

neden isteğinizi dizininizle daha uzun sürüyor.

  • tam tablo tarama ile: 660.054 tutarlı başka deyişle

alır: Oracle daha okuma işlemleri gerçekleştirmek tutarlı indeksi

  • alır cevabı oldukça basittir Dizin ile tam tablo taramasından daha fazla.

    1. TAM TABLO TARAMA (bir kerede birçok blokları) olan toplu işlemler okur ve bu nedenle okumakta sona bir dizinden okurken verilerine bazen
    2. çok okumak için etkili bir yoldur: Bunun nedeni Tam olarak aynı veri bloğu bir kereden fazla. (Eğer MEASURE_0 sütunda topladıkları) bile esimate_percent=100 ve tam histogramlar, bazı veri dağıtım hala güvenilir bir ifade edilemez çünkü
    3. iyileştirici bu belli olmayan etkili dizini kullanmayı seçtim gelince

    , bu Optimize edicinin basit analizi ile. Özellikle, çapraz kolonu ve çapraz tablo bağımlılığı analizör tarafından iyi anlaşılmamıştır. Bu, yanlış plan seçimine yol açan yanlış tahminlere yol açar.

    Düzenleme: CBO'nun çalışma hipotezi bu kendi kendine katılım için hiç çalışmaz gibi görünmektedir (son sorgunuz 31 milyon satır beklerken sadece 450 tanesi seçilebilir!). Bu tablo sadece 1.5 M satırları olduğundan oldukça şaşırtıcıdır. Oracle'ın hangi sürümünü kullanıyorsunuz?

    Ben size kendini katılmak kaldırmak ve bu nedenle analitik ile sorgu performansını artırabilir olduğunu göreceksiniz düşünüyorum:

    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; 
    

    sorgu çalıştırıldığında ilk kez genel olarak daha fazla zaman alır neden Ayrıca soruyorlardı. Bunun nedeni iş yerinde önbelleklerin bulunmasıdır. Veri tabanı düzeyinde, tüm blokların ilk olarak diskten kopyalandığı ve daha sonra birçok kez okunabildiği SGA vardır (ilk kez bir blok sorgulandığında her zaman fiziksel bir okumadır).Daha sonra bazı sistemler, son zamanlarda okunduğunda verileri daha hızlı döndürecek bağımsız bir sistem önbelleğine sahiptir. Daha fazlasını okumak için

    :

  • +0

    Teşekkürler, kesinlikle Tom Kyte'nin qoute aklında tutacağım :). Oracle 11g kullanıyorum. SQL profillerini okudum, maalesef SQL profillerinin problemimi çözebileceğini sanmıyorum. SQL profilleri, yüklemi değişmeyen sorgulara uygulanır, burada bahsettiğim sorgu değişecektir (son COL1> = 0 ve COL1 <= 449 = olan filtre, "COL1> = 400000 VE COL1 <= 400449" gibi bir şey olabilir.). Dinamik örnekleme ipucu kullanmaya çalıştım ama doğru yaptığımdan emin değilim. Dinamik bir örnekleme düzeyi 3 ipucu 'tab3' üzerinde ikinci seçime koydum, ancak hiçbir etki yapmadan. – rirhs

    +0

    Yazdığınız sorguyu çalıştırmayı denedim, geri dönmek yaklaşık 14 saniye sürüyor. – rirhs

    +0

    (1) Bağlama değişkenlerini kullanabilirsiniz :) ve (2) sorguyu analitik ile denediniz mi? Her neyse, indeks kullanımının bu durumda faydalı olacağını düşünmüyorum: temelde tüm tablodan satırların yaklaşık yarısını seçecek olan 'MEASURE_0' filtresine sahipsiniz. Filtre zayıf olduğunda çok güçlü bir seçicilik olduğunda indeks çok iyi. –

    3

    Bu kod nasıl çalışır?

    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

    Bu sorgu gerçekten iyi bir performans sergiliyor, 0.04 saniyede geri döndü, ancak burada bahsettiğim sorgu değişecek (son filtre "COL1> = 0 VE COL1 <= 449 ', "COL1> = 400000 VE COL1 <= 400449" gibi bir şey olabilir. Bu yüzden, sorgunuzu, bu yüklemi belirten bir seçimle çevreledim ve 1.6 saniyede sonuç aldım. Bu, bir önceki sorguda olandan daha iyi bir sonuç. Teşekkürler! – rirhs

    +0

    @shri: Üst sorgudaki 'ROWNUM <= 450' süzgecinin iç sorguda olmasına izin verebilirsiniz, bu Oracle'ın en fazla 450 satır gerektiğini bilmesini sağlayacaktır. 'COL1> = 0' ek filtresinin elbette dış sorguda olması gerekir. Bkz. [Sayfalandırma optimizasyonu] (http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:127412348064). –

    İlgili konular