Optimizacin de Consultas
Trataremos de Orientarlo a Desarrolladores
Es un tema que tiene muchos Sub-temas
Algunos subtemas estn fuera del scope de tareas
de un desarrollador.
Configuracin de Posgresql,
Analyze (actualizar estadsticas)
Vamos a ver:
Algunas formas de monitorear queries
Explain y Explain/Analyze
Algunos ejemplos de queries y como los optimizamos
Optimizacin de Consultas
Conceptos Generales
Antes de ir a Postgres, veamos algo general de ndices y del optimizador
Trade off Teora / Prctica
Explain y Explain Analyze
Explain = Plan de Acceso + Pronstico
Explain Analyze = Plan de Acceso + Pronstico + Realidad
Tipos de Accesos de Postgres
Sequencial, Indexado, Mltiple Indice, Nested Loop Join, Hash Join,
Subqueries correlacionados
Monitoreo de queries
Psql (poco pgadminIII)
Formas de JOIN
JOIN Tradicional, INNER JOIN, OUTER JOIN
Que diferencias hay ?
Es alguno ms performante ?
Optimizacin de Consultas - Indices
Indices Btree+ Soportan eficientemente bsquedas por igualdad y rangos
Where legajo = 123
Where salario > 8000
Son los ms usados (en Postgres y otras bases)
Existen otros tipos de ndices (R-Tree,hash,Gin)
Indice Btree
Tiempo de Optimizacin
(eleccion del plan de Tiempo de Ejecucin
acceso optimo)
Los costos son valores arbitrarios
para que cierre el ejemplo (puede
Tiempo Total del Query haber inconsistencias)
Optimizador basado en costos (2/3)
SELECT T1.A, T1.B, T2.C, T2.D Indices Disponibles:
FROM T1, T2 Ix1: clave T2.A
WHERE T1.A = T2.A and T1.E > 100 AND T2.F = 06-04-2014
TENEMOS DOS
INDICES A LOS
Plan
Plan 5 Optimo
PLANES ANTERIOES
C. Total: 350
SE AGREGAN
ALGUNOS MAS Filtro T2.F=06-04-2014
Costo: 100
Plan 1 Plan 4
C. Total: 6800 C. Total: 1650
Junta por Nested Loop
Join T1.A =T2.A
Plan 2 Costo: 200
C. Total: 3100
Plan 3 Filtro T1.E > 100 via
C. Total: 1900 Indice T1.E
Costo:50
Tiempo de Optimizacin
(eleccion del plan de Tiempo de Ejecucin
acceso optimo)
Los costos son valores arbitrarios
para que cierre el ejemplo (puede
Tiempo Total del Query haber inconsistencias)
Index Matching Ejemplos
Tabla negocio.sga_alumnos
Alumno legajo Propuesta Plan_version ubicacion Modalidad Division Anio_cursada readmisiones Regular calidad
Dado el query:
SELECT * FROM sga_alumnos Claves de Indices
WHERE legajo = 1111 en sga_alumnos
Legajo
AND modalidad = P
Persona
Calidad
De los ndices que existen cuales puedo usar el planner ? Modalidad
Puedo usar idx Es bueno ? Comentarios Plan version
legajo Si !! Trae 1 fila, y luego verifico el filtro Propuesta
de modalidad = P Ubicacion
modalidad Maso Trae muchas filas y luego en cada Persona, propuesta
una verifico el filtro legajo = 1111
Dado el query:
Claves de Indices
SELECT * FROM sga_alumnos en sga_alumnos
Legajo
WHERE modalidad = P
Persona
AND anio_cursada = 2014 Calidad
Modalidad
De los ndices que existen cuales puedo usar ? Plan version
Puedo usar idx Es bueno ? Comentarios Propuesta
modalidad Maso Trae muchas filas y luego en cada una Ubicacion
verifico el filtro anio_cursada = 2014
Persona, propuesta
Hay algn ndice para crear que pueda mejorar ?
Puedo usar idx Es bueno ? Comentarios
Anio_cursada Si (no es Trae algunas filas y luego en cada
super) una verifico el filtro modalidad = P
Index Matching Ejemplos
Tabla negocio.sga_alumnos
Alumno legajo Propuesta Plan_version ubicacion Modalidad Division Anio_cursada readmisiones Regular calidad
Dado el query:
Claves de Indices
SELECT * FROM sga_alumnos en sga_alumnos
Legajo
WHERE legajo > 0
Persona
AND apellido = Perez Calidad
Modalidad
De los ndices que existen cuales puedo usar ? Plan version
Puedo usar idx Es bueno ? Comentarios Propuesta
legajo Malo Trae todas las filas y luego en cada Ubicacion
(con >0) una verifico el filtro apellido = Perez
Persona, propuesta
Apellido mejor Trae solo los Perez
apellido
Queda para otra oportunidad ver como se activa. Naturalmente en produccin debera
desactivarse.
Postgres Query Log (1/1)
Para activarlo es necesario configurar el SQL query
logging, en el postgresql.conf con el parmetro :
0 Indica loggear todos los queries.
-1 deshabilita el log.
log_min_duration_statement = 0 otro valor (ej.300) solo logea
aquellos queries cuya duracin
exceda 300 milisegundos.
Pg_stat_statements (1/5)
Extension para agrupar los queries que recibe la base
Permite conocer de cada query:
Cuntas veces se lo ejecuta,
Cunto tiempo acumulan todas sus ejecuciones
Se instala asi:
1- Modificar parmetro en el postgresql.conf
shared_preload_libraries = 'pg_stat_statements'
2- Bajar y subir postgres
3- En la base de datos que deseo monitorear ejecutar:
CREATE extension pg_stat_statements;
en el postgresql.conf
Monitoreo de Queries
Conclusiones
Ventajas Desventajas
Pg_stat_activity Facil de Usar Es una foto de los queries en
ejecucin.No tiene los
queries que ya terminaron
LOG de postgres Podemos ver la historia, los Requiere un poco de
queries que ya terminaron, y configuracin y buscar en el
su duracin. log generado por postgres.
Queries rpidos que se
ejecutan muchas veces, no
los veo
Pg_stat_statement Muestra historia y queries Requiere configurar y agregar
actuales. Incluye la cantidad una extensin en la base de
de veces que se ejecut un datos. Y ejecutar un query
query y duracin total. para obtener los resultados
Puede detectar queries
relativamente rpidos que se
ejecutan muchas veces
Anlisis de Queries
Arranquemos con casos de una sola tabla para
graficar algunas ideas:
SELECT * FROM mdp_personas WHERE email_valido = 1
SELECT * FROM mdp_personas WHERE apellido = Perez
Como ya vimos Postgres tiene 2 formas de
acceder a mdp_personas:
Secuencial (no es bueno, pero a veces no queda otra)
Usando un Indice (si existe alguno que le sirva)
Existen varias formas de usar ndices para acceder a tablas
Cuando el query tiene varias tablas se combinan !!
EXPLAIN de Queries
Si anteponemos EXPLAIN al query vemos el plan de acceso
generado por el planner (solo pronsticos, no ejecuta el query)
SELECT * FROM mdp_personas WHERE email_valido = 0
Que hubiera pasado si existieran 2 ndices: uno por dni y otro por codpostal ?
- 2 Posibles Planes de acceso. Cual es el menos costoso en trminos de lectura ?
- Habr alguna otra forma de acceder por ndice cuando hay 2 ndices?.
Ejemplo Where nombre = juan and codpostal = 1661
Plan-reading is an art that deserves an extensive tutorial, which this is not; but
here is some basic information.
Anlisis de Queries
Acceso por indice, filtrando por otra condicion
(Similar al anterior) y luego con un sort
Tambin lo tenemos en formato grafico en el
PGAdminIII
Bitmap Index Scan
To combine multiple indexes, the system scans each needed index and prepares a bitmap in memory giving the locations of table rows that are reported as matching that
index's conditions. The bitmaps are then ANDed and ORed together as needed by the query. Finally, the actual table rows are visited and returned. Por ejemplo: Un qury con
WHERE x = 42 OR x = 47 OR x = 53 OR x = 99 could be broken down into four separate scans of an index on x, each scan using one of the query clauses. The results of these
scans are then ORed together to produce the result.
Si tenemos 2 indexes uno con clave x y el otro con clave y . Un query con WHERE x = 5 AND y = 6 puede hacer 2 index scans en cada indice y luego combinar los resultados
mediante un AND.
Indices Funcionales
SELECT codpostal FROM LOCALIDADES
WHERE upper(nombre) = MAR DEL PLATA
QUERY PLAN
---------------------------------------------------------------------------------
Bitmap Heap Scan on rrhh_cargos (cost=851.82..64504.40 rows=48943 width=6)
(actual time=24.000..184.007 rows=46974 loops=1)
Recheck Cond: (cod_rrhh_importacion = 6656)
-> Bitmap Index Scan on rrhh_cargos_imp (cost=0.00..839.58 rows=48943
width=0) (actual time=20.000..20.000 rows=46974 loops=1)
Index Cond: (cod_rrhh_importacion = 6656)
Total runtime: 312.010 ms
QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on rrhh_cargos (cost=0.00..105526.25 rows=13646 width=6) (actual
time=360.011..2176.070 rows=46974 loops=1)
Filter: ((cod_rrhh_importacion - 2) = 6654)
Total runtime: 2204.071 ms
Indices Funcionales Un EjemploReal
Dado este query
http://comunidad.siu.edu.ar/foro/index.php?topic=8823
Subquery Correlacionado (Caso real) 2/5
Subquery Correlacionado (Caso real) 3/5
Subquery Correlacionado (Caso real 4/5)
Subquery Correlacionado (Caso real 5/5)
COMPARANDO LOS EXPLAINS DE (USANDO www.explain.depesz.com)
SIN INDICE
CON INDICE
REVISAR SI VA !!Aplanar
subqueries(FROM-list subquery example)
El optimizador puede cambiar el query internamente
SELECT *
FROM t1, (SELECT * FROM t2 WHERE t2.x = 10) t2
WHERE t1.id = t2.id;
-- converted by the optimizer into
SELECT *
FROM t1, t2
WHERE t1.id = t2.id and t2.x = 10
Juntas
Si tenemos una junta entre 2 tablas con una
condicion de junta T1.A = T2.B
Es conveniente tener 2 ndices: T1(A) y T2(B)
El optimizador usar uno solo, pero tendr ms
opciones o planes para analizar
Postgres tiene 3 tcnicas o mecanismos para
resolver las JUNTAS:
NESTED LOOP JOIN
HASH JOIN
SORT MERGE JOIN
SI no hay ndices, Postgres deber usar HASH o
SORT MERGE.
Juntas
SELECT * FROM T1, T2
WHERE T1.PK = T2.FK
Tipos de Joins
Nestloop: Es el ms utilizado. Primero recorre una tabla (T1) y por cada fila ,
busca en la segunda tabla (T2) (usando un ndice) las filas que cumplen
T2.FK = T1.PK
Merge: Ambas tablas son ordenadas por las columnas del JOIN (T1.PK y
T2.FK) y luego se scanean en paralelo y se detectan las filas que hacen
JOIN (No es performante, revela falta de ndices)
Hash: Una de las tablas se scanea y se crea una tabla de HASH, usando las
columnas del JOIN como claves de HASH. Luego la otra tabla se escanea
y se aplica la funcion de HASH a las columnas del JOIN, con ese
resultado se busca en la tabla de HASH las filas que hacen JOIN (No es
performante, revela falta de ndices)
SET enable_nestloop = off; --permite ver q se hara en otro caso
SET enable_hashjoin = off;
SET enable_mergejoin= off;
Juntas
select *
FROM PERSONAS P INNER JOIN LOCALIDAD L ON L.codpostal = P.codpostal
WHERE L.nombre = localidad2341;
select *
FROM PERSONAS P INNER JOIN LOCALIDAD L USING (codpostal)
WHERE L.nombre = localidad2341;
select *
FROM PERSONAS P NATURAL JOIN LOCALIDAD L
WHERE L.nombre = localidad2341;
El uso del OUTER puede imponer un orden en la forma que se accede a tablas. Por ejemplo si tenemos
SELECT * FROM A LEFT OUTER JOIN (B join C on (b.ref = c.id) ) ON (A.id = B.id)
Tiene que resolver el primero el JOIN entre B y C y luego el JOIN entre A y B+C
http://comunidad.siu.edu.ar/foro/index.php?topic=8823
Demo 1 Subquery Correlacionado
cd /home/demo/test/mapuche
Ejecutamos ./q1.sh y vemos la salida
Ejecutamos time ./q1.sh y vemos cuanto demora
Ejecutamos ./qex1.sh y vemos que el Subplan se
resuelve con una busqueda sequencial.
More creaidx.sh para ver el indice que vamos a crear
Ejecutamos ./creaidx.sh y creamos el indice
Ejecutamos ./q1.sh y vemos que trae las mismas filas
pero ms rpido
Ejecutamos time ./q1.sh y comparamos los tiempos
Demo2 Queries en el FROM (qry_dnp_mal.sh) 1 Vez por Row
Demo2 Queries en el FROM (qry_dnp_ok.sh)
1 Vez por query. (No
es correlacionado)
Demo 2 Uso de Queries en el FROM
cd /home/demo/test/pilaga
Ejecutamos ./qry_dnp_mal.sh y vemos la salida
Ejecutamos time ./qry_dnp_mal.sh y vemos cuanto demora
Ejecutamos time ./qry_dnp_ok.sh y vemos cuanto demora.
Ejecutamos time ./qry_dnp_ok.sh > /dev/null y vemos cuanto
demora. La diferencia es el trafico de las filas
Ejecutamos time ./qry_exp_dnp_mal.sh y vemos cuanto demora
Ejecutamos time ./qry_exp_ana_dnp_mal.sh y vemos cuanto
demora
guarani_3_10=# \d test;
Tabla public.test
Columna | Tipo | Modificadores
---------+-----------------------------+---------------
nombre | character varying(30) |
nacim | timestamp without time zone |
ndices:
"testix1" btree (nacim)
guarani_3_10=# explain select nombre,nacim from test where nacim::date = '02-07-2015' limit 3 ;
QUERY PLAN
--------------------------------------------------------------
Limit (cost=0.00..12.54 rows=3 width=18)
-> Seq Scan on test (cost=0.00..209.00 rows=50 width=18)
Filter: ((nacim)::date = '2015-07-02'::date)
(3 filas)
cost -> costo en traer una pagina (constante 1.0 en seq scan)
rows -> en filas
width -> en bytes
Anlisis de Consultas
Ejemplo de barrido Secuencial
(Los barridos secuenciales suelen ser ineficientes, recorren toda la tabla)
cost -> costo en traer una pagina (constante 1.0 en seq scan)
rows -> en filas
width -> en bytes
Query1.sql
ndices
En las hojas del rbol el optimizador debe decidir
cual es la mejor forma de acceder a cada tabla
Barrido Secuencial ?
Acceso Indexado ?
Qu ndices me permite usar Postgres ?
CREATE [ UNIQUE ] INDEX [CONCURRENTLY] name ON table
[USING method] ({ column | ( expression )}
[WITH (storage_parameter = value [, ... ] )]
[TABLESPACE tablespace ]
[ WHERE predicate ]
ndices (7)
387 294 A
> 293
292 292
T
97
O
95
292 S
89
89
59
57
56
Query1.sql
Anlisis de Consultas
Acceso Index Bitmap
Puede acceder a una tabla usando 2 ndices, luego obtener la
interseccin de los punteros
EXPLAIN ANALYZE select * from CENSO2012 where nacimiento=14-01-1995
and codpostal = 9993;
Query3.sql
Anlisis de Consultas
Acceso Index Bitmap
Cuando se accede a una tabla por un ndice, y se espera que
muchas filas sean recuperadas, es conveniente partir el
acceso a la tabla en 2 etapas:
Acceder primero por el ndice recuperando todos los punteros a las filas.
Ordenar dichos punteros de acuerdo a la posicin fsica de la fila a recuperar
EXPLAIN ANALYZE select * from CENSO2012 where nacimiento=14-01-1995;
Query3.sql
EXPLAIN Vs EXPLAIN ANALYZE
El mismo query ejecutado con EXPLAIN y con EXPLAIN ANALYZE
Costo en unidades tericas Tiempo de ejecucin en mseg
Anlisis de Consultas
SELECT * FROM T1, T2
WHERE T1.PK = T2.FK
Tipos de Joins
Nestloop: Es el ms utilizado. Primero recorre una tabla (T1) y por cada fila ,
busca en la segunda tabla (T2) (usando un ndice) las filas que cumplen
T2.FK = T1.PK
Merge: Ambas tablas son ordenadas por las columnas del JOIN (T1.PK y
T2.FK) y luego se scanean en paralelo y se detectan las filas que hacen
JOIN (No es performante, revela falta de ndices)
Hash: Una de las tablas se scanea y se crea una tabla de HASH, usando las
columnas del JOIN como claves de HASH. Luego la otra tabla se escanea
y se aplica la funcion de HASH a las columnas del JOIN, con ese
resultado se busca en la tabla de HASH las filas que hacen JOIN (No es
performante, revela falta de ndices)
SET enable_nestloop = off; --permite ver q se hara en otro caso
SET enable_hashjoin = off;
SET enable_mergejoin= off;
Anlisis de Consultas
Nested Loop Join
Notar que si por algn motivo tenemos que buscar por dni_propietario en vehculos,
no tenemos un ndice
Control de la Integridad Referencial
Los INSERT en vehculo tienen que verificar si
Existe el DNI en propietario, para lo cual tienen un
ndice (la PK)
Los DELETES en propietario tienen que verificar si
Existe alguna referencia a la fila a borrar en
vehculo, para lo cual NO hay un ndice
Los DELETES en propietario se pueden volver
muuuy lentos, si tenemos muchas filas en
vehculos.
Control de la Integridad Referencial
EJEMPLO: Un DELETE que borra 5000 filas tarda 8 minutos,
porque tiene que validar la FK y no tiene ndice.
Control de la Integridad Referencial
Alternativas para acelerar que los DELETES en
propietario
Le ponemos un ndice a vehculos
Desactivamos las FKs durante el DELETE
Varias FORMAS de desactivar las constraints:
PONER LA EN MODO DEFERED (difiere el control al momento del
commit)
DROPEAR y RECREAR CONSTRAINT (controla la FK al recrearla)
DESHABILITAR LOS TRIGGERS (no se controla la FK mientras se
deshabilitan)
alter table propietario disable trigger all
antes de 8.1 hacer un:
update pg_class set reltriggers=0 where relname = propietario';
Control de la Integridad Referencial
Si desactivamos los trigggers antes, el DELETE se ejecuta en
0.5 segs. Pero no se controla la FK durante el DELETE
Control de la Integridad Referencial
Borrando y re-creando la
FK. EL Delete tarda 1.5
seg. Al recrear la FK
controla que los datos
existentes la cumplan. La
tabla con la FK tiene
500.000 filas
Window Functions
Son funciones similares a las funciones de agregacin. Pero tienen la
ventaja de que NO obligan a agrupar filas (mediante group by) en una
sola fila. As cada fila es independiente de las demas, aunque la window
function claramente acceder a otras filas aparte de la row corriente para
hacer sus clculos
En el ejemplo vemos que tenemos el promedio de salario por depto, junto
con los datos de cada empleado. Con un group by no podriamos
obtenerlo ya que deberiamos agrupar por deptname y no podriamos
traer empno y salary
Window Functions
La diferencia con las funciones de agrupacin es que siempre la window
funtion va acompaada de un OVER, el cual indica o define cual ser la
ventana (como se agrupan las filas del query).
La clusula PARTITION BY EXPRESION agrupa las filas que tienen el
mismo valor en expresin. Para cada fila del SELECT se calcula la
window function usando todas las filas que estn en el mismo grupo que
la fila corriente
Window Functions
Window functions are permitted only in the SELECT list and the
ORDER BY clause of the query. They are forbidden elsewhere, such
as in GROUP BY, HAVING and WHERE clauses. This is because
they logically execute after the processing of those clauses.
Anlisis de Consultas (3)
ndices (10)
Hash
Implementacin de las dispersiones (Hashing) lineales de
Litwin
Es el indicado cuando la clave del ndice no se repite y la
bsqueda es por un valor nico
En diferentes foros indican que los ndices Hash son
claramente deficientes frente a B-tree (en PostgreSQL)
=
GiST y GIN
Son usadas en sistemas de informacin geogrfica.
Es una forma mas generalizada de los R-Tree
ndices en Order By (8)
R-tree
ndices (11)
ndices (2)
- Si falla
ndices incompletos e inutilizables.
Puede pasar de que quede la constraint UNIQUE
Multiples ndices
given an index on (a, b) a query condition like WHERE a = 5 AND b = 6 could use the index, but a query like WHERE a = 5 OR b = 6 could
not directly use the index.
Fortunately, PostgreSQL has the ability to combine multiple indexes The system can form AND and OR conditions across several index
scans.
For example, a query like WHERE x = 42 OR x = 47 OR x = 53 OR x = 99 could be broken down into four separate scans of an index on x,
each scan using one of the query clauses. The results of these scans are then ORed together to produce the result.
Another example is that if we have separate indexes on x and y, one possible implementation of a query like WHERE x = 5 AND y = 6 is
to use each index with the appropriate query clause and then AND together the index results to identify the result rows.
To combine multiple indexes, the system scans each needed index and prepares a bitmap in memory giving the locations of table rows
that are reported as matching that index's conditions. The bitmaps are then ANDed and ORed together as needed by the query. Finally,
the actual table rows are visited and returned.
The table rows are visited in physical order, because that is how the bitmap is laid out; this means that any ordering of the original
indexes is lost, and so a separate sort step will be needed if the query has an ORDER BY clause. For this reason, and because each
additional index scan adds extra time, the planner will sometimes choose to use a simple index scan even though additional indexes are
available that could have been used as well.
In all but the simplest applications, there are various combinations of indexes that might be useful, and the database developer must
make trade-offs to decide which indexes to provide. Sometimes multicolumn indexes are best, but sometimes it's better to create
separate indexes and rely on the index-combination feature. For example, if your workload includes a mix of queries that sometimes
involve only column x, sometimes only column y, and sometimes both columns, you might choose to create two separate indexes on x
and y, relying on index combination to process the queries that use both columns. You could also create a multicolumn index on (x, y).
This index would typically be more efficient than index combination for queries involving both columns, but as discussed in Section
11.3, it would be almost useless for queries involving only y, so it should not be the only index. A combination of the multicolumn index
and a separate index on y would serve reasonably well. For queries involving only x, the multicolumn index could be used, though it
would be larger and hence slower than an index on x alone. The last alternative is to create all three indexes, but this is probably only
reasonable if the table is searched much more often than it is updated and all three types of query are common. If one of the types of
query is much less common than the others, you'd probably settle for creating just the two indexes that best match the common types.
Esquemas de las tablas del ejemplo