Carregar apresentação
A apresentação está carregando. Por favor, espere
PublicouGabrielhenrique Cecilio Alterado mais de 9 anos atrás
1
BD I / 2013-02 Processamento de Consultas Prof. Altigran Soares da Silva IComp/UFAM
2
Processamento de Consultas Q Plano de execução da consulta Foco: Sistemas relacionais Outros?
3
Exemplo Select B,D From R,S Where R.A = “c” and S.E = 2 and R.C=S.C
4
RABC S CDE a11010x2 b12020y2 c21030z2 d23540x1 e34550y3 ResultadoB D 2 x
5
Como executar a consulta? - Fazer produto cartesiano - Selecionar as tuplas - Fazer projeção Uma idea
6
RXSR.AR.BR.CS.CS.DS.E a 1 10 10 x 2 a 1 10 20 y 2. C 2 10 10 x 2. Uma resposta..
7
Álgebra Relacional – pode ser usada para descrever planos de execução Ex: Plano I B,D R.A =“c” S.E=2 R.C=S.C X RS OU: B,D [ R.A=“c” S.E=2 R.C = S.C (RXS)]
8
Outra ideia: B,D R.A = “c” S.E = 2 R S Plano II Junção natural
9
R S A B C ( R ) ( S ) C D E a 1 10 A B C C D E 10 x 2 b 1 20c 2 10 10 x 2 20 y 2 c 2 10 20 y 2 30 z 2 d 2 35 30 z 2 40 x 1 e 3 45 50 y 3
10
Plano III Usar os índices sobre R.A e S.C (1) Usar o indíce sobre R.A para selecionar as tuplas onde R.A = “c” (2) Para cada valor de R.C, usar o índice sobre S.C para achar as tuplas de S (3) Eliminar as tuplas de S onde S.E 2 (4) Aplicar o Join sobre as tuplas de R e S e projetar os atributos B e D
11
R S A B C C D E a 1 10 10 x 2 b 1 20 20 y 2 c 2 10 30 z 2 d 2 35 40 x 1 e 3 45 50 y 3 AC I1I1 I2I2 =“c”=“c” E=2? saida: prox. tupla:
12
Otimização de Consulta Determinar qual o “melhor” entre os vários possíveis planos de execução de uma consulta
13
parse convert regras Est. tamanho Comp. planos físicos Custos estimados melhor execução {P1,P2,…..} {(P1,C1),(P2,C2)...} Pi resposta Consulta SQL parse tree plano lógico p/ a consulta Plano “melhorado” Plano + tamanho estatísticas
14
Exemplo: Consulta SQL SELECT title FROM StarsIn WHERE starName IN ( SELECT name FROM MovieStar WHERE birthdate LIKE ‘%1960’ ); Encontrar os filmes cujos atores nasceram em 1960
15
Examplo: Parse Tree SELECT FROM WHERE IN title StarsIn ( ) starName SELECT FROM WHERE LIKE name MovieStar birthDate ‘%1960’
16
Examplo: Álgebra Relacional title StarsIn IN name birthdate LIKE ‘%1960’ starName MovieStar
17
Examplo: Plano lógico da consulta title starName=name StarsIn name birthdate LIKE ‘%1960’ MovieStar Aplicando regra para condições “IN”
18
Examplo: Plano Melhorado title starName=name StarsIn name birthdate LIKE ‘%1960’ MovieStar
19
Examplo: Estimado tamanhos de resultados tamanho estimado StarsIn MovieStar
20
Examplo: Possível plano físico Parâmetros: ordem da junção, tamanho da mem, atributos,... Hash join SEQ scanindex scan Paramêtro: Condiçaõ de seleção,... StarsInMovieStar
21
Example: Custo estimado L.Q.P P1 P2 …. Pn C1 C2 …. Cn Escolha o melhor!
22
Estrutura desta Unidade Capitulo 6 6.1 Álgebra para consultas [“bags” vs sets] - Seleção, projeção, junção, … - Elminação de duplicatas, agrupamento, ordenação 6.2Operadores físicos - Varredura (Scan), ordenação, … 6.3-6.10 Implementação de operadores + estimativa de curstos
23
Capítulo 7 7.1Parsing 7.2Leis da Álgebra 7.3Parse tree -> Plano lógico de consulta 7.4Estimativa do tamanho de resultados 7.5-7 Otimização baseada em custos
24
Estudo do Livro Texto - Capítulos 6,7 Opcionais: 6.8, 6.9, 6.10, 7.6, 7.7 Eliminação de duplicadas, agrupamento e agregação
25
Otimização de consultas - Níveis Nível de álgebra relacional Nível do plano de consulta detalhado Estimativa de custos Sem índices Com índices Gerar e comparar planos
26
Otimização em Álgebra Relacional Regras de transformação Preservando equivalência O que são boas transformações?
27
Leis Associativas e Comutativas Produtos R x S = S x R (R x S) x T = R x (S x T) Junções Naturais R S = S R (R S) T = R (S T) Uniões e Intersecções R U S = S U R R U (S U T) = (R U S) U T
28
Junções Teta Comutativa R C S = S C R Não é associativa: Seja R(a,b), S(b,c) e T(c,d) (R R.b>S.b S) a S.b (S a<d T)
29
Seleções Tendem a reduzir bastante o tamanho das relações Portanto, em geral, devem ser processados antes dos outros operadores, ou seja, nos níveis mais baixos da árvore Regras da álgebra são usadas para “quebrar” condições complexas e aumentar as oportunidades de “descidas” na árvore
30
Seleções - Regras p1 p2 (R) = p1vp2 (R) = p1 [ p2 (R)] = p2 [ p1 (R)] [ p1 (R)] U [ p2 (R)]
31
Bags vs. Conjuntos R = {a,a,b,b,b,c} S = {b,b,c,c,d} R U S = ? Opção 1: R U S = {a,a,b,b,b,b,b,c,c,c,d} Opção 2: R U S = {a,a,b,b,b,c,c,d}
32
Efeito da opção 2 p1vp2 (R) = p1 (R) U p2 (R) Exemplo R={a,a,b,b,b,c} P1 satisfeita por a,b; P2 satisfeita por b,c p1vp2 (R) = {a,a,b,b,b,c} p1 (R) = {a,a,b,b,b} e p2 (R) = {b,b,b,c} p1 (R) U p2 (R) = {a,a,b,b,b,c}
33
Opção 1 – Mais interessante Senador (……)Deputado (……) T1 = ano,estado Senador; T2 = ano,estado Deputado T1 Ano Estado T2 Ano Estado 97 AM 99 AM 99 AM 99 AM 98 SP 98 AM União?
34
Projeções Notação Para X e Y sendo conjuntos de atributos XY = X U Y xy (R) ≠ x [ y (R)]
35
p (R S) = [ p (R)] S p = predicado com atributos de R q (R S) = R [ q (S)] q = predicado com atributos de S Objetivo é “adiantar” as seleções para antes da junção
36
Derivações p q (R S) = [ p (R)] [ q (S)] p q m (R S) = m [ ( p R) ( q S) ] pvq (R S) = [ ( p R) S ] U [ R ( q S) ]
37
Regras: combinados Sejam x = subconjunto dos atributos de R z = atributos do predicado de P (subconjunto dos atribs de R) x [ p ( R ) ] = { p [ x ( R ) ] } x x xz
38
Sejam x = subconjunto dos atributos de R y = subconjunto dos atributos de S z = interseção dos atributos de R e S xy (RS) = xy {[ xz (R) ] [ yz (S) ]}
39
Projeções Notação Para X e Y sendo conjuntos de atributos XY = X U Y xy (R) ≠ x [ y (R)]
40
Regras: combinados Sejam x = subconjunto dos atributos de R z = atributos do predicado de P (subconjunto dos atribs de R) x [ p (R)] = { p [ x ( R ) ] } x x xz
41
p (R U S) = p (R) U p (S) p (R - S) = p (R) - S = p (R) - p (S) Regras U combinadas:
42
p1 p2 (R) p1 [ p2 (R)] p (R S) [ p (R)] S R S S R x [ p (R)] x { p [ xz (R)] } Quais são as boas transformações?
43
Convenção: Projeções ocorrem antes Exemplo: R(A,B,C,D,E) x={E} P: (A=3) (B=“gato”) x { p (R)} vs. E { p { ABE (R)} }
44
E se houverem indíces em A, B? B = “gato” A=3 fazer a interseção de apontadores para encontrar os apontadores que levam as tuplas desejadas
45
Limites para aplicação de regras: Nenhuma transformação por aplicação da regra é sempre boa No entanto, executar seleções mais cedo é geralmente melhor
46
Mais transformações no livro texto Eliminação de sub-expressões comuns Outras operações: eliminação de duplicatas
47
Onde estamos Processamento de Consultas Nível da Álgebra Relacional transformações boas transformações Nível de plano de consulta detalhado estimativa de custos gerar e comparar planos
48
Estimativa de Custos (1) Estimativa do tamanho dos resultados (2) Estimativa do nr. de operações de E/S
49
Tamanho do resultado Para obter estimativas do tamanho do resultado, manter estatísticas para cada relação R T(R) : # tuplas em R S(R) : # bytes em cada tupla de R B(R): # blocos p/ armazenar todas as tuplas de R V(R, A) : # valores distintos em R p/ o atrib. A
50
Exemplo RA: 20 bytes string B: 4 bytes inteiro C: 8 bytes data D: 5 bytes string ABCD cat110a cat120b dog130a dog140c bat150d T(R) = 5 S(R) = 37 V(R,A) = 3V(R,C) = 5 V(R,B) = 1V(R,D) = 4
51
Estimativa de tamanho para W = R1 x R2 T(W) = S(W) = T(R1) T(R2) S(R1) + S(R2)
52
S(W) = S(R) T(W) = ? Estimativa de tamanho p/ W = A=a (R)
53
Exemplo RV(R,A)=3 V(R,B)=1 V(R,C)=5 V(R,D)=4 W = z=val (R) T(W) = ABCD cat110a cat120b dog130a dog140c bat150d T(R) V(R,Z)
54
Hipótese: Valores na expressão de seleção Z = val são uniformemente distribuídas sobre os possíveis valores de V(R,Z)
55
O que acontece com W = z val (R) ? T(W) = ? Solução 1: Há 50% de chance da tupla satisfazer a condição T(W) = T(R)/2 Solução 2: Intuitivamente, menos que a metade satisfaz T(W) = T(R)/3
56
Solução # 3: Estimar faixas de valores Examplo R Z Min=1 V(R,Z)=10 W= z 15 (R) Max=20 f = 20-15+1 = 6 (fração dentro da faixa) 20-1+1 20 T(W) = f T(R)
57
Ou, alternativamente: f V(R,Z) = fração de valores distintos T(W) = [f V(Z,R)] T(R) = f T(R) V(Z,R)
58
Estimativa de Tamanho para W = R1 R2 Seja x = atributos de R1 y = atributos of R2 x y = Mesmo que R1 x R2 Caso 1
59
W = R1 R2 x y = A R1 A B C R2 A D Caso 2 Hipóteses: V(R1,A) V(R2,A) Cada valor de A em R1 está em R2 V(R2,A) V(R1,A) Cada valor de A em R2 está em R1 Lembrete: V(R,A) = nr. de valores distintos de A em R
60
R1 A B C R2 A D Cálculo de T(W) se V(R1,A) V(R2,A) Tome 1 tupla compara 1 tupla casa com T(R2) tuplas... V(R2,A) Logo, T(W) = T(R2) T(R1) V(R2, A)
61
V(R1,A) V(R2,A) T(W) = T(R2) T(R1) V(R2,A) V(R2,A) V(R1,A) T(W) = T(R2) T(R1) V(R1,A) [A é o atributo comum]
62
T(W) = T(R2) T(R1) max{ V(R1,A), V(R2,A) } Em geral W = R1 R2
63
Hipótese Alternativa Valores uniformemente distribuídos sobre o domínio R1 ABC R2 A D Uma tupla casa com T(R2)/DOM(R2,A) tupla, então T(W) = T(R2) T(R1) = T(R2) T(R1) DOM(R2, A) DOM(R1, A) Caso 2 Assume-se que é o mesmo domínio
64
Em todos os casos: S(W) = S(R1) + S(R2) - S(A) Lembrete = S é o tamanho da tupla
65
Usando ideias similares é possível estimar os tamanhos de: AB (R) ….. Seção 7.4.2 A=a B=b (R) …. Seção 7.4.3 R S com vários atributos comuns …. Seção 7.4.5 União, Intersecção, Diferença, …. Seção 7.4.7
66
Nota: Para expressões complexas, estimar tamanhos de valores intermediários Ex.: W = [ A=a (R1) ] R2 Tratar como uma relação U T(U) = T(R1)/V(R1,A) S(U) = S(R1) V (U, *) = ???? …
67
Estimando os V (U,*) Ex., U = A=a (R1) Suponha que R1 tem atributos A,B,C,D V(U, A) = V(U, B) = V(U, C) = V(U, D) =
68
Exemplo R1V(R1,A)=3 V(R1,B)=1 V(R1,C)=5 V(R1,D)=3 U = A=a (R1) ABCD cat110 cat120 dog13010 dog14030 bat15010 V(U,A) =1 V(U,B) =1 V(U,C) = T(R1) V(R1,A) V(U,D)... algo entre os dois
69
Possíveis escolhas U = A=a (R) V(U,A) = 1 V(U,X)= V(R,X), X ≠ A
70
Para junções U = R1(A,B) R2(A,C) V(U,A) = min { V(R1, A), V(R2, A) } V(U,B) = V(R1, B) V(U,C) = V(R2, C) [Preservação de conjuntos de valores 7.4.4]
71
Exemplo: Z = R1(A,B) R2(B,C) R3(C,D) T(R1) = 1000 V(R1,A)=50 V(R1,B)=100 T(R2) = 2000 V(R2,B)=200 V(R2,C)=300 T(R3) = 3000 V(R3,C)=90 V(R3,D)=500 R1 R2 R3
72
T(U) = 1000 2000 V(U,A) = 50 200 V(U,B) = 100 V(U,C) = 300 Resultado Parcial: U = R1 R2
73
Z = U R3 T(Z) = 1000 2000 3000 V(Z,A) = 50 200 300 V(Z,B) = 100 V(Z,C) = 90 V(Z,D) = 500
74
Sumário Estimar o tamanho dos resultados é uma “arte” Não esquecer: Estatísticas devem ser mantidas (custo?)
75
Visão Geral Estimando o custo dos plano de consulta [feito!] Estimando o tamanho dos resultados [feito!] [próximo!] Estimando o número de op. de ES [próximo!] Gerando e comparando planos
76
--> Geração e compraração de planos Consulta GeraçãoPlanos Poda x x Estimativa de Custo Custos Seleção Otimização de Consultas Escolher mínimo
77
Para gerar planos deve-se considerar: Transformações nas expressão da Algebra (e.x. ordem das junções) Uso dos índices existentes Construções de índices ou ordenação das consultas em tempo de processamento
78
Detalhes de implementação: ex. – Algoritmo de junção - Gerenciamento de Memória - Processamento paralelo
79
Estimando custos de E/S: Contagem do nr. blocos de disco que devem ser lidos ou escritos para executar o plano de consulta
80
Para estimar estes custos, parâmetros adicionais são necessários: B(R) = nr. de blocos que contêm as tuplas de R f(R) = nr. max de tuplas de R por bloco M = nr. de blocos de memória disponíveis HT(i) = nr. de níveis no índice i LB(i) = nr. de blocos folha no índice i
81
Índices de Clustering Indíces que permitem que as tuplas sejam lidas na ordem em que ocorrem fisicamente A Índice A 10 15 17 19 35 37
82
Noçoes de clustering Clustered file organization ….. Clustered relation ….. Clustering index R1 R2 S1 S2R3 R4 S3 S4 R1 R2 R3 R4R5 R5 R7 R8
83
Exemplo R1 R2 sobre um atributo comum C T(R1) = 10.000 T(R2) = 5.000 S(R1) = S(R2) = 1/10 blocos Mémoria disponível = 101 blocos Metrica: nr. de ESs (ignorando a escrita do resultado)
84
Cuidado! Essa pode não ser a melhor maneira de comparar Ignora custos de CPU Ignora temporização Ignora requisitos de “double buffering”
85
Opções Transformações: R1 R2, R2 R1 Algoritmos de junção: Iteração (loops aninhados) Merge Join Join com Indices Hash join
86
Iteração (conceitualmente) para cada r R1 faça para cada s R2 faça se r.C = s.C então retorne
87
Iteração motivação Otimizador usa iteração quando nós temos tabelas usando junção que possuem poucas tuplas.
88
Hash join (conceitualmente) Função de hashing h, valores entre 0 k Buckets para R1: G0, G1,... Gk Buckets para R2: H0, H1,... Hk Algoritmo (1) Tuplas de R1 nos buckets G (2) Tuplas de R2 nos buckets H (3) Para i = 0 até k faça comparar as as tuplas dos buckets Gi e Hi
89
Exemplo simples hash: para/impar R1R2Buckets 2 5Par: 4 4 R1 R2 3 12Impar: 5 3 813 9 8 11 14 2 4 84 12 8 14 3 5 95 3 13 11
90
Hash Join Motivação Hash joins são usados quando existe junções de grandes tabelas. O otimizador usa a tabela menor das duas tabelas para construir uma tabela hash em memória, e faz a varredura na tabela maior e compara com o valor de hash com esta tabela hash para encontrar as linhas que pertencem a junção.
91
Merge join (conceitualmente) (1) se R1 e R2 não ordenados, ordene-os (2) i 1; j 1; enquanto (i T(R1)) (j T(R2)) faça se R1{ i }.C = R2{ j }.C then RetorneTuplas i,j senão se R1{ i }.C > R2{ j }.C então j j+1 senão se R1{ i }.C < R2{ j }.C então i i+1
92
Procedimento RetorneTuplas Enquanto (R1{ i }.C = R2{ j }.C) (i T(R1)) faça jj j; enquanto (R1{ i }.C = R2{ jj }.C) (jj T(R2)) faça retorne ; jj jj+1; i i+1;
93
Sort Merge Join Motivação Sort merge join funciona melhor que iteração quando o volume de dados é maior nas tabelas, mas não tão bom quanto um hash join em geral. Ele pode ser melhor que o hash join quando a junção tem as colunas já ordenadas ou a ordenação não é requerida.
94
Junção com Ìndice (Conceitualmente) Para cada r R1 faça [ X index (R2, C, r.C) para cada s X faça retorne ] Assuma índices sobre R2.C Nota: X index(rel, atr, valor) X = conjunto de tuplas de rel onde atr = valor
95
Fatores que afetam a performance (1) Tuplas da relação são armazenadas fisicamente juntas? (2) Relações são ordenadas pelo atributo de da junção? (3) Existem índices ?
96
Custo: para cada tupla de R1: [Leitura da tupla + Leitura de R2] Total =10.000 [1+5.000]=50.010.000 op. de ES Examplo 1(a): Junção por iteração R1 R2 Relações não contíguas T(R1) = 10.000; T(R2) = 5.000 S(R1) = S(R2) =1/10 blocos MEM=101 blocos
97
Pode-se fazer melhor? Usar a memória (1)Ler 100 blocos de R1 (2)Ler todos de R2 (usando 1 bloco) + join (3)Repetir até terminar
98
Custo: para ler cada porção de R1: Ler Porção de R1: 1000 Ler R2 : 5000 6000 Total = 10.000 x 6000 = 60,000 1.000
99
Reverter a ordem do join: R2 R1 Total = 5000 x (1000 + 10.000) = 1000 5 x 11.000 = 55.000 Pode-se fazer melhor?
100
Relações Contíguas Exemplo 1(b) Iteração R2 R1 Custo Para cada porção de R2: Ler porções: 100 ESs Ler R1: 1000 ESs 1.100 Total= 5 porções x 1.100 = 5.500 ESs
101
Exemplo 1(c) Merge Join R1 e R2 ordenados por C; relações contíguas Memória R1 R2 ….. R1 R2 Custo total: Custo de Ler R1 + Custo de Ler R2 = 1000 + 500 = 1.500 ESs
102
Example 1(d) Merge Join R1, R2 não ordenados, mas contiguos Necessário ordenar R1e R2 primeiro….
103
Uma maneira de ordenar: Merge Sort (i) Para cada 100 blocos de R: - Ler os 100 blocos - Ordenar na memória - Escrever no disco partes ordenadas Memória R1 R2...
104
(ii) Ler as partes + merge + escrever Ordenado Memória Partes Ordenadas...
105
Custo: Ordenação Cada tupla é lida,escrita, lida,escrita Portanto... Custo para ordenar R1: 4 x 1.000 = 4.000 Custo para ordenar R2: 4 x 500 = 2.000
106
Exemplo 1(d) Merge Join (continuação) R1,R2 contíguos, mais não ordenados Custo Total = custo de ordenação + custo de junção = 6.000 + 1.500 = 7.500 ESs Mas: Custo Iteração = 5.500 Portanto, merge join não compensa!
107
SuponhaR1 = 10.000 blocos contíguos R2 = 5.000 blocos não ordenados Iteração: 5000 x (100+10.000) = 50 x 10.100 100 = 505.000 ESs Merge join: 5(10.000+5.000) = 75.000 ESs Merge Join (com sort) VENCE!
108
Quanto de memória é necessária para o Merge Sort? Ex.: Suponha que temos 10 blocos 10... 100 partes O merge requer 100 blocos! R1
109
Em geral: k blocos na memória x blocos para ordenar a relação nr. de partes = (x/k) tamanho da parte = k nr. de partes < buffers disponíveis para merge portanto... (x/k) k ou k 2 x ou k x
110
Em nosso exemplo R1 tem 1000 blocos, k 31.62 R2 tem 500 blocos, k 22.36 São necessários pelo menos 32 buffers
111
Exemplo 1(e) Index Join Assuma que há um índice sobre R1.C 2 níveis Cabe na memória Assuma que R2 é contíguo, não ordenado
112
Custo: Leituras: 500 op de E/S Para cada tupla de R2: Se R2.C=R1.C – Verifica no índice → 0 op de E/S Ler tupla de R1 → 1 op de E/S
113
Qual o número esperado de tuplas para R2.C=R1.C? (a) Se R1.C é chave e R2.C é chave estrangeira nr. de tuplas esperadas é = 1 (b) Suponha que V(R1,C) = 5000, T(R1) = 10,000 com distribuição uniforme: nr. de tuplas esperadas é = 2
114
(c) Suponha que DOM(R1, C) = 1,000,000 T(R1) = 10,000 Com a hipótese alternativa nr. esperado de tuplas = 10,000 = 1 1,000,000 100 Qual o número esperado para R2.C=R1.C?
115
Custo total com index join (a) Custo total = 500+5000(1)1 = 5.500 (b) Custo total= 500+5000(2)1 = 10.500 (c) Custo total = 500+5000(1/100)1=550
116
E se o índice não cabe na memória? Exemplo: Suponha que o índice sobre R1.C ocupa 201 blocos Manter a raiz e 99 folhas na memória Os custo esperado de cada verificação é E = (0) 99 + (1)101 0.5 200 200
117
Custo total (incluindo verificações) Caso (b) : 2 tuplas esperadas = 500+5000 [verific. + carga de registros] = 500+5000 [0.5+2] = 500+12.500 = 13.000 op de E/S Caso (c) : 1/100 tuplas esperadas = 500+5000 [0.5 + (1/100) ] = 500+2500+50 = 3050 op de E/S
118
Até agora … Iteração 55.000 Merge Join _______ Sort+ Merge Join _______ R1.C Index _______ R2.C Index _______ Iteração 5500 Merge join 1500 Sort+Merge Join 7500 R1.C Index 5500 3050 550 R2.C Index ________ contíguos não contíguos R1 R2
119
R1, R2 contiguous (não ordenados) Usar 100 buckets Ler R1, hash, + escrever buckets R1 Exemplo 1(f) Hash Join... 10 blocos 100
120
→ O mesmo para R2 → Ler um bucket de R1; construi tabela hash na memória →Ler o correpondente de Re + verifica na tabela hash R1 R2... R1 memória... → Repetir para todos os buckets
121
Custo: Buckets Ler R1 + escrever Ler R2 + escrever Join:Ler R1, R2 Custo total = 3 x [1000+500] = 4500 Nota: isto é uma aproximação, uma vez que os buckets podem variar de tamanho e os blocos tem de estar completos
122
Requisitos mínimos de memória: Tamanho dos buckets de R1 =(x/k) k = nr. de buffers de memória x = número de blocos de R1 Assim: (x/k) < k k > x São necessários k+1 buffers
123
Sumário Iteração funciona bem para “pequenas” relações (relativo ao tamanho da memória) Para equi-junções onde as relações não estão ordenadas e não há índices, hash join é usualmente melhor Ordenação + merge join: bons para não equi- junções (ex. R1.C > R2.C) Se as relações já estão ordenadas, usar merge join Se existem índices, eles podem ser úteis, dependendo do tamanho esperado para os resultados
Apresentações semelhantes
© 2024 SlidePlayer.com.br Inc.
All rights reserved.