PostgreSQL Capacitación Nivel 2 Día 1 Agenda • Aspectos avanzados de la arquitectura de Postgres. • Compilación y opciones a tener en cuenta. • Recomendaciones para el manejo del servidor. • Configuración • Parámetros avanzados • GEQO • Tipos de identificación de objetos y columnas de sistema. • Tipos de datos propios. • Introducción a los lenguajes procedurales. – Tipos. – Variedad. – Finalidad. • Expresiones regulares. Homo compilatis # ./configure --prefix=/usr/local/pg824 CC=/opt/SUNWspro/bin/cc CFLAGS=" -xO3 -xarch=native -xspace -W0,-Lt -W2,-Rcond_elim -Xa -xildoff -xc99=none -xCC" –without-readline –with-perl –with-python – enable-dtrace # gmake # gmake install # useradd postgres # groupadd postgres # useradd -c 'PostgreSQL user' -d /export/home/postgres -g postgres -m -s /bin/ bash postgres postgres$ $PG_BIN/initdb -D /data -U postgres Paquetes necesarios • Build-essential • Libperl-dev (y python) si queremos incluir estos lenguajes. También se pueden instalar por separado a través de apt. • Bison (para documentación). • Openssl • Zlib (compresión), readline. Configuración Arquitectura Query Path Configuración • SHARED_BUFFERS – El que más afecta el rendimiento. – Comenzar a partir del 10% de memoria. – Se peude setear en MB, KB (24MB, 24576KB). – Tener en cuenta el /proc/sys/kernel/shmax (Linux) # sysctl -w kernel.shmmax=112009216 ó modificar a mano shmmax y shmall • WORK_MEM – Memoria utilizada para trabajo del servidor. – Aumentar en caso de tener muchas consultas complejas. – Para empezar el 4% de la memoria total. Configuración • MAX_CONNECTIONS • LOGGING (Varios parametros) • effective_cache_size • Una de las más importantes debe tener un buen espacio en memoria para serv. Dedicados. • Tamaño efectivo del caché de disco disponible para rastreo de índice. Aumentarlo, aumenta la probabilidad de rastreo por índice) • wal_sync_method wal_buffers (cantidad, método y tamaño de los buffers). • Checkpoint_Segments. • Autovacuum Configuración F[ree] S[pace] M[ap] • max_fsm_pages, max_fsm_pages – Gracias al Visibility Map, en 8.4 ya no es necesario setear estas variables. – En versiones menores a 8.3, se debe setear en un valor determinado a la base más grande del cluster. » El Vacuum nos dirá a través de un HINT que debemos aumentar por encima de un determinado número. Parámtetros avanzados Opciones avanzadas • default_statistics_target (valores por defecto de la recolección de estadísticas, con exepción de aquellas establecidas con ALTER TABLE SET STATISTICS) • from_collapse_limit , join_collapse_limit (establece si el optimizador debe fusionar subconsultas en las consultas si los items del FROM o el JOIN -según corresponda- están por debajo del valor dado) • constraint_exclusion (establece si el optimizador debe utilizar las restricciones para la optimización). • effective_cache_size (tamaño efectivo del caché de disco disponible para rastreo de índice. Aumentarlo, aumenta la probabilidad de rastreo por índice). Opc. durante la compilación • block_size (por defecto 8192) » Indica el tamaño del bloque de datos. • integer_datetime » Soporte o no de 64 bits. • lc_collate, lc_ctype » Forma de hacer la ordenación y clasificaciones de texto. • server_encoding » Encoding del servidor Parametros de almacenamiento • Fillfactor(integer) – Porcentaje entre 10 y 100 (empaquetamiento completo). – A menor valor, las operaciones de inserción empaquetarán la tabla solo en el porcentaje especificado. – El espacio remanente será reservado para los UPDATE de las filas de esa página. • Esto le da la chance a los UPDATE de almacenar la copia de la fila en el mismo espacio que el original, lo que es mejor que almacenarla en otro lugar. – Para tablas con poco o casi nada de UPDATES, 100% es el mejor valor. Caso contrario, disminuirlo. Parametros de almacenamiento (2) • autovacuum_enabled(boolean) (deshabilita o habilita el autovacuum en una tabla particular) • autovacuum_vacuum_threshold(int) (numero de inserciones o actualizaciones para disparar el autovacuum) TOAST • (The Oversized Attributte Storage Technique) Se reconocen 4 tipos de estrategias para el almacenamiento de columnas TOASTables Tipos Variables: Varchar Text, Bytea, etc. • PLAIN previene la compresión o el almacenamiento fuera de linea. Deshabilita el uso de encabezados de un solo byte para los tipos varlena. Es la única posible estrategia para los tipos no toast-ables (Tipos Fijos : int, char, real). • EXTENDED permite compresión y almacenamiento fuera de linea. Es el por defecto de la mayoría de los tipos de datos toastables. La compresión ocurrirá primero, si la fila sigue siendo grande: out-of-line. • EXTERNAL permite el alamcenamiento fuera de linea pero no la compresión. Hará las operaciones con caracteres y expresiones más rápidas en textos y byteas largos ( pero consumiendo mayor espacio) debido a que esas operaciones están optimizadas para avanzar sobre solamente las partes requeridas del valor de fuera de linea cuando no están comprimidas. • MAIN permite la compresión pero no el almacenamiento fuera de linea (Actualmente, el almacenamiento fuera de linea será mejorado para este tipo de columnas, pero solo como último recurso, cuando no hay otro camino para hacer que la fila sea más pequeña). GEQO Genetic Query Optimizer • Elimina aquellos planes de ejecución que posiblemente sean caros. • geqo_thresold (items del FROM a partir del cual se debe utilizar geqo). Se podría recomendar bajar. • Geqo (activa o desactiva) Gestión de Recursos del Kernel • max_locks_per_transaction » 220 bytes c/u • max_connections » 400 bytes ~c/u + 220*max_locks_per_transactions • max_prepared_transactions » 600 bytes ~ c/u +220*max_locks_per_transactions • shared_buffers » Cada buffer es de 8kb (se recomiendan valores superiores a 5000) • wal_buffers » 8kb c/u (puede recomendarse un valor superior a los 5000) Getión de Recursos del Kernel (2) • max_fsm_relations » 70 bytes c/u • max_fsm_pages » c/u 6 bytes (max_fsm_relations*16) Parametros del kernel Parámetros Descripción Valores Razonables SHMMAX Maximo del segmento de mem compartida 32MB es por defecto. Se aconsejan 200 MB mínimo. SHMMIN Mínimo del segmento de mem compartida 500 kb SHMALL Total compartida ~SHMMAX SHMSEG Máximo seg. Mem. Por proceso 1 SHMNI Máximo de segmentos SHMSEG+requerido por aplic. SEMMNI Máx. De identificadores de semáforos Al menos max_conection /16 SEMMNS Máx. De semáforos del sistema (max_connection/16)*17+req. Por las aplic. SEMMSL Semáforos del conjunto Min. 17 SEMMAP Entradas en un mapa de semáforos ~SEMMNS SEMVMX Valor máx. De semáforo Al menos 32767 Modificación Parametros del Kernel • Archivo sysctl.conf en el directorio /etc. • Delante de cada parámetro agregar kernel.<parametro> Establecimiento de variables en caliente Variables de sesión • Para afinar el servidor es necesario realizar pruebas cambiando las variables de sesión que afectan directamente a las consultas. Ejemplos • set search_path = sau_np, sau_no, sau_gb; • set geqo_threshold = 12; • set from_collapse_limit = 8; • set join_collapse_limit = 8; • set geqo = on; Recomendaciones Cambiando la configuración • ¿Como resetear – recargar? – /etc/init.d/postgres reload – /etc/init.d/postgres restart – Service postgres reload | restart • En el postgresql.conf, las variables que requieren restartear el motor, tienen un comentario que indica eso. • 'Reload' utiliza mucho menos tiempo. Identificadores de objetos Y columnas de sistema OID • Se usa internamente para tablas de sistema como PK's. • No son agregadas a las tablas de usuarios a menos que se la cree con la opción WITH OIDS o se habilite la variable default_with_oids. • Hay diversos tipos de alias para el OID: regproc, regprocedure, regoper, regoperator, regclass, regtype, regconfig, and regdictionary. Ejemplos con OID y Regclass crap=# select ('individuo'::regclass)::oid; oid ------24716 (1 row) crap=# select 24716::regclass; regclass ----------individuo (1 row) Tableoid • El OID de la tabla es el contenido de esta fila. Es particularmente útil para consultas que selecccionan desde herencia, permitiendo observar deque tabla individualmente proviene un registro. Puede ser 'unido' contra el OID de la columna OID de pg_class, obteniendo el nombre de la tabla. Ejemplo Tableoid xmin • Es la identidad de la transacción de inserción de la versión de la fila. • Una 'versión de una fila' es un estado individual de una fila. – Cada actualización de una fila genera una nueva versión de la misma para la misma fila lógica. Ejemplo xmin crap=# select txid_snapshot_xmin(txid_current_snapshot()); txid_snapshot_xmin -------------------1053 crap=# insert into src values(1),(2),(9); crap=# select xmin,xmax,* from src where xmin = 1053; xmin | xmax | i ------+------+--1053 | 0|1 1053 | 0|2 1053 | 0|9 (3 rows) Cmin -cmax • CMIN: El identificador de comando (comenzando de 0) de la transacción de inserción. • CMAX:Idem de la transacción de borrado o en 0. Ejemplo cmin Ejemplo cmax Luego de COMMIT • Queda el orden en el cual en una transacción se insertaron los registros. xmax • Es la identidad de la transacción de borrado o en 0 para una fila no borrada. • Es posible para esta columna ser distinto de 0 en una versión de fila visible. • Usualmente indica que la transacción de borrado no ha sido comprometida aún o que fue abortada con 'rollback'. Ejemplo Luego de un ROLLBACK • Se observa que aún conserva el xid en el xmax. ctid • Ubicación física de una versión de una fila de una tabla • El CTID puede variar, por lo que no se aconseja para ser utilizada para buscar un determinado campo. (Esto lo hace el VACUUM FULL). • Es útil para identificar campos en conjuntos grandes. En el caso de buscar filas lógicas, se recomienda OID. Hackaton Ctid Más sobre CTID Tipos propios Ejemplo create type groupOfNumber AS ( first integer, second float, third numeric(10,2) ); create table tabla1( numeros groupOfNumber, a serial not null, dia date default CURRENT_DATE ); NOTICE: CREATE TABLE will create implicit sequence "tabla1_a_seq" for serial column "tabla1.a" CREATE TABLE base1=# \d List of relations Schema | Name | Type | Owner --------+--------------+----------+---------public | tabla1 | table | postgres public | tabla1_a_seq | sequence | postgres (2 rows) CREATE DOMAIN midominio as integer default 1 NOT NULL; insert into tabla1 default values; create table foo3 (numero midominio); --mirar que no hay restriccion en 'numeros' alter domain midominio set default 2; insert into tabla1 values( (1,2.0,2.1) ); Ejemplos CREATE TYPE dia AS ENUM ('lunes','martes','miercoles','jueves','viernes'); Ejemplos CREATE DOMAIN grupo_dia AS text CHECK (VALUE IN ('lunes','martes','miercoles','jueves','viernes')); CREATE DOMAIN dni AS numeric(8,0) CHECK (VALUE::text ~ $dni$^[1-4,9]\d{7}$$dni$); CREATE DOMAIN exclusivo AS text CHECK (VALUE NOT IN ('e','p') AND VALUE IS NOT NULL); Expresiones regulares Operadores http://developer.postgresql.org/pgdocs/postgres/functions-string.html Ejemplos • 'abc' ~ 'abc' true • 'abc' ~ '^a' true • 'abc' ~ '(b|d)' true • 'abc' ~ '^(b|c)' false • 'abc' ~ '(b)$' false Funciones • regexp_matches('foobarbequebaz', '(bar) (beque)') • regexp_replace('Thomas', '.[mN]a.', 'M') • regexp_split_to_array('hello world', E'\\s+') • regexp_split_to_table('hello world', E'\\s+') Ejemplos funciones • substring('foobar' from 'o.b') oob • substring('foobar' from 'o(.)b') o • regexp_replace('foobarbaz', 'b..', 'X') fooXbaz • regexp_replace('foobarbaz', 'b..', 'X', 'g') fooXX • regexp_replace('foobarbaz', 'b(..)', E'X\\1Y', 'g') fooXarYXazY Ejemplos Ejemplos Lenguajes Procedurales Finalidad • Extienden los limites de SQL para tareas complejas. • Permiten el control de acceso a determinados objetos. • Controlar la integridad de los datos. • Realizar operaciones suplementarias del lado del servidor, aprovechando el poder de procesamiento- Características • Las funciones se ejecutan del lado servidor, lo que puede ser utilizado para aprovechar los beneficios que eso acarrea, en lugar de ejecutarlos localmente. • Están 'más cerca de los datos'. Lenguajes • Postgresql posee varios lenguajes Procedurales (o extensiones). • Entre ellos se encuentran: SQL, PL/Pgsql, C, PL/python, PL/perl, PL/tcl, PL/Proxy, PL/Scheme, PL/R, PL/java, PL/php entre varios más... • Saber aprovechar las ventajas de cada uno y conocer las debilidades. Intro Pl/Pgsql • • • • • • PL por excelencia Procedural Fácil de usar Fácil de portar desde Oracle PL/SQL Sintaxis simple y apropiada No particularmente veloz … • cache de planes de ejecución • Requiere ser instalado, pero no necesita modificaciones en la compilación. PL/pgsql • Plpgsql no esta instalado por defecto. • Se lo instala: CREATE LANGUAGE 'plpgsql'; • Se puede crear a traves de un handler teniendo compilada la shared library. • Plperl no viene por defecto, requiere librerias no incluidas. • Entre los mas conocidos PL/tcl, python, ruby,php, java... y continua la lista... Crear lenguaje • CREATE [ PROCEDURAL ] LANGUAGE name • CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name • HANDLER call_handler [ VALIDATOR valfunction ] CREATE LANGUAGE plpgsql; GRANT ALL ON LANGUAGE plpgsql TO resagado2; --all es USAGE en este caso Tipos de Funciones • Según lo que retornan – Funciones “normales” – – SRF (set-returning function) Agregación • Especiales – trigger – language_handler • Privilegios durante invocación – security definer – security invoke • Por lo que modifican – Volátiles VOLATILE – Inmutable INMUTABLE – Estricta STRICT • Tradicionales – Retornan un solo resultado (escalar o tupla) – Es posible retornar un cursor abierto – Pueden tener efectos secundarios( tabla temporal) Declaración postgres=# \h create function ... CREATE [ OR REPLACE ] FUNCTION name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) [ RETURNS rettype ] { LANGUAGE langname | IMMUTABLE | STABLE | VOLATILE | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | COST execution_cost | ROWS result_rows | SET configuration_parameter { TO value | = value | FROM CURRENT } | AS 'definition' | AS 'obj_file', 'link_symbol' } ... [ WITH ( attribute [, ...] ) ] Estructura • Tienen estructuras de 'bloque'. • Cada bloque se define usando DECLARE, BEGIN, END; Estos bloques pueden estar anidados. • NO SE PUEDEN DEFINIR TRANSACCIONES EN UNA FUNCIÓN. • Los tipos de datos pasados a la función se dan en paréntesis • El cuerpo de la función se pasa a la base de datos como una cadena de caracteres (véase, que el cuerpo empieza y acaba con comillas simples en las versiones 7.x, a partir del 8 se recomienda el uso de $$ o $BODY$) • Tras la cadena el lenguaje usado para crear la función se define usando la orden "LANGUAGE" (otros lenguajes posibles son PL/PERL, PL/python, C, etc) Calificadores • • • • SECURITY DEFINER STRICT COST cost_metric ROWS est_num_rows Tipos de variables Numero INTEGER; otro VARCHAR(20); otroNumero NUMERIC(10,2); -- RECOMENDADO, podemos utilizar nuestros datos predefinidos soyDelTipoQueSeaUnCampo mitabla.campo%TYPE; soyDelTipoRegistroDeUnaTabla mitable%ROWTYPE; ... RETURN soyDelTipoRegistroDeUnaTabla.unCampoDeLaTabla; -- utilizo un campo de la tupla en la variable Bloques y declaración DECLARE variable tipodedato:= dameUnValor; variable2 algunTipo curs1 refcursor; curs2 CURSOR FOR SELECT * FROM tablita; variable := valor; SELECT field1, field2 INTO variable,variable2 FROM tablita WHERE .. LIMIT 1; Ejemplo CREATE FUNCTION suma (INT,INT,INT,INT) RETURNS INT4 AS $BODY$ DECLARE SUMA INT4; soyElPrimerParametro ALIAS FOR $1; BEGIN SUMA:=soyElPrimerParametro+$2+$3; SUMA:=SUMA-$4; RETURN cast(SUMA as int4); END; $BODY$ LANGUAGE plpgsql; postgres=> SELECT SUMA (1,2,3,4); Suma ----2 Control de Flujo (FOR) FOR i IN 1 ... numtimes LOOP statements END LOOP; FOR i IN REVERSE numtimes ...1 LOOP FOR var_e IN EXCUTE('someDynamicS ql') LOOP statements RETURN NEXT var_e; statements END LOOP END LOOP; FOR var_e IN someSql LOOP statements RETURN NEXT var_e; END LOOP; Control condicional IF IF condition THEN : END IF; IF condition THEN : ELSE : END IF; IF condition THEN : ELSEIF condition THEN : ELSE : END IF; 8.4 CASE (x valor) CREATE OR REPLACE FUNCTION x(INT4) RETURNS TEXT as $$ BEGIN CASE $1 WHEN 1,2 THEN RETURN 'uno o dos'; WHEN 3 THEN RETURN 'tres...'; ELSE RETURN 'ni idea'; END CASE; END; $$ language plpgsql; 8.4 CASE (x expresión) CREATE OR REPLACE FUNCTION x(INT4) RETURNS TEXT as $$ BEGIN CASE WHEN $1 < 10 THEN RETURN 'menor a 10'; WHEN $1 = 10 THEN RETURN 'it''s 10'; ELSE RETURN 'mas de 10 seguro'; END CASE; END; $$ language plpgsql; Bucle (while y loop) WHILE condition LOOP : END LOOP; LOOP -- codigo EXIT WHEN count > 100; CONTINUE WHEN count < 50; -- cout IN [50 .. 100] END LOOP; Return RETURN somevariable; RETURN NEXT rowvariable; RETURN QUERY; --nuevo!! RETURN algundato RETURN SETOF algunTipoDeDato (SRF) RETURN void RETURN refcursor RETURN trigger Estados y constantes de error FOUND ROW_COUNT division_by_zero no_data_found too_many_rows unique_violation RAISE • • • • • RAISE DEBUG[1-5] RAISE EXCEPTION RAISE INFO RAISE LOG RAISE NOTICE Exepciones RAISE EXCEPTION 'Exception notice: %', var EXCEPTION WHEN condition THEN hacer o dejar en blanco para ignorar END; Variables predefinidas para Triggers Nombre Tipo NEW %ROWTYPE OLD %ROWTYPE TG_NAME NAME TG_WHEN TEXT TG_LEVEL TEXT TG_OP TEXT TG_RELID OID TG_RELNAMENAME TG_NARGS INT TG_VARGS TEXT[] Descripción Nuevos Valores (INSERT | UPDATE) Valores Antiguos ( UPDATE |DELETE ) Nombre del TRIGGER BEFORE | AFTER ROW | SENTENCIA (SQL) INSERT, UPDATE | DELETE Identificador de la tabla Nombre de la tabla Numero de argumentos Argumentos Ejemplo CREATE OR REPLACE FUNCTION capitalize(_texto text) RETURNS text AS $BODY$ DECLARE fin INTEGER; temporal RECORD; retval TEXT; BEGIN retval = ' '; FOR temporal IN SELECT string_to_array (_texto,' ') AS arreglo LOOP SELECT regexp_replace( regexp_replace( array_dims(temporal.arreglo),'[^1-9]','','g') ,'.','')::integer into fin; FOR i IN 1..fin LOOP retval = retval || upper(substring(temporal.arreglo[i],1,1)) || lower(regexp_replace(temporal.arreglo[i],'(.)(.*)','\\2')) ||' '; END LOOP; END LOOP; RETURN trim(retval); END; $BODY$ LANGUAGE 'plpgsql' VOLATILE; Ejemplo Se inserta el valor de un campo En una variable (cursor implícito) Ejemplo Triggers </Parte 1>