Tuneando PostgreSQL

PostgreSQL

Después de una larga ausencia en el blog, vamos a explicar una configuración para la base de datos PostgreSQL que pueda soportar altas cargas y aumentar la disponibilidad del servicio, comentaremos sus opciones y justificaremos los valores que decidimos aplicar en función de los recursos de la máquina.

Nuestra máquina es una servidor cloud que tiene 4 núcleos y 8G de memoria RAM, la máquina actualmente está compartida con contenedores docker de otros servicios por lo que en este contenedor vamos a consumir como máximo 3G de RAM y un pool de 250 conexiones, ya que el software que la usa (Elixir en este caso) es muy rápido y necesita de una alta disponibilidad, así mismo precisa de un alto número de conexiones concurrentes para no saturarla.

Opciones de configuración

Estas opciones las hemos sacado de la página https://pgtune.leopard.in.ua que nos ayudará a afinar la configuración en función de los valores de versión, núcleos, memoria y conexiones que necesitemos, hemos decidido usar el perfil online transaction processing system para nuestro caso.

# DB Version: 12
# OS Type: linux
# DB Type: oltp
# Total Memory (RAM): 3 GB
# CPUs num: 4
# Connections num: 250

max_connections = 250 # máximo número de conexiones concurrentes
shared_buffers = 768MB # cantidad de memoria dedicada a datos en caché
effective_cache_size = 2304MB # cantidad de memoria disponible para memoria intermedia en el disco
maintenance_work_mem = 192MB # cantidad de memoria usada para operaciones de mantenimiento
checkpoint_completion_target = 0.9 # permite escribir lentamente en la instancia: checkpoint_completion_target * checkpoint_timeout (5min)
wal_buffers = 16MB # pequeña memoria que sincroniza los datos, aumentándola se permiten inserciones más grandes
default_statistics_target = 100 # recolecta estadísticas de cada una de las tablas para decidir como se ejecutarán las consultas sobre ellas
random_page_cost = 1.1 # sugiere al optimizador cuanto tiempo le llevará al disco encontrar una página aleatoria de disco
effective_io_concurrency = 200 # número de operaciones de disco I/O concurrentes
work_mem = 1572kB # para operaciones complejas realiza ordenamientos más distendidos en memoria
min_wal_size = 2GB # cantidad mínima de la memoria usada para integridad de los datos
max_wal_size = 4GB # cantidad máxima de la memoria usada para integridad de los datos
max_worker_processes = 4 # cantidad máxima de procesos
max_parallel_workers_per_gather = 2 # cantidad máxima de subprocesos en paralelo por nodo, no puede exceder a max_parallel_workers
max_parallel_workers = 4 # cantidad máxima de subprocesos en paralelo

Con esta configuración el contenedor de PostgreSQL 12 está preparado para trabajar con 250 conexiones concurrentes, pudiendo gestionar correctamente la carga de las consultas que se realicen y mantener la estabilidad del sistema a lo largo del tiempo.

Esperamos que os haya gustado, nos vemos en la próxima entrada, saludos

Resumen PL/SQL

Este post es un resumen de PL/SQL. Pensado para las personas que estén preparándose los exámenes de grado superior a modo de guía rápida.

PL/SQL nos permite un pequeño ámbito de programación dentro de las bases de datos. Enfocado a administración, eventos o tareas en la misma.

La éxtasis para ejecutar un código arbitrario:

DECLARE 
   <declarations section> 
BEGIN 
   <executable command(s)>
[EXCEPTION
   exception_section]
END;

Un hola mundo seria:

DECLARE 
   message  varchar2(20):= 'Hello, World!'; 
BEGIN 
   dbms_output.put_line(message); 
END; 
/ 

Se usa “/” para declarar que hemos terminado la ejecución de código.

Un delimitador es un símbolo con un significado especial. La siguiente es la lista de delimitadores en PL/SQL:

Como en cualquier lenguaje tendremos procedimientos:

---- Procedimiento
-- Sintaxis 
CREATE [OR REPLACE] PROCEDURE procedure_name 
[(parameter_name [IN | OUT | IN OUT] type [, ...])] 
{IS | AS} 
BEGIN 
  < procedure_body > 
[EXCEPTION
   exception_section]
END procedure_name; 
-- Ejemplo
CREATE OR REPLACE PROCEDURE greetings 
AS 
BEGIN 
   dbms_output.put_line('Hello World!'); 
END; 
/

Y funciones:

---- Función
-- Sintaxis
CREATE [OR REPLACE] FUNCTION function_name 
[(parameter_name [IN | OUT | IN OUT] type [, ...])] 
RETURN return_datatype 
{IS | AS} 
BEGIN 
   < function_body > 
END [function_name];
-- Ejemplo
CREATE OR REPLACE FUNCTION totalCustomers 
RETURN number IS 
   total number(2) := 0; 
