y Director Técnico en NOSYS • ¿Qué hacemos en NOSYS? ✔ Formación, consultoría y desarrollo de software con PostgreSQL (y Java) ✔ Partners de EnterpriseDB ✔ Formación avanzada en Java con Javaspecialists.eu: Java Master Course y Java Concurrency Course ✔ Partners de Amazon AWS. Formación y consultoría en AWS • Twitter: @ahachete • LinkedIn: http://es.linkedin.com/in/alvarohernandeztortosa/
nombre, que se pueden crear al vuelo para simplificar la escritura de consultas • Se utilizan con la cláusula WITH: ✔ puede haber tantas “vistas temporales” como se quiera ✔ se pueden hacer JOINs entre ellas y referenciar entre ellas también ✔ incluso a sí mismas, para dar lugar a la recursividad • Disponibles desde PostgreSQL 8.4 (escribibles desde 9.1)
(SELECT cols FROM tabla 2) AS tabla2 ON (…) JOIN (SELECT cols FROM tabla 3) AS tabla3 ON (…) WHERE … WITH tabla2 AS ( SELECT cols FROM tabla2 ), tabla3 AS ( SELECT cols FROM tabla3 ) SELECT cols FROM tabla1 INNER JOIN tabla2 ON (…) JOIN tabla3 ON (…) WHERE … l Sin CTEs CTEs (WITH)
WITH tabla (i) AS (SELECT 1) SELECT i FROM tabla; WITH seq (i) AS ( SELECT generate_series(1,10) ), seq2 (i) AS ( SELECT * FROM seq WHERE i%2=0 ) SELECT i FROM seq2 RIGHT OUTER JOIN seq ON (seq.i = seq2.i);
total_sales FROM orders GROUP BY region ), top_regions AS ( SELECT region FROM regional_sales WHERE tot_sales > ( SELECT SUM(tot_sales)/10 FROM regional_sales ) ) SELECT region, product, SUM(quantity) AS product_units, SUM(amount) AS product_sales FROM orders WHERE region IN (SELECT region FROM top_regions) GROUP BY region, product; http://www.postgresql.org/docs/9.3/static/queries-with.html
filas actualizadas WITH t AS ( UPDATE products SET price = price * 1.05 RETURNING * ) SELECT * FROM t; -- cuidado: “FROM t”, no “FROM products” -- Realizar varias operaciones al tiempo WITH moved_rows AS ( DELETE FROM products WHERE "date" >= '2010-10-01' AND "date" < '2010-11-01' RETURNING * ) INSERT INTO products_log SELECT * FROM moved_rows; http://www.postgresql.org/docs/9.3/static/queries-with.html
recursivas son difíciles de representar en RDBMSs • La solución “típica” es una tabla auto-referenciada, donde la FK apunta a la propia tabla • El problema es: ¿cómo realizar una consulta que deba recorrer el árbol, el grafo, o recursivamente la tabla? • Y la solución naive es con lenguajes procedurales, pero ¿puede hacerse de otra manera?
nombre AS ( -- valor inicial SELECT cols FROM tabla UNION ALL -- o UNION -- elemento recursivo: se apunta a sí mismo SELECT cols FROM nombre -- condición de terminación WHERE … ) SELECT * FROM nombre;
UNION SELECT * FROM generate_series(1,2) ORDER BY 1 ASC; generate_series ----------------- 1 2 aht=> SELECT * FROM generate_series(1,2) UNION ALL SELECT * FROM generate_series(1,2) ORDER BY 1 ASC; generate_series ----------------- 1 1 2 2
SELECT n+1 FROM t WHERE n < 100 ) SELECT sum(n) FROM t; WITH RECURSIVE subdepartment AS ( SELECT * FROM department WHERE name = 'A' UNION ALL SELECT d.* FROM department AS d JOIN subdepartment AS sd ON (d.parent_department = sd.id) ) SELECT * FROM subdepartment ORDER BY name; http://www.postgresql.org/docs/9.3/static/queries-with.html http://wiki.postgresql.org/wiki/CTEReadme
(mask, mask_path, name, parent_network, is_leaf) AS ( SELECT mask, abbrev(mask), name, parent_network, parent_network IS NULL FROM noc.ip_network UNION SELECT i1.mask, abbrev(i2.mask) || ' > ' || i1.mask_path, i1.name, i2.parent_network, i2.parent_network IS NULL FROM ip_network_recursive AS i1 INNER JOIN noc.ip_network AS i2 ON (i1.parent_network = i2.mask) ) SELECT name, mask, mask_path FROM ip_network_recursive WHERE is_leaf;
de comentarios en una web • Los comentarios son de naturaleza jerárquica (aka recursiva) • Migraron de MySQL con procesado de la jerarquía en la aplicación a PostgreSQL con soporte de queries recursivas. Resultados: ✔ 5x mejora velocidad ejecución de consultas ✔ 20x mejora latencia global sirviendo comentarios
ltree) para árboles • Usa paths materializados por lo que puede ser más eficiente que CTEs • Tiene índices y operadores “built-in” INSERT INTO comments (user_id, path) VALUES (1, '0001'); INSERT INTO comments (user_id, path) VALUES (6, '0001.0002'), (7, '0001.0004'), (18, '0001.0004.0005'); SELECT * FROM comments WHERE path <@ '0001.0002'; http://www.postgresql.org/docs/9.3/static/ltree.html