Performance Tuning w środowisku RAC/WebLogic na maszynach Sun T5220 OPITZ CONSULTING Kraków Nowoczesne techniki konsolidacji i optymalizacji środowisk opartych o rozwiązania Oracle (2011) Piotr Sajda (kierownik Service Engineering) OPITZ CONSULTING Kraków 2011 Strona 1
Agenda 1. Wprowadzenie do środowiska testowego 2. Opis problemu 3. Krok po kroku - analiza problemu 4. Metody optymalizacji 5. Podsumowanie OPITZ CONSULTING Kraków 2011 Strona 2
1 Wprowadzenie do środowiska testowego OPITZ CONSULTING Kraków 2011 Strona 3
Środowisko testowe Middleware Database Storage Clustered (2 node) Weblogic Server 10.3 initial/maximal connection pool of 200 connections/database (100 physical connections per database instance) Oracle 10GR2 RAC database, OS: Solaris 10, Hardware: 2 x Sun T5220. Storage: High-end class storage Application for generating of the load DVD Store - JEE compliant application deployed on the clustered WLS servers OPITZ CONSULTING Kraków 2011 Strona 4
Profil obciążenia select INST_ID, decode(command_type,2,'insert',3,'select',6,'update') type, sum(fetches), sum(executions), sum(cpu_time), sum(rows_processed) from gv$sqlarea where PARSING_SCHEMA_NAME='DS2' and command_type in (2,3,6,7) group by INST_ID, command_type order by INST_ID,command_type INST_ID TYPE SUM(FETCHES) SUM(EXECUTIONS) SUM(CPU_TIME) SUM(ROWS_PROCESSED) ------- ------ ------------ --------------- ------------- ------------------- 1 INSERT 0 62032 65801909 209057 1 SELECT 366825 216934 4233908440 1839480 1 UPDATE 0 19323 46564670 92917 2 INSERT 0 68379 161967276 229583 2 SELECT 399063 238030 4660019826 1985351 2 UPDATE 0 21333 50369385 101946 1839480 [rows processed] / 216934 [executions of "select query"] = 8.47 [rows per select] Średnio 8.47 [wierszy na operację select] - mamy do czynienia z typową aplikacją typu OLTP OPITZ CONSULTING Kraków 2011 Strona 5
2 Opis problemu OPITZ CONSULTING Kraków 2011 Strona 6
Opis problemu Czas trwania testu: ok. 30 minut. W okolicach (chwilę po) 5:00 mamy wyraźny peak oczekiwań klasy CLUSTER. Analiza migawki AWR sekcji zapytań SQL wykazała, że odpowiedzialne za to jest zapytanie... OPITZ CONSULTING Kraków 2011 Strona 7
Winowajcą jest.. select count(*) from ds2.orders ; Krótka analiza: Tego typu zapytanie powinno skorzystać z indeksu na kluczu PRIMARY. Nie powinna zatem istnieć potrzeba sięgnięcia do bloków tabeli ORDERS (FAST FULL INDEX SCAN). Tak więc... zapytanie powinno zwrócić wynik prawie natychmiast! OPITZ CONSULTING Kraków 2011 Strona 8
Analiza problemu pierwsze spojrzenie SQL> select count(*) from ds2.orders ; Elapsed: 00:00:34.42 Execution Plan ------------------------------------------------------------------------------------------------------------------------ Id Operation Name Rows Cost (%CPU) Time Pstart Pstop TQ IN-OUT PQ Distrib ------------------------------------------------------------------------------------------------------------------------ 0 SELECT STATEMENT 1 6 (0) 00:00:01 1 SORT AGGREGATE 1 2 PX COORDINATOR 3 PX SEND QC (RANDOM) :TQ10000 1 Q1,00 P->S QC (RAND) 4 SORT AGGREGATE 1 Q1,00 PCWP 5 PX BLOCK ITERATOR 1207K 6 (0) 00:00:01 1 26 Q1,00 PCWC 6 TABLE ACCESS FULL ORDERS 1207K 6 (0) 00:00:01 1 26 Q1,00 PCWP ------------------------------------------------------------------------------------------------------------------------ Statistics ---------------------------------------------------------- 4591 recursive calls 3 db block gets 21617 consistent gets 0 physical reads 3740 redo size 518 bytes sent via SQL*Net to client 488 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 88 sorts (memory) 0 sorts (disk) 1 rows processed OPITZ CONSULTING Kraków 2011 Strona 9
3 Analiza problemu OPITZ CONSULTING Kraków 2011 Strona 10
Analiza problemu istnieje INDEX na kluczu gł. SQL> exec dbms_metadata.get_ddl(.) ; CREATE TABLE "DS2"."ORDERS" ( "ORDERID" NUMBER NOT NULL ENABLE, "ORDERDATE" DATE NOT NULL ENABLE, "CUSTOMERID" NUMBER, "NETAMOUNT" NUMBER(12,2) NOT NULL ENABLE, "TAX" NUMBER(12,2) NOT NULL ENABLE, "TOTALAMOUNT" NUMBER(12,2) NOT NULL ENABLE, CONSTRAINT "PK_ORDERS" PRIMARY KEY ("ORDERID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "INDXTBS" ENABLE, CONSTRAINT "FK_CUSTOMERID" FOREIGN KEY ("CUSTOMERID") REFERENCES "DS2"."CUSTOMERS" ("CUSTOMERID") ON DELETE SET NULL DISABLE ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE( BUFFER_POOL DEFAULT) TABLESPACE "ORDERTBS" PARTITION BY RANGE ("ORDERDATE") (PARTITION "JAN2004" VALUES LESS THAN (TO_DATE(' 2004-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) ( ) TABLESPACE "ORDERS_JAN2004" NOCOMPRESS, PARTITION "FEB2004" VALUES LESS THAN (TO_DATE(' 2004-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) ( ) ( ) (other partitions ) ( ) PARTITION "MAXVAL" VALUES LESS THAN (MAXVALUE) OPITZ CONSULTING Kraków 2011 Strona 11
Analiza problemu użyjmy podowiedzi (hint) i wymuśmy INDEX (FAST) FULL SCAN SQL> select /*+ index(orders PK_ORDERS) */ count(*) from ds2.orders; Elapsed: 00:00:02.86 Execution Plan ---------------------------------------------------------------------- Id Operation Name Rows Cost (%CPU) Time ---------------------------------------------------------------------- 0 SELECT STATEMENT 1 3420 (3) 00:00:54 1 SORT AGGREGATE 1 2 INDEX FULL SCAN PK_ORDERS 1423K 3420 (3) 00:00:54 ---------------------------------------------------------------------- Statistics ------------------------------------------ 1 recursive calls 0 db block gets 4335 consistent gets 4480 physical reads 0 redo size 518 bytes sent via SQL*Net to client 488 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed Rzeczywiście... Z hintem: Elapsed: 00:00:02.86 Bez hintu: Elapsed: 00:00:34.42 OPITZ CONSULTING Kraków 2011 Strona 12
Analiza problemu dlaczego optymalizator wybiera tak nieefektywny plan??? 10053 is your friend.. SQL> alter session set events '10053 trace name context forever, level 2 Tutaj: old school - alter session set events '10053 trace name context forever, level 2. Alternatywnie: dbms_system.set_ev() Dobry artykuł: http://www.petefinnigan.com/ramblings/how_to_set_trace.htm OPITZ CONSULTING Kraków 2011 Strona 13
Analiza problemu - 10053 SINGLE TABLE ACCESS PATH Table: ORDERS Alias: ORDERS Card: Original: 1207210 Rounded: 1207210 Computed: 1207210.00 Non Adjusted: 1207210.00 Q: dlaczego optymalizator preferuje FTS z użyciem opcji PARALLEL (i koszcie: 6,39)? Access Path: TableScan Cost: 1472.06 Resp: 6.39 Degree: 0 Cost_io: 1410.00 Cost_cpu: 181081500 Resp_io: 6.12 Resp_cpu: 785944 Access Path: index (index (FFS)) Index: PK_ORDERS resc_io: 749.00 resc_cpu: 177670962 ix_sel: 0.0000e+00 ix_sel_with_filters: 1 Access Path: index (FFS) Cost: 809.89 Resp: 809.89 Degree: 1 Cost_io: 749.00 Cost_cpu: 177670962 Resp_io: 749.00 Resp_cpu: 177670962 Access Path: index (FullScan) Index: PK_ORDERS resc_io: 3420.00 resc_cpu: 279905125 ix_sel: 1 ix_sel_with_filters: 1 Cost: 3515.92 Resp: 3515.92 Degree: 1 Best:: AccessPath: TableScan Cost: 6.39 Degree: 256 Resp: 6.39 Card: 1207210.00 Bytes: 0 Dlaczego koszt Resp_cpu (użycia CPU z dostępem PARALLEL) jest około 230 razy niższy niż Cost_cpu (z dostępem SERIAL)? 181081500 / 785944 = ~230 Obliczone DEGREE (of parallelism) = 256 OPITZ CONSULTING Kraków 2011 Strona 14
Analiza problemu parametry odpowiedzialne za przetwarzanie równoległe SQL> select OWNER, TABLE_NAME, DEGREE from dba_tables where owner = 'DS2' and TABLE_NAME = 'ORDERS'; OWNER TABLE_NAME DEGREE ------------------------- -------------------------------------- ----- DS2 ORDERS DEFAULT SQL> show parameter parallel NAME TYPE VALUE ------------------------------------ ----------- --------- parallel_adaptive_multi_user boolean TRUE parallel_automatic_tuning boolean TRUE parallel_execution_message_size integer 2152 parallel_max_servers integer 1280 parallel_server boolean TRUE Ponieważ DEGREE = DEFAULT obowiązują ustawienia na poziomie 1. sesji (u nas nie istnieją) 2. instancji SQL> show parameter cpu NAME TYPE VALUE ------------------------------------ ----------- ----------- cpu_count integer 64 parallel_threads_per_cpu integer 2 Max. # of Parallel Servers = min ( parallel_max_servers, (cpu_count * parallel_threads_per_cpu) ) = 128 2 nodowy klaster, zatem: 256 OPITZ CONSULTING Kraków 2011 Strona 15
Analiza problemu gv$px_session podczas wykonywania analizowanego zapytania SQL> select inst_id, sid, qcsid, server#, degree, req_degree from gv$px_session where QCSID = 2503 order by INST_ID, SERVER# ; INST_ID SID QCSID SERVER# DEGREE REQ_DEGREE ---------- ----------- ---------- ---------- --------------- ---------- 1 3139 2503 1 256 256 1 3113 2503 2 256 256 ( ) 1 3211 2503 126 256 256 1 3224 2503 127 256 256 1 3209 2503 128 256 256 2 2399 2503 129 256 256 2 1744 2503 130 256 256 ( ) 2 2663 2503 254 256 256 2 396 2503 255 256 256 2 3169 2503 256 256 256 2 2503 2503 257 rows selected. Mechanizm zapytania równoległego na RAC: QC (query coordinator, SID 2503) otrzymuje dane do scalenia przez interconnect od 128 serwerów zapytania równoległego pracujących na instancji #1 OPITZ CONSULTING Kraków 2011 Strona 16
Analiza problemu coraz bliżej... Zaraz, zaraz... zapytanie uruchamiamy na maszynach SUN T5220 opartych o technologię Chip Multi-Threading (MTS), tzn. 64 sprzętowych wątkach w obrębie jednego fizycznego CPU! I tak też został ustawiony parametr cpu_count (cpu_count = 64) finalnie odpowiedzialny za stopień równoległości zapytań opartych na obiektach, dla których DEGREE = DEFAULT. OPITZ CONSULTING Kraków 2011 Strona 17
4 Tuning OPITZ CONSULTING Kraków 2011 Strona 18
Możliwości optymalizacji 1. Wbudować hint na stałe 2. Zmienić parametr DEGREE dla tabeli ORDERS 3. Skierować zapytanie do jednego (wybranego) węzła klastra 4. Połączyć (2) i (3) 5. Ustawić OPTIMIZER_INDEX_COST_ADJ ( = 100?) Żadne (poza ostatnim) z powyższych nie uzdrowi sytuacji globalnie. Na początek należy dać znać optymalizatorowi, że nie ma do dyspozycji 64 jednostek, które mogą przetwarzać podobne zapytania równolegle: SQL> alter system set parallel_max_servers=8 scope=both sid='*' ; SQL> alter system set parallel_threads_per_cpu=1 scope=both sid='*' ; OPITZ CONSULTING Kraków 2011 Strona 19
Wyniki po zmianie parallel_max_servers=8 i parallel_threads_per_cpu=1 (Tuning) SQL> select count(*) from orders; COUNT(*) ---------- 1423615 Elapsed: 00:00:03.21 Execution Plan ------------------------------------------------------------------------------------------------------------------------ Id Operation Name Rows Cost (%CPU) Time Pstart Pstop TQ IN-OUT PQ Distrib ------------------------------------------------------------------------------------------------------------------------ 0 SELECT STATEMENT 1 18 (6) 00:00:01 1 SORT AGGREGATE 1 2 PX COORDINATOR 3 PX SEND QC (RANDOM) :TQ10000 1 Q1,00 P->S QC (RAND) 4 SORT AGGREGATE 1 Q1,00 PCWP 5 PX BLOCK ITERATOR 1423K 18 (6) 00:00:01 1 26 Q1,00 PCWC 6 TABLE ACCESS FULL ORDERS 1423K 18 (6) 00:00:01 1 26 Q1,00 PCWP ------------------------------------------------------------------------------------------------------------------------ Statistics ---------------------------------------------------------- 6296 recursive calls 4 db block gets 11241 consistent gets 8755 physical reads 672 redo size 518 bytes sent via SQL*Net to client 488 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 120 sorts (memory) 0 sorts (disk) 1 rows processed Znacznie lepiej, Elapsed = ~ 3 sec. W dalszym ciągu jednak FTS. OPITZ CONSULTING Kraków 2011 Strona 20
gv$px_session podczas wykonywania analizowanego zapytania po zmianie parametrów SQL> r 1 select QCINST_ID, INST_ID, SID, QCSID, SERVER#, DEGREE from gv$px_session where QCSID = 3239 order by INST_ID, SERVER#; INST_ID SID QCSID SERVER# DEGREE ---------- ------------ ---------- ---------- ------------ 1 3213 3239 1 16 1 3230 3239 2 16 1 3223 3239 3 16 1 3224 3239 4 16 1 3232 3239 5 16 1 3203 3239 6 16 1 3220 3239 7 16 1 3201 3239 8 16 2 3171 3239 9 16 2 3174 3239 10 16 2 3170 3239 11 16 2 3173 3239 12 16 2 3169 3239 13 16 2 3172 3239 14 16 2 3178 3239 15 16 2 3167 3239 16 16 2 3239 3239 17 rows selected. gv$px_session potwierdza, tym razem tylko 8 slaves/node (wcześniej 128!) OPITZ CONSULTING Kraków 2011 Strona 21
Bloki w tabeli I indeksie Można jeszcze raz 10053, ale sprawdźmy najpierw ilość bloków w obu segmentach... SQL> select owner, blocks from dba_tables where owner = 'DS2' and TABLE_NAME like 'ORDERS'; OWNER BLOCKS ------------------------- ---------- DS2 8905 SQL> select OWNER,INDEX_NAME, LEAF_BLOCKS from dba_indexes where owner = 'DS2' and INDEX_NAME ='PK_ORDERS'; OWNER INDEX_NAME LEAF_BLOCKS ------------------------- ---------------------------------------- ----------- DS2 PK_ORDERS 4401 Różnica nie powala na kolana, a więc... OPITZ CONSULTING Kraków 2011 Strona 22
Tuning Równoległy dostęp do indeksu...a więc pozwólmy skorzystać optymalizatorowi również z indeksu w sposób równoległy: SQL> alter index ds2.pk_orders parallel (degree default) ; Index altered. SQL> alter system flush buffer_cache ; System altered....i wykonajmy zapytanie raz jeszcze: OPITZ CONSULTING Kraków 2011 Strona 23
Plan wykonania po ostatnich zmianach SQL> select count(*) from orders; COUNT(*) ---------- 1423615 Znowu postęp: 1. Plan wykonania optymalny 2. Response time zadawalający (?) Elapsed: 00:00:02.05 Execution Plan ------------------------------------------------------------------------------------------------------------ Id Operation Name Rows Cost (%CPU) Time TQ IN-OUT PQ Distrib ------------------------------------------------------------------------------------------------------------ 0 SELECT STATEMENT 1 9 (12) 00:00:01 1 SORT AGGREGATE 1 2 PX COORDINATOR 3 PX SEND QC (RANDOM) :TQ10000 1 Q1,00 P->S QC (RAND) 4 SORT AGGREGATE 1 Q1,00 PCWP 5 PX BLOCK ITERATOR 1423K 9 (12) 00:00:01 Q1,00 PCWC 6 INDEX FAST FULL SCAN PK_ORDERS 1423K 9 (12) 00:00:01 Q1,00 PCWP Statistics ---------------------------------------------------------- 48 recursive calls 0 db block gets 6817 consistent gets 4404 physical reads 0 redo size 518 bytes sent via SQL*Net to client 488 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 1 rows processed OPITZ CONSULTING Kraków 2011 Strona 24
5 Podsumowanie OPITZ CONSULTING Kraków 2011 Strona 25
Podsumowanie Czy wynik można uznać za zadawalający? Raczej nie... To samo zapytanie pod znaczącym obciążeniem: SQL> select count(*) from orders; COUNT(*) ---------- 1423615 Elapsed: 00:00:04.08 Execution Plan ------------------------------------------------------------------------------------------------------------ Id Operation Name Rows Cost (%CPU) Time TQ IN-OUT PQ Distrib ------------------------------------------------------------------------------------------------------------ 0 SELECT STATEMENT 1 9 (12) 00:00:01 1 SORT AGGREGATE 1 2 PX COORDINATOR 3 PX SEND QC (RANDOM) :TQ10000 1 Q1,00 P->S QC (RAND) 4 SORT AGGREGATE 1 Q1,00 PCWP 5 PX BLOCK ITERATOR 1423K 9 (12) 00:00:01 Q1,00 PCWC 6 INDEX FAST FULL SCAN PK_ORDERS 1423K 9 (12) 00:00:01 Q1,00 PCWP Całość z interpretacją (ang.) http://www.opitz-consulting.pl/?id=127 lub http://www.ploug.org.pl/plougtki.php?action=read&p=52&a=7 OPITZ CONSULTING Kraków 2011 Strona 26
Kontakt Piotr Sajda Kierownik Service Engineering OPITZ CONSULTING Kraków piotr.sajda@opitz-consulting.com tel. +48 12 617 1810 tel. kom. +48 519 309 710 OPITZ CONSULTING Kraków 2011 Strona 27
Pytania/Odpowiedzi OPITZ CONSULTING Kraków 2011 Strona 28