BEGIN 
   SELECT count(*) into total 
   FROM customers; 
    
   RETURN total; 
END; 

Lo mejor de PL/SQL es que permite controlar los datos a través de los eventos o triggers:

---- Triggers
-- Sintaxis
CREATE [OR REPLACE ] TRIGGER trigger_name  
{BEFORE | AFTER | INSTEAD OF }  
{INSERT [OR] | UPDATE [OR] | DELETE}  
[OF col_name]  
ON table_name  
[REFERENCING OLD AS o NEW AS n]  
[FOR EACH ROW]  
WHEN (condition)   
DECLARE 
   Declaration-statements 
BEGIN  
   Executable-statements 
EXCEPTION 
   Exception-handling-statements 
END;
-- Ejemplo
CREATE OR REPLACE TRIGGER display_salary_changes 
BEFORE DELETE OR INSERT OR UPDATE ON customers 
FOR EACH ROW 
WHEN (NEW.ID > 0) 
DECLARE 
   sal_diff number; 
BEGIN 
   sal_diff := :NEW.salary  - :OLD.salary; 
   dbms_output.put_line('Old salary: ' || :OLD.salary); 
   dbms_output.put_line('New salary: ' || :NEW.salary); 
   dbms_output.put_line('Salary difference: ' || sal_diff); 
END;

Se recomienda la lectura del siguiente link, con toda la documentación oficial en ingles.

Resumen comandos de SQL

Este post es un resumen de los comandos SQL. Pensado para las personas que estén preparándose los exámenes de grado superior a modo de guía rápida.

  • DDL

Los comandos DDL, son los que nos permiten crear y denominar las tablas, indices y todos aquellos componentes de la estructura de las bases de datos y sus tablas.

---- CREATE
-- Crear tabla:
CREATE TABLE tablename (
   column1 datatype(size) constraint[optional], 
   column2 datatype(size) constraint[optional]
);

---- ALTER
-- Añadir columna a tabla existente:
ALTER TABLE tablename ADD column_name datatype(size);
-- Cambiar tipo a columna a tabla existente:
ALTER TABLE tablename MODIFY column_name datatype(size);
-- Borrar columna en una tabla:
ALTER TABLE tablename DROP column_name ;

---- DROP
-- Borrar una tabla:
DROP TABLE tablename;

---- RENAME
-- Cambiar nombre a una tabla:
RENAME existing_column_name to new_column_name;

---- TRUNCATE
-- Vaciar contenido de una tabla:
TRUNCATE TABLE tablename;

  • DML

Aquí se agrupan los comando que sirven para añadir, modificar o eliminar datos en las tablas.

---- SELECT
-- Mostramos toda las filas y columnas de una tabla: 
SELECT * FROM table_name;
-- Mostramos todas las fila pero solo las columnas declaradas: 
SELECT column1, column2 FROM table_name;
-- Buscamos filas que coincidan en la condición y mostramos todas las columnas:
SELECT * FROM table_name WHERE some_column=some_value
-- Buscamos filas que coincidan en la condición y mostramos las columnas declaradas:
SELECT column1, column2 FROM table_name WHERE some_column=some_value

---- UPDATE
-- Actualizamos las filas que cumplan las condiciones:
UPDATE table_name SET column1=value, column2=value2,... WHERE some_column=some_value

---- DELETE
-- Borramos las filas que cumplan las condicion
-- https://www.youtube.com/watch?v=i_cVJgIz_Cs
DELETE FROM table_name [WHERE condition];

  • DCL

Este es el apartado donde agruparemos los comandos relacionados con permisos de usuarios. Básicamente dos comandos GRANT(Añadir permiso) y REVOKE(Revocar permisos).

---- GRANT
-- Permite crear sesión al usuario 
GRANT CREATE SESSION TO username;
-- Permite al usuario crear tablas
GRANT CREATE TABLE TO username;
-- En ocasiones, el usuario no puede crear tablas con nombres reservados para las tablas del sistema
GRANT CREATE ANY TABLE TO username 
-- Permite al usuario borrar tablas
GRANT DROP ANY TABLE TO username

---- ALTER
-- Cambia la cuota que puede usar el usuario.
ALTER USER username QUOTA UNLIMITED ON SYSTEM;

---- REVOKE
-- Revocamos al usuario 
REVOKE CREATE TABLE FROM username

  • TCL

En este grupo no nos vamos a extender. Pues no se suele pedir en los grados superior. Pero está bien tener en cuenta el comando COMMIT. Que nos asegura que los comandos que introdujimos antes que él. Se sincronicen con el servidor. Ya que existe la posibilidad de que algunos comando, sobretodo los relacionados con permisos de usuario. No se hagan efectivos al ejecutarlos y el servidor espera a reiniciar o a dicho comando.

---- COMMIT
-- Confirma que se guarden los cambios efectuados referentes a permisos de usuario:
COMMIT;