Descargar la presentación
La descarga está en progreso. Por favor, espere
1
Optimització de BDR (Oracle)
Toni Navarrete Enginyeria del Software II – UPF 2003
2
I si és millor no utilitzar-ne cap?
Introducció Si hi ha més d’un índex, com tria Oracle quin és el que ha d’utilitzar? I si és millor no utilitzar-ne cap? Podem escriure les consultes de forma que s’executin de forma més ràpida? Dues parts: Accés a les taules Joins
3
Com es processa una query
4
Com es processa una query
Creació d’un cursor El cursor és l’àrea de memòria que manté la definició d’un statement (sentència) SQL ja obert Parsejat Es comprova la sintaxi de la instrucció SQL i de les referències a objectes. Es comprova si ja ha estat parsejada abans (PreparedStatements) Binding de variables Es donen els valors a les variables Execució Si la instrucció és DML o DDL (no una consulta) s’executa Si és una consulta, es prepara el statement per recuperar les dades Fetch Recupera una o més files del result set (només si és una consulta) Quasi sempre és la més costosa
5
Parsejat L’ús de PreparedStatements millora molt aquesta fase
En aquesta fase també es decideix el pla d’execució (ho fa l’optimitzador d’Oracle) Hi ha un parámetre SESSION_CACHED_CURSORS que fa que es gestioni una caché de cursors També es pot forçar a que el parser substitueixi literals per variables de binding. Exemple: SELECT * FROM clients WHERE nom=‘pep s.a.’; Alter session set cursor_sharing=FORCE; ho transforma a: SELECT * FROM clients WHERE nom=:SYS_B_0;
6
Fetch 3 tipus d’accés a les taules: Table scan ROWID access
És llegeix cada fila de la taula a la memòria ROWID access És una pseudo-columna (tot i que no forma part de la taula, és pot fer un select sobre ella) Representa la localització física d’una fila És típicament la forma més ràpida d’accedir a una fila Típicament s’obté d’un índex B*-tree o bitmap Hi ha vàries formes de buscar dins l’índex Hash key access S’utilitza per accedir a clusters hash
7
Fetch 3 tècniques per fer joins:
Sort merge És un join sense utilitzar índexs: S’ordena cada taula a partir de la columna de join i s’ajunten en una única taula resultant Nested loops S’utilitza un índex almenys en una de les taules Es recuperen les files de la primera taula (potser fent un full-scan) i després es fa un lookup (=resolució) sobre la segona taula Hash join Es crea un hash per accedir a la taula més grosa a partir de la més petita (és una espècie d’índex creat on-the-fly) S’usa quan les taules són de tamany molt diferent Útil especialment si el hash cap en memòria Paràmetre de configuració SORT_AREA_SIZE Per a sorts (ORDER BY), agregacions (GROUP BY, DINSTINCT, MAX, COUNT,...) i operacions de conjunt (UNION, INTERSECT, MINUS)
8
Recordatori Joins Inner Join Outer Join (+) Self Join Conjunts (Sets)
Equijoin vs thetajoin Outer Join (+) Considerant també els valors que no tenen correspondència Nota: els drivers JDBC d’Oracle no soporten la notació OUTER JOIN (left outer join, right outer join, full outer join). Veure exemple a transp. següent Self Join Conjunts (Sets) UNION (i UNION ALL amb repeticions), MINUS, INTERSECT Operacions de grup AVG, COUNT, MAX, MIN, SUM, STDDEV...
9
Exemple d’outer join en les dues notacions
La següent query retorna els departaments i els seus empleats (incloent els departaments que no tenen cap empleat): SELECT ename, dname FROM {OJ dept LEFT OUTER JOIN emp ON dept.deptno = emp.deptno} FROM emp e, dept d WHERE e.deptno = d.deptno(+)
10
Algunes consideracions importants sobre l’ús d’índexs (d’arbre B*)
L’ordre és molt important quan es defineix un índex multiclau. No només es pot utilitzat l’índex “complet” (totes les columnes) També en parts, si es fa en l’ordre en que està definit Exemple: Si definim un índex amb tres claus (A,B,C) Si apareixen A, B i C al where, pot utilitzar l’índex sobre les 3 cols. Si apareixen A i B al where, pot utilitzar l’índex sobre A i B Si apareixen A i C al where, pot utilitzar l’índex només per A (no per C perquè prèviament hi ha B, que no surt al where) Si apareix B al where, no pot utilitzar l’índex Posar al davant els camps amb més probabilitat de sofrir cerques no conjuntes Quasi sempre es crearan índexs per a les foreign keys, per tal de millorar l’eficiència dels joins Els valors NULL no s’indexen Això és un problema si cerquem els valors nuls al where. En canvi, sí s’usarà l’índex si cerquem els NOT NULL
11
Oracle té dos optimitzadors:
L’optimitzador L’optimitzador determina la millor manera per processar una sentència SQL Oracle té dos optimitzadors: Basat en regles (rule-based) Té una sèrie de regles prefixades per fer les decissions. Per exemple, sempre preferirà un índex a un full-scan, però no distingeix entre fer un full-scan d’una taula de 2 files o de 2 milions de files Basat en el cost (cost-based) Usa principalment informació estadística relativa al volum de les dades i la distribució de les dades en les taules i índexs. Disponible des d’Oracle 7
12
Els dos optimitzadors d’Oracle
No són perfectes No fan miracles!! Cap dels dos permet: Re-escriure queries mal formulades Crear índexs L’optimitzador basat en regles és més predecible (i més segur) L’optimitzador basat en costos utilitza algorismes no públics Per un bon funcionament de l’optimitzador basat en costos cal recollir estadístiques periòdicament
13
Aspectes comuns dels dos optimitzadors
Transformacions de consultes equivalents IN passa a un inner join OR (no usa índexs) passa a UNION ALL “Select ... From nombre_vista Where ...”, se transforma al Select només utilitzant taules (sense vistes), a partir de la definició de la vista
14
Descripció del procés (per ambdòs optimitzadors)
Per a cada taula es consideren les opcions que hi ha per recuperar les dades S’analitza per quina taula començar i quin ordre seguir per fer el join Independentment de l’optimitzador, s’apliquen aquestes regles: Si un join resulta en una única fila (potser perquè ambdues taules tenen una clau primària o una constraint unique en el where), se li dóna preferència a aquest join Si hi ha un outer join, la taula externa (la que pot té files sense correspondència, la que porta el +) s’ajuntarà després de l’altra (la interna)
15
Seleccionant l’objectiu de l’optimitzador
Objectiu de l’optimitzador: quin enfocament utilitza l’opt. per decidir Hi ha quatre possibles valors: RULE CHOOSE (defecte) ALL_ROWS FIRST_ROWS Per seleccionar (tres formes): Paràmetre init.ora: optimizer_mode=FIRST_ROWS ALTER SESSION SET OPTIMIZER_GOAL=RULE Usant hints: SELECT /*+ ALL_ROWS */ id, nombre FROM alumne WHERE ...;
16
Ranking de l’optimitzador basat en regles
Single row by ROWID Single row by cluster join Single row by hash cluter key with unique or primary key Single row by unique or primary key Cluster join Hash cluster key Indexed cluster key Composite key (but only if all keys are used) Single column indexes Bounded range search on indexed columns Unbounded range search on indexed columns Sort-merge join MAX or MIN of indexed columns ORDER BY on indexed columns Full-table scan
17
Ranking de l’optimitzador basat en regles (resum)
Es prefereixen lookups que donen una sola fila que els que donen múltiples files Els índexs es prefereixen als full-scan de taules o als sort merges Es prefereixen lookups amb igualtat que amb rangs Rangs afitats (per exemple amb between) es prefereixen a rangs no afitats (>) Es prefereix utilitzar totes les columnes d’un índex concatenat (multiclau) a només algunes d’elles
18
Optimització basada en costos. Obtenció d’estadístiques
Sense estadístiques de les taules i índexs, l’optimitzador no pot decidir de forma precissa ANALYZE ANALYZE TABLE | INDEX | CLUSTER nom [ COMPUTE STATISTICS | ESTIMATE STATISTICS SAMPLE tamany [ROWS|PERCENT] ] Exemple: ANALYZE TABLE alumne COMPUTE STATISTICS; ESTIMATE STATISTICS SAMPLE 10 PERCENT; En el cas d’un índex es guarda a INDEX_STATS i d’una taula a DBA_TABLE
19
Optimització basada en costos. Obtenció d’estadístiques
Histograma de les columnes per tenir més detalls de com es distribueixen els valors: ANALYZE TABLE nom [ COMPUTE STATISTICS | ESTIMATE STATISTICS ...] {FOR COLUMNS llista_columnes | FOR ALL COLUMNS | FOR ALL INDEXED COLUMNS} SIZE n (n és el nombre de caixes de l’histograma) Exemple: ANALYZE TABLE matricula COMPUTE STATISTICS FOR COLUMNS assignatura_id SIZE 10;
20
Hints Introduint hints a les sentències SQL es poden forçar camins d’accés. Exemples: Select /*+ index(alumne) */ ... Fa que forçosament s’usi algun índex de la taula alumne Select /*+ index(alumne, ind_al_pk) */ ... Fa que forçosament s’usi l’índex ind_al_pk sobre la taula alumne La coma no és obligatòria Podrien haver més índexs en la llista Select /*+ full(alumne) */ ... Fa que forçossament es faci un full-scan de la taula alumne Select /*+ ordered */ ... Fa que forçossament el join s’executi en l’ordre en què esta especificat al FROM /*+ use_nl(...) */ fa que s’usi un nested loop /*+ use_merge(...) */ fa que es faci un merge
21
Com analitzar els plans de consulta
Pla de consulta: Com l’optimitzador executa una sentència SQL Analitzant el pla de consulta per una query podem descobrir problemes 3 eines: EXPLAIN PLAN SQL_TRACE I TKPROF AUTOTRACE
22
Explain plan Explain plan Set statement_id=‘cons_alumnes’ Into plan_table For select * from alumnes; (en vermell la consulta que es vol analitzar) Prèviament cal crear la taula plan_table
23
Taula de plan de consulta
CREATE TABLE PLAN_TABLE ( STATEMENT_ID VARCHAR2(30), TIMESTAMP DATE, REMARKS VARCHAR2(80), OPERATION VARCHAR2(30), OPTIONS VARCHAR2(30), OBJECT_NODE VARCHAR2(128), OBJECT_OWNER VARCHAR2(30), OBJECT_NAME VARCHAR2(30), OBJECT_INSTANCE NUMERIC, OBJECT_TYPE VARCHAR2(30), OPTIMIZER VARCHAR2(255), SEARCH_COLUMNS NUMBER, ID NUMERIC, PARENT_ID NUMERIC, POSITION NUMERIC, COST NUMERIC, CARDINALITY NUMERIC, BYTES NUMERIC, OTHER_TAG VARCHAR2(255), PARTITION_START VARCHAR2(255), PARTITION_STOP VARCHAR2(255), PARTITION_ID NUMERIC, OTHER LONG, DISTRIBUTION VARCHAR2(30));
24
Presentació de les dades del pla de consultes
select lpad(' ',2*(level-1))||operation||' '|| options, object_name "QUERY PLAN", cost, cardinality from plan_table start with id=0 and statement_id=‘cons_alumnes' connect by prior id=parent_id;
25
Presentació de les dades del pla de consultes. Operacions més freqüents
TABLE ACCESS (FULL) fila a fila (BY ROWID) s’accedeix a una fila a partir del seu rowid (CLUSTER) utilitzant un cluster INDEX (UNIQUE SCAN) retorna el rowid d’una única fila (RANGE SCAN) retorna el rowid de vàries files, ja sigui perquè l’índex no és unique o perquè s’utilitza un comparador en el where (FULL SCAN) recorre cada entrada de l’índex en ordre de clau (FAST FULL SCAN) recorre cada entrada de l’índex en l’ordre de bloc, possiblement usant lectures multi-bloc
26
Presentació de les dades del pla de consultes. Operacions més freqüents
Per fer els joins: MERGE JOIN s’ordena cada taula a partir de la columna de join i s’ajunten en una única taula resultant (no utilitza índex) NESTED LOOPS es recuperen les files de la primera taula i després es fa un lookup sobre la segona taula (s’usa un índex) HASH JOIN cada fila d’una banda (típicament la més petita) s’usa com a hash per accedir a files de l’altra (la més grossa). Es crea una espècie de índex on-the-fly SORT (ORDERED BY) resultat de la clàusula order by (JOIN) ordena els valors en preparació d’un merge join (UNIQUE) un sort per eliminar files duplicades, típic amb la clàusula distinct (AGGREGATE) amb una clàusula d’agregac. (GROUP BY) amb una clàusula group by
27
Presentació de les dades del pla de consultes. Exemple
SELECT STATEMENT MERGE JOIN SORT JOIN TABLE ACCESS FULL T2 TABLE ACCESS FULL T12 TABLE ACCESS FULL T1
28
Presentació de les dades del pla de consultes. Exemple
SELECT STATEMENT NESTED LOOPS INDEX UNIQUE SCAN PK1 INDEX RANGE SCAN PK12 TABLE ACCESS BY INDEX ROWID T2 INDEX UNIQUE SCAN PK2
29
Explain Plan dóna molt poques dades
SQL*TRACE i TKPROF Explain Plan dóna molt poques dades Amb SQL*TRACE podem obtenir informació sobre: Nombre de files processades Temps de CPU (en centèssimes de segon) Temps total invertit (en centèssimes de segon) Operacions d’accés a disc Lectures lògiques ... Divisió per fases (parse, execute, fetch)
30
SQL*TRACE i TKPROF alter session set sql_trace=true timed_statistics=true; select t2.* from t1,t12,t2 where t1.id1=1 and t12.id1=t1.id1 and t2.id2=t12.id2; alter session set sql_trace=true timed_statistics=false; Es genera un arxiu .trc a al directori del servidor %OracleHOME%/ADMIN/nom_bd/udump Després cal executar la comanda tkprof per generar una sortida llegible. Per exemple: tkprof ORA03072.TRC out.txt
31
SQL*TRACE i TKPROF. Exemple de sortida
select t2.* from t1,t12,t2 where t1.id1=1 and t12.id1=t1.id1 and t2.id2=t12.id2 call count cpu elapsed disk query current rows Parse Execute Fetch total Misses in library cache during parse: 1 Optimizer goal: CHOOSE Parsing user id: 37 Rows Row Source Operation 3 NESTED LOOPS 6 NESTED LOOPS 2 INDEX FAST FULL SCAN (object id 12260) 6 TABLE ACCESS FULL T2 3 INDEX UNIQUE SCAN (object id 12264) Nombre de files retornades Nombre de lectures de disc Nombre de blocs llegits, l’important és el total (“lectures lògiques”)
32
SQL*TRACE i TKPROF. Aspectes a tenir en compte
Pla d’execució de la consulta Relació entre els blocs lògics llegits (total query+total current) i les files processades (total rows) Quant més blocs s’han de processar per recuperar una fila, més costosa és l’operació Ratios per damunt de 10 a 20 indiquen que la consulta es pot millorar Excepcions, per exemple, casos com count(*) sempre retornen una fila, amb la qual cosa la relació és molt alta
33
SQL*TRACE i TKPROF. Aspectes a tenir en compte
Relació entre el cost de parsejar i d’executar Idealment el parse count hauria de ser 1 (o proper) Si és superior que el execute count, s’hauria de reescriure la consulta Relació entre lectures de disc i lectures lògiques S’ha de minimitzar el nombre de lectures de disc El rati hauria de ser inferior a un 10% (10 vegades més lectures lògiques que de disc) El contrari indica un mal ús de la caché Comprovar que no es processen més files que les que té la taula Això indicaria que estem recorrent diverses vegades la taula
34
AUTOTRACE Es pot fer des de SQL*PLUS
No és tan detallat com SQL*TRACE, però sí més que EXPLAIN PLAN També ha d’estar creada la taula PLAN_TABLE SET AUTOTRACE OFF ON EXPLAIN ON STATISTICS ON (ambdues) TRACEONLY
35
AUTOTRACE. Un exemple set autotrace on
select t2.* from t1,t12,t2 where t1.id1=1 and t12.id1=t1.id1 and t2.id2=t12.id2; Execution Plan SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=2 Bytes=56) NESTED LOOPS (Cost=2 Card=2 Bytes=56) NESTED LOOPS (Cost=2 Card=5 Bytes=80) INDEX (FAST FULL SCAN) OF 'PK1' (UNIQUE) (Cost=1 Card=1 Bytes=8) TABLE ACCESS (FULL) OF 'T2' (Cost=1 Card=5 Bytes=40) INDEX (UNIQUE SCAN) OF 'PK12' (UNIQUE) Statistics 0 recursive calls 8 db block gets 6 consistent gets 0 physical reads 0 redo size 1233 bytes sent via SQL*Net to client 715 bytes received via SQL*Net from client 4 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 3 rows processed
36
Segona part: Aplicació dels conceptes
Optimitzar l’accés a una taula Optimització d’índex amb arbre B* Optimització dels full-table-scan Optimitzar els joins (recordatori dels clusters i taules organitzades per índex)
37
Hints Introduint hints a les sentències SQL es poden forçar camins d’accés. Exemples: Select /*+ index(alumne) */ ... Fa que forçosament s’usi algun índex de la taula alumne Select /*+ index(alumne, ind_al_pk) */ ... Fa que forçosament s’usi l’índex ind_al_pk sobre la taula alumne La coma no és obligatòria Podrien haver més índexs en la llista Select /*+ full(alumne) */ ... Fa que forçosament es faci un full-scan de la taula alumne Select /*+ ordered */ ... Fa que forçosament el join s’executi en l’ordre en què esta especificat al FROM /*+ use_nl(...) */ fa que s’usi un nested loop /*+ use_merge(...) */ fa que es faci un merge
38
Optimitzant índexs amb arbre B*. Índexs concatenats
Sempre que sigui possible, incloure totes les columnes contingudes al WHERE L’ordre és important Primer la columna que té més probabilitat de ser accedida individualment Sobre-indexació Select cognom, nom, data_naimexement, telefon From alumne Where nom=‘Toni’ and cognom=‘Navarrete’ and data_naixement=to_date(‘ ’,’DD-MM-YYYY’); Això utilitza un índex (cognom,nom, data_naixement) Si afegim a l’índex la columna telefon ens estalvia haver d’accedir a la taula per saber el seu valor un cop obtenim de l’índex el Rowid En entorns transaccionals (OLTP) això pot arribar a suposar fins a un 20-25% de benefici
39
Optimitzant índexs amb arbre B*. Índex concatenats
Només cognom: 700 lectures lògiques 3 índex i després un merge: 40 l.l. Si les columnes tenen baixa cardinalitat (i en conseqüència se’n retornaran moltes files) pot ser molt pitjor Índex sobre cognom + nom: 20 l.l. Índex sobre cognom + nom + data_naixament: 6 l.l. Índex sobre cognom + nom + data_naixament + telefon: 4 l.l.
40
Optimitzant índexs amb arbre B*. Cerques per rang
Exemple: Select cognom from alumne where data_naixament > to_date(:data,’DD-MM-YYYY’); :data és una variable L’optimitzador no pot saber quin serà el valor de la variable, així que fa la suposició que el 5% de files serà el resultat de la query El pla d’execució serà: SELECT STATEMENT (Cost=326 Card=5000 Bytes=215000) TABLE ACCESS (BY INDEX ROWID) OF ‘ALUMNE’ (Cost=326 Card=5000) INDEX (RANGE SCAN) OF ‘ALUMNE_INDEX’ (Cost=13 Card=5000)
41
Optimitzant índexs amb arbre B*. Cerques per rang
Però si volem consultar els alumnes que van nèixer després de ‘ ’ això provocarà que es retornin totes les files Hagués estat millor usar un Full-table scan enlloc d’un índex Quan es fan consultes per rang és millor no usar variables de binding. Això incrementa el temps de parsejat però millora la decisió de l’optimitzador Sempre es pot forçar a que faci un full-table scan amb un hint si preveiem que serà necessari L’ús d’estadístiques per columnes (histogrames) també millora la decissió
42
Optimitzant índexs amb arbre B*. Cerques amb OR
Exemple Select id from municipi where nom=‘Santa Coloma’ or nom=‘Santa Coloma de Gramanet’ or nom=‘Sta. Coloma’ or nom=‘Sta. Coloma de Gramanet’ El pla d’execució serà: SELECT STATEMENT (...) TABLE ACCESS (FULL) OF ‘MUNICIPI) L’optimitzador prefereix fer un full-scan perquè estima que el resultat pot ser molt gran, quan nosaltres sabem que només serà una fila
43
Optimitzant índexs amb arbre B*. Cerques amb OR
Seria millor forçar a utilitzar l’índex sobre la columna nom i símplement concatenar les files resultants: Select /*+ USE_CONCAT INDEX(MUNICIPI MUN_NOM_IND)*/ id from municipi where nom=‘Santa Coloma’ or nom=‘Santa Coloma de Gramanet’ or nom=‘Sta. Coloma’ or nom=‘Sta. Coloma de Gramanet’ Resultat: SELECT STATEMENT CONCATENATION TABLE ACCESS (BY INDEX ROWID) OF ‘MUNICIPI’ INDEX (RANGE SCAN) OF ‘MUN_NOM_IND’ Seria UNIQUE si s’hagués declarat com a tal
44
Optimitzant índexs amb arbre B* INDEX FULL FAST SCAN
Exemple: Select count(*) from alumne; L’optimitzador triaria fer un Full table scan, perquè s’ha de recórrer tota la taula A més, es pot paral·lelitzar Hi ha una solució millor: Fer un full-scan de l’índex Raó: hi ha molts menys blocs! També és paral·lelitzable
45
Optimitzant índexs amb arbre B* INDEX FULL FAST SCAN
Comparant amb index scan “normal”: L’índex “normal” va posició a posició de l’índex, començant pel valor més petit de la clau, fins al més gran L’índex “normal” no és paral·lelitzable L’optimitzador ho considera a no ser que el paràmetre FAST_FULL_SCAN_ENABLED valgui FALSE Manualment: Select /*+ index_ffs(alumne, pk_alumne) */ count(*) from alumne; Quan utilitzar Index FFS? Quan totes les columnes resultants estan a l’índex Almenys una de les columnes és NOT NULL (recordatori: els NULLs no s’indexen!!) La query retorna més d’un 10-20% de les files (si no, es faria amb un índex scan “normal”)
46
Optimitzant full-table scans
Poden haver situacions en què no hi ha més remei que recórrer tota la taula: S’accedeix a un alt percentatge de files de la taula i un index ffs no és possible (bé perquè poden haver valors nuls o bé perquè cal retornar columnes que no estan a l’índex) Vist d’altra manera: s’accedeix a un gran nombre de blocs Els valors de blocs o % de files depenen molt de cada situació. Alguns parlen del 5% ó 25% de files, de 8 ó 16 blocs
47
Optimitzant full-table scans
L’objectiu és reduir el nombre de blocs que cal llegir Solucions: Baixar el high-water mark En Oracle només refent la taula Optimitzar els paràmetres d’emmagatzematge PCTFREE i PCTUSED Reduir el tamany de la fila (de-normalització) Multiblock read y block size Millorar el hit rate del buffer cache Usar l’opció Sample o Sample block Queries paral·leles
48
Optimitzant joins Tres tipus de joins
Sort merge Hash Nested loops Nested loop dóna millor temps de resposta, mentre que sort merge i hash donen millor throughput Com més gran sigui el conjunt de files a processar, el nested loops és més lent en comparació al sort merge o hash Nested loops només és aplicable si s’utilitza un índex per a unir les taules Sort merge necessita molta memòria. També, però no tanta, el hash join (per constuir la taula de hash) Tots poden ser paral·lelitzables, però el sort merge i hash milloren molt més (i tenen menys restriccions)
49
Optimitzant joins
50
Optimitzant joins. Triant sort merge o hash
Hash i sort merge tenen un comportament semblant, quan funciona bé un, funciona bé l’altre i viceversa Pràcticament sempre és més eficient un hash que un sort merge En canvi, l’algorisme de l’optimitzador (tant per cost com per regles) quasi sempre tria sort merge Forçar amb el hint USE_HASH(taula)
51
Optimitzant joins. Triant sort merge o hash
Exemple (un join de totes les files de venda i client): select nom_client, valor_venda from venda v, client c Where v.id_client=c.id_client; Pla d’execució: SELECT STATEMENT MERGE JOIN SORT (JOIN) TABLE ACCESS (FULL) OF ‘CLIENT’ TABLE ACCESS (FULL) OF ‘VENDA’ Millor forçant l’ús de hash join: select /*+ ordered use_hash(c) */ nom_client, valor_venda Where v.client_id=c.client_id; HASH JOIN
52
Optimitzant joins. Preferències dels modes de l’optimitzador
Mode de l’optimitzador: RULE: afavoreix nested-loops si hi ha índex i sort-merge si no FIRST_ROWS: normalment afavoreix nested-loops si hi ha índex i sort-merge si no ALL_ROWS: normalment tria un sort merge o un hash join CHOOSE: si hi ha estadístiques, igual que ALL_ROWS. Si no n’hi ha, igual que RULE
53
Optimitzant joins. Algunes regles bàsiques
Per a un nested-loop, assegurar que l’índex conté tantes columnes com sigui possible de la clàusula where. Si l’índex pot contenir també totes les columnes de la clàusula select, encara millor Nota: si la taula interior (la segona) d’un join nested-loop, no té índex i s’ha de recórrer amb full-scan, s’acabaran fent molts recorreguts complets de la taula Per a un sort-merge, optimitzar els paràmetres de sort de la BD: bàsicament SORT_AREA_SIZE; i també els paràmetres relatius a full-scan de les taules Per a un hash-merge, optimitzar els paràmetres que controlen la taula hash temporal (HASH_AREA_SIZE i HASH_MULTIBLOCK_IO_COUNT); també aquí els paràmetres relatius a full-scan de la primera taula HASH_MULTIBLOCK_IO_COUNT determina el nombre de blocs que s’escriuren o llegeixen en una única operació d’E/S
54
Optimitzant joins. L’ordre del join
Determinar el millor dels ordres en què es fa un join pot ser complexe. Per exemple, si 5 taules en un join hi ha 5! (120) possibilitats diferents Ambdòs optimitzadors fan errors El basat en cost perquè ha de fer suposicions sobre el cost de la ordenació, nombre de files a recuperar per un índex,... El basat en regles, perquè són regles estàtiques
55
Optimitzant joins. L’ordre del join
Exemple amb taules alumne, matrícula i assignatura: select /*+ordered */ * from assignatura, matricula, alumne where assignatura.as_ncredits=3 and matricula.ma_as_id=assignatura.as_id and alumne.al_id=matricula.ma_al_id; Cost 19 select /*+ordered */ * from matricula, alumne, assignatura where assignatura.as_ncredits=3 and matricula.ma_as_id=assignatura.as_id and alumne.al_id=matricula.ma_al_id; Cost 76 select /*+ordered */ * from alumne, assignatura, matricula where assignatura.as_ncredits=3 and Cost 1137 select /*+ordered */ * from alumne, matricula, assignatura where assignatura.as_ncredits=3 and Cost 64
56
Optimitzant joins. L’ordre del join
Alguns principis (que poden tenir excepcions): La primera taula del join (la taula conductora) hauria de ser la que té la clàusula where més selectiva i eficient. Així s’eliminen moltes files el més aviat possible i es redueix el nombre de files retornades a cada passa Si es fa el join de petits subconjunts de les taules involucrades, intentar usar nested loops per a cada join subsegüent si hi ha índex que ho suporta i si no, hash tables Assegurar-se que els índex que suporten els nested loops contenen totes les columnes del where per a la taula corresponent
57
Optimitzant joins. L’ordre del join
El mètode de join afecta l’ordre. Un exemple, amb files a la taula client i a la taule venda: Si el join és amb sort-merge, l’ordre és irrellevant Si el join és nested-loops basat en índexs, la taula interna (la segona) hauria de ser la més petita de les dues. La segona taula és la que més vegadas es recorrerà, ja sigui amb índex o no Si el join és hash, la interna (segona) també hauria de ser la més petita de les dues. El join hash funciona bé si la taula hash cap en memòria i és en la taula més petita. Si la taula és gran no hi cabrà. No obstant, si la taula és molt petita, no obtindrem cap benefici usant un hash
58
Optimitzant joins. L’ordre del join
Nested loop Client-venda: temps s Venda-client: temps s Hash join Client-venda: temps s Venda-client: temps s Millor opció: Select /*+ ORDERED USE_NL(C) */ nom_client, sum(valor_venda) From venda v, client c Where s.id_client = c.id_client Group by nom_client;
59
Optimitzant joins. L’ordre del join. Hints
ORDERED FULL, INDEX, HASH USE_NL, USE_MERGE, USE_HASH El paràmetre per als joins és respecte de la segona taula de la clàusula Exemple: SELECT /*+ ORDERED INDEX(P PK_PRODUCTE) USE_NL(V) USE_MERGE(C) */ p.descripcio_producte, v.data_venda, c.nom_client FROM producte p, venda v, client c WHERE p.id_producte=v.id_producte AND v.id_client=c.id_client;
60
Optimitzant joins. Clusters
L’ús dels clusters millora l’eficiència dels joins però empitjora la dels full-scans. Exemple: Select e.cognom, c.cognom From empleat e, client c Where e.id_empleat=c.empleat_responsable And e.id_empleat=20; Resultats (temps): Join: Sort-merge join: 2.44 s Nested loop join: 1.6 s Join amb cluster: 0.47 s Full-scan dela taula empleat: Sense cluster: 0.02 s Amb cluster: 0.65 s
61
Optimitzant joins. Índex “estrella”
Hi ha un cas habitualment on el model E-R pren la forma d’una estrella: no hi ha més relacions que amb una taula central (fact table) Per exemple: Producte Departament Venda Empleat
62
Optimitzant joins. Índex “estrella”
Una consulta com la següent pot ser molt costosa: Select sum(valor_venda) From departament d, empleat e, producte p, venda v Where p.descripcio=‘xxxx’ and e.cognom=‘García’ and e.nom=‘Manolo’ and d.nom=‘Bases de dades’ and p.id=v.id_producte and e.id=v.id_responsable and d.id=v.id_departament
63
Optimitzant joins. Índex “estrella”
Oracle té una manera eficient de fer-ho, amb el hint /*+ STAR */ Resultat (temps): Optimitzador basat en regles: s Optimitzador basat en cost (sense STAR): 3.43 s Usant el hint STAR: 0.06 s
64
Optimitzant joins i altres temes...
No hem vist: Subqueries (in, exists) Queries jeràrquiques Outer joins Altres temes (diferent dels joins): Agregacions i ordenaciones DML (inserts, updates, deletes) SQL paral·lel
65
Índexs sobre taules particionades (horitzontalment)
Si particionem la taula però no els índexs només treurem profit quan fem full-scan de la taula (o taules particionades) Per ser eficient, la partició de l’índex hauria de usar els mateixos rangs que les taules CREATE TABLE sales ( invoice_no NUMBER, sale_year INT NOT NULL, sale_month INT NOT NULL, sale_day INT NOT NULL ) STORAGE (INITIAL 100K NEXT 50K) LOGGING PARTITION BY RANGE ( sale_year, sale_month, sale_day) ( PARTITION sales_q1 VALUES LESS THAN ( 1999, 04, 01 ) TABLESPACE tsa STORAGE (INITIAL 20K, NEXT 10K), PARTITION sales_q2 VALUES LESS THAN ( 1999, 07, 01 ) TABLESPACE tsb, PARTITION sales_q3 VALUES LESS THAN ( 1999, 10, 01 ) TABLESPACE tsc, PARTITION sales q4 VALUES LESS THAN ( 2000, 01, 01 ) TABLESPACE tsd) ENABLE ROW MOVEMENT; CREATE INDEX month_ix ON sales(sale_month) GLOBAL PARTITION BY RANGE(sale_month) (PARTITION pm1_ix VALUES LESS THAN (2) PARTITION pm2_ix VALUES LESS THAN (3) PARTITION pm3_ix VALUES LESS THAN (4) PARTITION pm4_ix VALUES LESS THAN (5) PARTITION pm5_ix VALUES LESS THAN (6) PARTITION pm6_ix VALUES LESS THAN (7) PARTITION pm7_ix VALUES LESS THAN (8) PARTITION pm8_ix VALUES LESS THAN (9) PARTITION pm9_ix VALUES LESS THAN (10) PARTITION pm10_ix VALUES LESS THAN (11) PARTITION pm11_ix VALUES LESS THAN (12) PARTITION pm12_ix VALUES LESS THAN (MAXVALUE));
Presentaciones similares
© 2025 SlidePlayer.es Inc.
All rights reserved.