Performance Tuning PostgreSQL
Performance Tuning PostgreSQL
by Frank Wiles
Introduction
PostgreSQL is the most advanced and flexible Open Source SQL database today. With this power and flexibility comes a problem. How do the PostgreSQL developers tune the default configuration for everyone? Unfortunately the answer is they can't. The problem is that every database is not only different in its design, but also its requirements. Some systems are used to log mountains of data that is almost never queried. Others have essentially static data that is queried constantly, sometimes feverishly. Most systems however have some, usually unequal, level of reads and writes to the database. Add this little complexity on top of your totally unique table structure, data, and hardware configuration and hopefully you begin to see why tuning can be difficult. The default configuration PostgreSQL ships with is a very solid configuration aimed at everyone's best guess as to how an "average" database on "average" hardware should be setup. This article aims to help PostgreSQL users of all levels better understand PostgreSQL performance tuning.
The first step is the sending of the query string ( the actual SQL command you type in or your application uses ) to the database backend. There isn't much you can tune about this step, however if you have a very large queries that cannot be prepared in advance it may help to put them into the database as a stored procedure and cut the data transfer down to a minimum. Once the SQL query is inside the database server it is parsed into tokens. This step can also be minimized by using stored procedures. The planning of the query is where PostgreSQL really starts to do some work. This stage checks to see if the query is already prepared if your version of PostgreSQL and client library support this feature. It also analyzes your SQL to determine what the most efficient way of retrieving your data is. Should we use an index and if so which one? Maybe a hash join on those two tables is appropriate? These are some of the decisions the database makes at this point of the process. This step can be eliminated if the query is previously prepared.
Now that PostgreSQL has a plan of what it believes to be the best way to retrieve the data, it is time to actually get it. While there are some tuning options that help here, this step is mostly effected by your hardware configuration. And finally the last step is to transmit the results to the client. While there aren't any real tuning options for this step, you should be aware that all of the data that you are returning is pulled from the disk and sent over the wire to your client. Minimizing the number of rows and columns to only those that are necessary can often increase your performance.
General Tuning
There are several postmaster options that can be set that drastically affect performance, below is a list of the most commonly used and how they effect performance: max_connections = <num> This option sets the maximum number of database backend to have at any one time. Use this feature to ensure that you do not launch so many backends that you begin swapping to disk and kill the performance of all the children. Depending on your application it may be better to deny the connection entirely rather than degrade the performance of all of the other children. shared_buffers = <num> Editing this option is the simplest way to improve the performance of your database server. The default is pretty low for most modern hardware. General wisdom says that this should be set to roughly 25% of available RAM on the system. Like most of the options I will outline here you will simply need to try them at different levels (both up and down ) and see how well it works on your particular system. Most people find that setting it larger than a third starts to degrade performance. effective_cache_size = <num> This value tells PostgreSQL's optimizer how much memory PostgreSQL has available for caching data and helps in determing whether or not it use an index or not. The larger the value increases the likely hood of using an index. This should be set to the amount of memory allocated to shared_buffers plus the amount of OS cache available. Often this is more than 50% of the total system memory. work_mem = <num> This option is used to control the amount of memory using in sort operations and hash tables. While you may need to increase the amount of memory if you do a ton of sorting in your application, care needs to be taken. This isn't a system wide parameter, but a per operation one. So if a complex query has several sort operations in it it will use multiple work_mem units of memory. Not to mention that multiple backends could be doing this at once. This query can often lead your database server to swap if the value is too large. This option was previously called sort_mem in older versions of PostgreSQL. max_fsm_pages = <num> This option helps to control the free space map. When something is deleted from a table it isn't removed from the disk immediately, it is simply marked as "free" in the free space map. The space can then be reused for any new INSERTs that you do on the table. If your setup has a high rate of DELETEs and INSERTs it may be necessary increase this value to avoid table bloat. fsync = <boolean> This option determines if all your WAL pages are fsync()'ed to disk before a transactions is committed. Having this on is safer, but can reduce write performance.
If fsync is not enabled there is the chance of unrecoverable data corruption. Turn this off at your own risk. commit_delay = <num> and commit_siblings = <num> These options are used in concert to help improve performance by writing out multiple transactions that are committing at once. If there are commit_siblings number of backends active at the instant your transaction is committing then the server waiting commit_delay microseconds to try and commit multiple transactions at once. random_page_cost = <num> random_page_cost controls the way PostgreSQL views nonsequential disk reads. A higher value makes it more likely that a sequential scan will be used over an index scan indicating that your server has very fast disks.
If this is still confusing to you, Revolution Systems does offer aPostgreSQL Tuning Service Note that many of these options consume shared memory and it will probably be necessary to increase the amount of shared memory allowed on your system to get the most out of these options.
Hardware Issues
Obviously the type and quality of the hardware you use for your database server drastically impacts the performance of your database. Here are a few tips to use when purchasing hardware for your database server (in order of importance): RAM The more RAM you have the more disk cache you will have. This greatly impacts performance considering memory I/O is thousands of times faster than disk I/O. Disk types Obviously fast Ultra-320 SCSI disks are your best option, however high end SATA drives are also very good. With SATA each disk is substantially cheaper and with that you can afford more spindles than with SCSI on the same budget. Disk configuration The optimum configuration is RAID 1+0 with as many disks as possible and with your transaction log (pg_xlog) on a separate disk ( or stripe ) all by itself. RAID 5 is not a very good option for databases unless you have more than 6 disks in your volume. With newer versions of PostgreSQL you can also use the tablespaces option to put different tables, databases, and indexes on different disks to help optimize performance. Such as putting your often used tables on a fast SCSI disk and the less used ones slower IDE or SATA drives. CPUs The more CPUs the better, however if your database does not use many complex functions your money is best spent on more RAM or a better disk subsystem.
In general the more RAM and disk spindles you have in your system the better it will perform. This is because with the extra RAM you will access your disks less. And the extra spindles help spread the reads and writes over multiple disks to increase throughput and to reduce drive head congestion. Another good idea is to separate your application code and your database server onto different hardware. Not only does this provide more hardware dedicated to the database server, but the operating system's disk cache will contain more PostgreSQL data and not other various application or system data this way.
For example, if you have one web server and one database server you can use a cross-over cable on a separate ethernet interface to handle just the web server to database network traffic to ensure you reduce any possible bottlenecks there. You can also obviously create an entirely different physical network for database traffic if you have multiple servers that access the same database server.
Total runtime: 16.386 ms You need to read this output from bottom to top when analyzing it. The first thing PostgreSQL does is do a sequence scan on the books table looking at each author_id column for values that equal 16. Then it does an index scan of the authors table, because of the implicit index created by the PRIMARY KEY options. Then finally the results are sorted by books.title. The values you see in parenthesis are the estimated and actual cost of that portion of the query. The closer together the estimate and the actual costs are the better performance you will typically see. Need some expert help tuning your database? Learn more about ourPostgreSQL Tuning Service Now, let's change the structure a little bit by adding an index on books.author_id to avoid the sequence scan with this command: CREATE INDEX books_idx1 on books(author_id); If you rerun the query again, you won't see any noticeable change in the output. This is because PostgreSQL has not yet re-analyzed the data and determined that the new index may help for this query. This can be solved by running: ANALYZE books; However, in this small test case I'm working with the planner still favors the sequence scan because there aren't very many rows in my books table. If a query is going to return a large portion of a table then the planner chooses a sequence scan over an index because it is actually faster. You can also force PostgreSQL to favor index scans over sequential scans by setting the configuration parameter enable_seqscan to off. This doesn't remove all sequence scans, since some tables may not have an index, but it does force the planner's hand into always using an index scan when it is available. This is probably best done by sending the command SET enable_seqscan = off at the start of every connection rather than setting this option database wide. This way you can control via your application code when this is in effect. However, in general disabling sequence scans should only be used in tuning your application and is not really intended for every day use. Typically the best way to optimize your queries is to use indexes on specific columns and combinations of columns to correspond to often used queries. Unfortunately this is done by trial and error. You should also note that increasing the number of indexes on a table increases the number of write operations that need to be performed for each INSERT and UPDATE. So don't do anything silly and just add indexes for each column in each table. You can help PostgreSQL do what you want by playing with the level of statistics that are gathered on a table or column with the command: ALTER TABLE <table> ALTER COLUMN <column> SET STATISTICS <number>;
This value can be a number between 0 and 1000 and helps PostgreSQL determine what level of statistics gathering should be performed on that column. This helps you to control the generated query plans without having slow vacuum and analyze operations because of generating large amounts of stats for all tables and columns. Another useful tool to help determine how to tune your database is to turn on query logging. You can tell PostgreSQL which queries you are interested in logging via the log_statementconfiguration option. This is very useful in situations where you many users executing ad hoc queries to your system via something like Crystal Reports or via psql directly.
); This design is easy to understand, but isn't very good on several levels. While it will depend on your particular application, in most cases you won't need to access all of this data at one time. In portions of your application that deal with HR functions you are probably only interested in their name, salary, vacation time, and sick days. However, if the application displays an organization chart it would only be concerned with the department and supervisor_id portions of the table. By breaking up this table into smaller tables you can get more efficient queries since PostgreSQL has less to read through, not to mention better functionality. Below is one way to make this structure better: CREATE TABLE employees ( id int4 PRIMARY KEY, active boolean, employee_number int4, first_name varchar, middle_name varchar, last_name varchar, department varchar, title varchar, email varchar ); CREATE TABLE employee_address ( id int4 PRIMARY KEY, employee_id int4, personal boolean, address_1 varchar, address_2 varchar, city varchar, state varchar(2), zip varchar ); CREATE TABLE employee_number_type ( id int4 PRIMARY KEY, type varchar ); CREATE TABLE employee_number ( id int4 PRIMARY KEY, employee_id int4, type_id int4, number varchar
); CREATE TABLE employee_hr_info ( id int4 PRIMARY KEY, employee_id int4, ssn varchar, salary int4, vacation_days int2, sick_days int2 ); With this table structure the data associated with an employee is broken out into logical groupings. The main table contains the most frequently used information and the other tables store all of the rest of the information. The added benefit of this layout is that you can have any number of phone numbers and addresses associated with a particular employee now. Another useful tip is to use partial indexes on columns where you typically query a certain value more often than another. Take for example the employee table above. You're probably only displaying active employees throughout the majority of the application, but creating a partial index on that column where the value is true can help speed up the query and may help the planner to choose to use the index in cases where it otherwise would not. You can create a partial index like this: CREATE INDEX employee_idx2 ON employee(active) WHERE active='t'; Or you may have a situation where a row has a column named 'employee_id' that is null until the row is associated with an employee, maybe in some trouble ticket like system. In that type of application you would probably have a 'View Unassigned Tickets' portion of the application which would benefit from a partial index such as this: CREATE INDEX tickets_idx1 ON tickets(employee_id) WHERE employee_id IS NULL;
Application Development
There are many different ways to build applications which use a SQL database, but there are two very common themes that I will call stateless and stateful. In the area of performance there are different issues that impact each. Stateless is typically the access type used by web based applications. Your software connects to the database, issues a couple of queries, returns to results to the user, and disconnects. The next action the users takes restarts this process with a new connect, new set of queries, etc. Stateful applications are typically non-web based user interfaces where an application initiates a database connection and holds it open for the duration the application is in use.
Stateless Applications
In web based applications each time something is requested by the user , the application initiates a new database connection. While PostgreSQL has a very short connection creation time and in general it is not a very expensive operation, it is best to use some sort of database connection pooling method to get maximum performance. There are several ways to accomplish database connection pooling, here is a short list of common ones: Pgpool is a small server that you run on the same server as your clients that will pool database connections to some local or remote server. The application simply points at the pgpool instance instead of the normal postmaster. From the application's perspective nothing has changed as the connection pooling is hidden from it. In a mod_perl environment you can use Apache::DBI to handle database connection pooling inside of Apache itself. SQLRelay is another db connection manager that is somewhat database agnostic. It works with with several databases other than PostgreSQL. You can always write a small bit of code to do this for you yourself, but I would highly recommend using an already developed solution to reduce the amount of debugging you have to do.
It should be noted that in a few bizarre instances I've actually seen database connection pooling reduce the performance of web based applications. At a certain point the cost of handling the pooling is more expensive than simply creating a new connection. I suggest testing it both ways to see which is best for your environment.
Stateful Applications
When building stateful applications you should look into using database cursors via theDECLARE command. A cursor allows you to plan and execute a query, but only pull back the data as you need it, for example one row at a time. This can greatly increase the snappiness of the UI.
You can also obviously utilize stored procedures here to reduce the transmit, parse, and plan portions of the typical query life cycle. It is best to profile your application and find commonly used queries and data manipulations and put them into a stored procedure.
Antes en entrar en el tema me parece importante aclarar el trmino anglosajn Tuning con el que nos referimos a puesta a punto de algo. PostgreSQL es actualmente la Base de Datos SQL de cdigo abierto ms avanzada y flexible. Con este poder y flexibilidad enfrentamos un problema: los desarrolladores de PostgreSQL suelen ajustar la configuracin de modo general, lamentablemente esto no se debe hacer. Esto se hace para asegurar que el servidor arrancar casi con cualquier configuracin hardware. El punto esta en que cada base de datos no solo es diferente en su diseo sino tambin en sus necesidades. Algunas por ejemplo, se usan para recopilar grandes cantidades de datos que casi nunca son consultados y otras en cambio tienen datos estticos y que son consultados frecuentemente. Sin embargo la mayora de sistemas tienen niveles de escritura y lectura sobre la base de datos, generalmente desiguales. Sumando a esto la estructura total de la base de datos, sus tipos de datos y configuracin de hardware hacen que hacer tuning al rendimiento de PostgreSQL no sea una tarea fcil. Sitios de Referencia: http://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server Entendiendo el proceso El primer paso para entender como funciona una base de datos PostgreSQL es entender el ciclo de vida de una consulta. Estos son los pasos que sigue una consulta:
1. 2. 3. 4. 5. Transmisin de la cadena de consulta al backend de la base de datos Anlisis(Parsing) de la cadena de consulta Planificacin de la consulta para optimizar la recuperacin de datos Recuperacin de datos desde el hardware Transmisin de los resultados del cliente
El primer paso es el envo de la cadena de consulta (el comando SQL que se tipea desde la aplicacin que se este usando) a la base de datos. No hay mucho que usted pueda ajustar en este punto. Sin embargo si usted tiene consultas muy grandes o largas que no se construyen de forma avanzada puede optar por ponerlas en la base de datos como procedimientos almacenados y as cortar la transferencia de datos a un mnimo que vendra siendo el llamado al procedimiento almacenado.
Una vez que la consulta SQL esta dentro del servidor de base de datos es analizada(Parsed). Este paso tambin puede evitarse con algunas consultas creando procedimientos almacenados. En la planificacin de la consulta es donde PostgreSQL realmente comienza a hacer algn trabajo. Esta etapa de controles verifican si la consulta ya esta preparada, si la versin de PostgreSQL y librerias cliente soportan esta caracterstica, funcin o consulta. Se analiza tambin el SQL para determinar cual es la forma ms eficiente para recuperar los datos. Se podra usar un Index, si es as cual debe ser?. Quizs un hashjoin en las dos tablas es lo adecuado?. Estas son algunas de las decisiones que la base de datos toma en este punto del proceso. Este paso puede ser eliminado si la consulta es previamente preparada. Ahora que PostgreSQL tiene un plan de lo que cree, es la mejor manera de recuperar los datos, es hora de hacerlo realidad. Si bien hay algunas opciones de optimizacin en este punto del proceso, la mayora de son realizadas por la configuracin de hardware. Y finalmente el ltimo paso es transmitir los resultados al cliente. Si bien no hay opciones de optimizacin real en este paso es importante tener en cuenta que todos los datos que se van a devolver son tomados desde el disco y son enviados a travs de los medios de conexin al cliente. Minimizar el nmero de filas y columnas a solo aquellas que son necesarias a menudo puede incrementar el rendimiento. Cuando inicializamos la base de datos PostgreSQL define unos valores por defecto, estos valores son muy bajos teniendo en cuenta el hardware moderno y de entrada es lo primero que se debe revisar en el momento de realizar Tuning al rendimiento del motor. La estratgia de como se debe realizar depende de la magnitud y complejidad la o las bases de datos. La informacin de Hardware es lo primero que debe obtener y as saber con que recursos disponemos. Luego revisamos que tipo de sistemas tenemos, que predomina, la consulta? la escritura?, existen procesos complejos de procesamiento? que recursos va a utilizar Apache y PHP y cuales PostgreSQL?, que cantidad de conexiones se producen simultaneamente, etc Esta informacin obetenida sumada a la configuracin actual de la mquina y a los resultados de desempeo que actualmente se tienen de la base de datos y del sistema en general nos da un punto de partida para realizar el tuning al rendimiento de postgresql. Tomando las medidas de contingecia respectivas, todo es un juego de tire y afloje. Aumente los valores de configuracin o disminuyalos, inclusive llegando a degradar el sistema y as fijar los limites de rendimiento que podemos llegar a tener. A continuacin describo las principales opciones de configuracin de PostgreSQL que unas ves comprendidas permiten realizar movimientos lgicos de configuracin en buscan de configuraciones acertadas para un sistema en particular.
Archivo de Configuracin postgresql.conf Siempre que realice cambios sobre este archivo debe reiniciar PostgreSQL En otro capitulo se describen detalladamente las principales opciones de este archivo de configuracin. Por ahora nos vamos a centrar en 3 parametros de configuracin El nmero de shared_buffers es el parmetro que ms afecta al rendimiento de PostgreSQL. Este valor, de tipo entero, indica el nmero de bloques de memoria o buffers de 8KB (8192 bytes) que postgres reservar, como zona de trabajo, en el momento del arranque para procesar las consultas. De forma predeterminada (enpostgresql.conf), su valor es de 1000. Un nmero claramente insuficiente para conseguir un rendimiento mnimamente aceptable. Estos buffers se ubican dentro de los denominados segmentos de memoria compartida. Es importante saber que el espacio ocupado por el nmero de buffers que pretendamos asignar, nunca podr exceder al tamao mximo que tengan los segmentos de memoria. En caso contrario, postgres se negar a arrancar avisando con un error que no puede reservar el espacio solicitado. Ahora de forma prctica, vamos a suponer que tenemos un server con 8GB en RAM y vamos a iniciar dejando 3GB como espacio reservado para postgres. 8GB = 8256992 (esta equivalencia solo la tomo de los datos reportados por el OS) 4GB = 8256992 / 2 = 4128496K
shared_buffers: (4128496 KB/8 KB) = 516062
Es posible que al fijar este valor a shared_buffers en el archivo postgresql.con f nos genere un error de este tipo
FATAL:
no se pudo crear el segmento de memoria compartida: Argumento invlido La llamada a sistema fallida fue shmget(key=5432001, size=112009216,
obtener un segmento de memoria compartida excedi el parmetro SHMMAX del kernel. Puede reducir el tamao de la peticin o reconfigurar el kernel con
un SHMMAX superior.
112009216 bytes), reduzca el parmetro de PostgreSQL shared_buffers (actualmente 13107) y/o el parmetro max_connections (actualmente 100). Si el tamao de la peticin ya es pequeo, es posible que sea inferior al parmetro SHMMIN del kernel, en cuyo caso se requiere alzar el tamao de la peticin o disminuir SHMMIN. La documentacin de PostgreSQL contiene ms informacin acerca de la configuracin de memoria compartida.
Nota: recuerda que este valor no debe ser fijado como formula, sino que puede se r un punto de partida. Recuerda que muchas veces hay que fijar valores tan altos (con conocimiento de causa claro esta) que hagan que el sistema no funcione ms, as encontrars los lmites de t configuracin.
El tamao ocupado por los 516062 buffers que has pedido reservar, simplemente no caben en el tamao actual de segmento (SHMMAX). Postgres en el arranque intenta reservar este espacio pero el sistema operativo no se lo permite. En Linux, de forma predeterminada, el tamao de un segmento de memoria compartida es de 32MB. Podemos comprobarlo haciendo (el resultado es en n de bytes): shell> cat /proc/sys/kernel/shmmax 33554432 Y el espacio que requiere el nmero de buffers, es superior al tamao del segmento:
516062 buffers ocupan 4227579904 (516062 * 8192 bytes/bloque) > 33554432
La solucin est en modificar el tamao mximo del segmento de memoria compartid a. Esto lo hacemos asignando un nuevo valor al parmetro del kernel SHMMAX
shell> sysctl -w kernel.shmmax=4227579904 Ahora, para fijar shmall debes ver como lo fija el mismo OS al momento de cargar, esto lo puedes ver en /usr/include/linux/shm.h. Encontrars algo como esto: #define SHMMAX 02000000 #define SHMMIN 1 /* max shared seg size (bytes) */ /* min shared seg size (bytes) */
#define SHMMNI 4096 #define SHMSEG SHMMNI Luego podemos decir que:
/* max num of segs system wide */ /* max shared segs per process */
shmall = 4227579904 / 4096 * (4096 / 16) = 264223744 // estamos hablando de cerca de 260MB frente a los 4GB de shmmax shell> sysctl -w kernel.shmall=264223744 Ahora debes guardar este valor de forma permanente en /etc/sysctl.conf, de forma que los cambios se conserven entre arranques: kernel.shmmax=4227579904 kernel.shmall=264223744 Podemos confirmar de esta forma, aunque en este punto los valores ya deben estar cargados.
sysctl -p /etc/sysctl.conf
Si necesitas ms detalles de la configuracin de los parametros del kernel puedes revisar la documentacin oficial aqu
######################################################################
La primer seccin de este archivo es FILE LOCATIONS, es fcil de interpretar, no voy a entrar en detalles. La segunda seccin es CONNECTIONS AND AUTHENTICATION. Esta seccin de conexiones se encuentra subdividida en 4 partes: tipo de conexiones, parmetros de autenticacin, kerberos y TCP. En su configuracin inicial, Postgres solo puede ser accedido desde socket unix, sin puertos TCP/IP abiertos. Conexiones listen_addresses = localhost Listado separado por comas de los host desde los cuales se aceptarn conexiones. De estar comentado ocon valor *, acepta desde cualquier host. port = 5432 Puerto en el cual esta escuchando esta instancia de Postgres. Notar que con esta directiva se puedenejecutar mltiples instancias del DBMS.
max_connections = 100 Cantidad mxima de conexiones permitidas(backends) en un mismo tiempo, sin considerar al superusuario. Aumentar este parmetro conlleva un mayor uso de memoria compartida. Al cambiar este parmetro tenga en cuenta que otros parmetros como work_men se configura con relacin a cada cliente. superuser_reserved_connections = 2 Cantidad de slots de conexin reservados para el superusuario unix_socket_directory = /var/run/postgresql Directorio de los sockets unix para esta instancia de Postgres. Note que con esta directiva se pueden ejecutar mltiples instancias del DBMS. unix_socket_group = Indica el grupo dueo de los sockets unix. unix_socket_permissions = 0777 Indica los permisos en octal de acceso a los sockets unix bonjour_name = Permite establecer el nombre del DBMS. De estar comentado o en blanco, toma el nombre el equipo host Seguridad y Autenticacin #authentication_timeout = 60 # 1-600, in seconds. Tiempo en segundos de espera por la
informacin de login. Desde 1 a 600. #ssl = true Indica si el uso de SSL es forzado. De estar comentado es falso. #password_encryption = on Flag que indica si el uso de encriptacin en el envo de la contrasea es obligatorio o no. De estarcomentado es apagado. #db_user_namespace = off Habilita la funcionalidad donde los nombres de usuario pueden ser especficos de cada base de datos, es decir, usuario@baseEjemplo quiere decir que usuario solo se aplicara a baseEjemplo y no a todas como es por defecto. Uso de Recursos En esta seccin se puede especificar la cantidad de recursos que esta instancia de PostgreSQL estaautorizada a consumir. shared_buffers = 1000 Editando esta opcin es la forma ms sencilla de mejorar el rendimiento del servidor de base de datos. El valor por defecto es muy bajo para la mayora de hardware moderno. Generalmente se dice que debera estar en alrededor del 25% de la memoria RAM disponible en el sistema. En sistemas que tengan menos de 1GB en RAM la proporcin suele ser 15%, dependiendo de la memoria que consume el sistema operativo. En algunas circunstancias se podra requerir ms del 25% pero dado que postgres tambin utiliza la memoria compartida del sistema de operativo los valores tan altos no tienen gran relevancia
frente a los valores bajos. Tenga en cuenta que para sistemas abajo de la versin 8.1 los valores altos en shared_buffers no funcionan bien, en cambio se pueden tener valores de 32MB a cerca de 400MB funcionando correctamente. Como la mayora de las opciones que se resumen aqu, simplemente tendr que probar diferentes valores, hacia arriba y haca abajo, y ver que tan bien funciona el sistema. Muchas personas van fijando valores altos hasta encontrar el valor que degrada el sistema y as ir encontrando el ideal. temp_buffers = 1000 Los buffers temporales hacen referencia a la cantidad de memoria utilizada por cada sesin de base de datos para acceder a tablas temporales. #max_prepared_transactions = 5 Se recomienda dejar por defecto.5 work_mem = 1024 Este valor se debe fijar con relacin al parmetro max_connections, si por ejemplo tiene 400 conexiones simultaneas y fija work_mem en 20MB estar utilizando 8GB de memoria compartida. Tenga en cuenta esta medida y fije el valor suficiente ya que este le permite mejorar el rendimiento de consultas de ordenamiento complejo. Por ejmeplo. maintenance_work_mem = 16384 Esta directiva en kilobytes, indica la cantidad de memoria a utilizar por las labores de mantencin como VACUUM, CREATE INDEX, restauracin de bases de datos, etc. Como no se suelen dar operaciones concurrentes de este tipo dejarlo en un valor como 256MB esta bien. max_fsm_pages = 20000 Esta opcin ayuda a controlar el Mapeo de Espacio Libre (free space map(FSM)). Cuando algo es eliminado de la tabla no es removido del disco inmediatamente. El espacio es realmente marcado como libre en el FSM. El espacio puede ser reutilizado para cualquier nuevo INSERT realizado en la tabla. Si el sistema tiene una alta tasa de INSERT y DELETE puede ser necesario aumentar este valor para evitar que las tablas aumenten desmesuradamente su tamao. max_fsm_relations = 1000 Cantidad de relaciones (tablas e ndices) de las cuales se mantiene monitoreo del espacio libre en el mapade espacio libre. Deben ser al menos 100 Ajustes a las Consultas (Query Tuning) Configuracin de las funciones del planificador. Desabilite la funcin que necesite pasando a off #enable_bitmapscan = on #enable_hashagg = on
#enable_hashjoin = on #enable_indexscan = on #enable_mergejoin = on #enable_nestloop = on #enable_seqscan = on #enable_sort = on #enable_tidscan = on Costos del planificador #effective_cache_size = 16000MB Este valor le dice al optimizador de PostgreSQL, cuanta memoria tiene asignada PostgreSQL para el almacenamiento de cache de datos y ayuda en el momento de la determinacin de si crear o no un indice. Cuanto mayor sea el valor se incrementa la probabilidad de usar un indice. Asigne la cantidad de memoria que queda luego de determinar la cantidad de memoria que se toma el sistema operativo y las dems aplicaciones que puedan existir(apache, PHP, etc). Esta memoria no es que este asignada realmente sino que es un valor que utiliza el planificador de PostgreSQL para saber si los planes que estn considerando caben en RAM. Establezcalo al 50% de la RAM y an esto es algo conservador. Un 75% se podra tener. #random_page_cost = 4 Controla la forma en que PostgreSQL ve las lecturas de disco no secuenciales. Un valor alto hace que sea ms probable que una bsqueda secuencial pueda ser realizada bajo una bsqueda de indices, indicando que el servidor tiene discos muy rpidos. #cpu_tuple_cost = 0.01 Costo de procesar una fila en una consulta. El valor esta indicado en una fraccin del costo de recuperacin de una pgina secuencial. #cpu_index_tuple_cost = 0.001 Costo de proceso de una fila durante un escaneo va ndice. El valor esta indicado en una fraccin del costo de recuperacin de una pgina secuencial. #cpu_operator_cost = 0.0025 - Costo estimado de procesar cada operador en una clusula WHERE. El valor est indicado en una fraccin del costo de recuperacin de una pgina secuencial.
Optimizador Gentico de Consulta (GEQO Genetic Query Optimizer) PostgreSQL incorpora dentro de su analizador de consultas, un algoritmo gentico para optimizacin de consultas que incorporan JOIN. Las siguientes directrices permiten ajustar el comportamiento de este algoritmo.
Los algoritmos genticos son una optimizacin heurstica que opera de forma nodeterminstica. El set desoluciones posibles para el problema se denomina poblacin, mientras que el grado de adaptacin de un individuo se llama ajuste. Las coordenadas del individuo dentro del espacio de soluciones se representa por cromosomas. Un gene es una subseccin de un cromosoma el cual codifica el valor de un nico parmetrodentro de la optimizacin. Para obtener la solucin se simula la recombinacin y mutacin de los individuos, realizndose la seleccin natural en base a aquel individuo que presenta en promedio un mayor grado de adaptacin que sus ancestros. #geqo = on Habilita o deshabilita el uso del algortmo gentico. #geqo_threshold = 12 Cantidad de elementos en la clusula FROM desde los cuales el algortmo gentico es utilizado. #geqo_effort 0 5 Controla en enteros de 1 a 10, la proporcin de tiempo que el planificador gasta en planificar y la efectivdad del mismo. Valores ms altos resultarn en un tiempo mayor de planificacin, pero tambin aumenta la probabilidad de encontrar un plan ms eficiente. #geqo_pool_size = 0 Cantidad de individuos en la poblacin, debiendo haber al menos 2. De fijarse en 0 se elige un tamao ptimo con base al esfuerzo indicado en geqo_effort #geqo_generations = 0 Controla la cantidad de generaciones(iteraciones) usadas por GEQO. Debe ser al menos 1. Fijando en 0 hace que el motor escoja un valor adecuado con base al esfuerzo indicado en geqo_effort. #geqo_selection_bias = 2.0 Ajusta la presin de seleccin dentro de la poblacin, valor de 1.5 a 2.0. #default_statistics_target = 10 Indica la cantidad de columnas a usar en el anlisis, en consultas que no se especifica o no se ha indicado va ALTER TABLE SER STATISTICS. #constraint_exclusion = off Al estar habilitado compara las condiciones de la consulta con las restricciones de la tabla impuestas en CHECK. #from _collapse_limit = 8 El planificador juntar subconsultas hacia niveles superiores si la lista resultante en la clusula FROM notiene ms elementos que este valor. Valores pequeos resultan en planificaciones ms cortas, pero menosefectivas. Es conveniente dejar este valor bajo gego_threshold. #join_collapse_limit = 8 El planificador rescribir los INNER JOINs de la consulta a items FROM, siempre y cuando el largo de la listaen esa clusula no sobrepase este valor. No tiene
efecto alguno en OUTTER JOINs. Fijar su valor a 1, inhibe la reescritura haciendo el planificador se comporte como la versin 7.3
parmetros de Autovacuum A partir de la versin 8.1 de PostgreSQL, existe un subproceso separado llamado demonio autovacuum. Este es el encargado de revisar peridicamente la tablas con modificacin considerables a su tuplas. Los datos utilizados por el demonio son aquellos generados al estar stats_start_collector y stats_row_levelencendidos. El proceso se conecta a la base de datos utilizando alguno de los slots de superusuario reservados. El subproceso realiza 2 tareas: VACUUM y ANALYZE sobre las tablas que hayan alcanzado el nivel de cambio indicado por autovacuum_vacuum_threshold y autovacuum_analyze_threshold respectivamente. autovacuum = on Indica si ejecutar el proceso autovacuum o no #autovacuum_naptime = 1 min Tiempo que duerme el proceso de autovacuum entre ejecuciones #autovacuum_vacuum_threshold = 500 Umbral para determinar cuando se aplica VACUUM a una tabla. Cuando el valor calculado de la base ms la cantidad de filas modificadas multiplicadas por el factor supera este valor, entonces se ejecuta VACUUM sobre la tabla. #autovacuum_analyze_threshold = 250 Umbral para determinar cuando se aplica ANALYZE a una tabla. Cuando el valor calculado de la base ms la cantidad de filas modificadas multiplicadas por el factor supera este valor, entonces se ejecuta ANALYZE sobre la tabla. #autovacuum_vacuum_scale_factor = 0.2 Factor por el cual se multiplican la cantidad de filas modificadas de una tabla para obtener el umbral de ejecucin de vacuum sobre esta tabla. #autovacuum_analyze_scale_factor = 0.1 Factor por el cual se multiplican la cantidad de filas modificadas de una tabla para obtener el umbral de ejecucin de analyze sobre esta tabla. Estas son las principales opciones de configuracin de PostgreSQL que impactan notoriamente el rendimiento de la base de datos. Evalue y ajuste hasta que encuentre la configuracin de mayor rendimiento para sus necesidades. Cuestiones de Hardware
Obviamente el tipo y la calidad de Hardware que se usa impacta drasticamente el rendimiento de la base de datos. Estos son algunos consejos a la hora de comprar hardware para su servidor de base de datos, en orden de importancia:
RAM Entre ms RAM se tenga debe tener ms cache de disco. Esto afecta en gran medida el rendimiento teniendo en cuenta que la memoria de E / S es miles de veces ms rpida que la E / S del disco. Disk types Definitivamente los rpidos discos SCSI Ultra-320 son la mejor opcin. Sin embargo los discos SATA de alta gama tambin son muy buenas. Los discos SATA son mucho ms econmicos y con ellos se pueden tener muchos ms ejes en su estructura de almacenamiento por el mismo precio. Disk configuration La confuguracin ms ptima es RAID 1+0 con tantos discos como sea posible y con le registro de transacciones (pg_xlog) en un disco independiente, bien sea fsico o viertual(Stripe Disk). RAID 5 no es una opcin recomendada a no ser que tenga ms de 6 discos en su volumen. Con las nuevas versiones de PostgreSQL se puede utilizar la opcin de tablespace para poner tablas, base de datos e indices en discos diferentes para mejorar el dendimiento. As como poner las tablas de uso frecuente en un disco SCSI y las menos utilizadas en discos ms lentos SATA o IDE. CPUs Entre mejor CPU se tenga mejor rendimiento, sin embargo, si su base de datos no utiliza muchas funciones complejas es mejor invertir el dinero en ms memoria RAM o un mejor sistema de discos.
En general cuanto ms RAM se tenga y ms posibilidad de conexiones de disco el sistema funcionar mejor. Esto por que entre ms RAM exista menos acceso al disco se realiza y entre ms conexiones de disco existan disponibles es posible distribuir las operaciones de lectura y escritura en disco, aumentando el rendimiento y disminuyendo los cuellos de botella. Otra buena idea es separar el cdigo de la aplicacin de la base de datos en diferente hardware. Esto significa que no solo se va a tener ms hardware disponible para la base de datos sino que la memoria cache del sistema operativo contendr ms datos PostgreSQL y no de otro tipo de aplicaciones o procesos. Por ejemplo, si usted tiene un servidor web y un servidor de base de datos se puede usar un cable cruzado por interfaces de redes exclusivas para que estos dos se comuniquen y a su vez el servidor web utiliza otra conexin diferente para comunicarse con sus clientes. Si son varios servidores web accediendo a un mismo servidor de base de datos podra armar una red independiente y esclusiva para este trfico. Una vez tengamos la mejor configuracin es ideal revisar todo tipo de consultas que recibe la base de datos y ver en que medida se puede mejorar su rendimiento. Para iniciar debe ubicar las
consultas ms repetitivas y las que ms consumen tiempo de ejecucin. En otro articulo puede encontrar ms informacin de como ubicar este tipo de consultas. Herramientas tiles para realizar Tuning a las Consultas La herrmienta ms usada para realizar Tuning a la base de datos es el comando SQL EXPLAIN ANALYZE. Este permite ver el registro de cada consulta SQL que es llevada a cabo y ver exactamente como el planificador de PostgreSQL procesa cada consulta. Veamos este ejemplo:
CREATE TABLE authors ( id name ); int4 PRIMARY KEY, varchar
author_id int4,
La salida se debe analizar de abajo hacia arriba. Lo primero que hace PostgreSQL es una bsqueda secuencial sobre la tabla books ubicando la colmna author_id con un valor igual a 16. Luego se hace un recorrido al indice de la tabla authors, el mismo indice que es creado por la PRIMARY KEY. Finalmente los resultados son ordenados por el campo books.tittle
Los valores que se ven en parntesis son el costo estimado y actual de esa parte de la consulta. Cuanto menor sea la diferencia entre estos dos valores existeme un mejor desempeo. Ahora vamos a cambiar un poco la estructura con la adicin de un Index en books.author_id y as evitar la bsqueda secuencial.
CREATE INDEX books_idx1 on books(author_id);
Si se vuelve a ejecutar la consulta de nuevo usted no vera ningn cambio notable en la salida. Estos es por que PostgreSQL no ha vuelto a analizar los datos y no ha determinado que el nuevo index puede ayudar en la consulta. Esto se puede solucionar mediante la ejecucin de:
ANALYZE books;
Puede que no note cambios en los resultados de la bsqueda en secuencia si la tabla no contiene muchos registros. Si una consulta va a retornar una gran cantidad de datos, el planificador selecciona una bsqueda en secuencia a travs del indice, ya que es ms rpido. Se puede forzar PosgreSQL a favor de las bsquedas por indices sobre las bsquedas secuenciales fijando el parmetro de configuracin enable_seqscan = off . Esto no quita todas las bsquedas por secuencia ya que algunas tablas pueden no tener indices pero si fuerza al planificador a utilizar siempre una bsqueda por indices cuando estos estn disponibles y sin importar si la cantidad de datos a retornar es mnima. Es recomendable hacer este cambio en la parte inicial de cada conexin con a la base de datos, por medio del comando SET enable_seqscan = off , y no hacerlo ampliamente en todas las bases de datos. Sin embargo desactivas esta opcin se hace en casos de pruebas y de realizacin de Tuning y no como opcin de uso diario. Generalmente la mejor forma de optimizar las consultas es usar indices en colmnas especficas y combinaciones de colmnas que corresponden a las consultas ms frecuentes. Lamentablemente esto se hace por ensayo y error. Tambin debe tener en cuenta que incrementar el nmero de indices en una tabla incrementa el nmero de operaciones de escritura que se deben realizar para cada INSERT y UPDATE. As que no haga cosas tontas como agregar indices a todas las colmnas de una tabla. Algo que puede ayudar es jugar con el nivel de las estadsticas que se recogen en una tabla o columna con el comando:
ALTER TABLE <table> ALTER COLUMN <column> SET STATISTICS <number>;
Este valor puede ser un nmero entre 0 y 1000 y ayuda a PostgreSQL a determinar el nivel de recopilacin de estadsticas que se debe realizar en esta columna. Esto ayuda a controlar la
generacin del plan de la consulta sin tener VACUUM lentos y analizar las operaciones debido a la generacin de grandes cantidades de estadsticas para todas las tablas y columnas. Otra herramienta til para ayudar a determinar como hacer Tuning a la base de datos son las consultas al registro del sistema. Se puede decir a PostgreSQL que consultas del registro nos interesan a travs de la opcin de configuracin de log_statement. Esto es muy til en situaciones donde hay muchos usuarios realizando consultas tipo ad hoc() en el sistema a travs de algo como Crystal Reports o directamente va PSQL. Diseo y estructura de la base de datos A veces el diseo y la estructura de la base de datos afecta el rendimiento. Por ejemplo si usted tiene una tabla como la que se muestra a continuacin:
CREATE TABLE employees ( id int4 PRIMARY KEY, active boolean, first_name varchar, middle_ name varchar, last_name varchar, ssn varchar, address1 varchar, address2 varchar, city va rchar, state varchar(2), zip varchar, home_phone varchar, work_phone varchar, cell_phone varchar, fax_phone varchar, pager_number varchar, business_email varchar, personal_email varchar, salary int4, vacation_days int2, sick_days int2, employee_number int4, office_ad dr_1 varchar, office_addr_2 varchar, office_city varchar, office_state varchar(2), office _zip varchar, department varchar, title varchar, supervisor_id int4 );
El diseo es fcil de entender, pero no es muy bueno en varios niveles. Si bien depender de la aplicacin en particular, en la mayora de casos usted no nececita acceder a todos los datos al mismo tiempo. Al romper esta tabla en tablas ms pequeas se puede conseguir que las consultas sean ms eficientes ya que PostgreSQL tiene que leer menos y eso sin tocar otros aspectos de funcionalidad. Esta es una mejor manera de hacer las cosas:
CREATE TABLE employees ( id int4 PRIMARY KEY, active boolean, employee_number int4, first _name varchar, middle_name varchar, last_name varchar, department varchar, title varchar, email varchar ); CREATE TABLE employee_address ( id int4 PRIMARY KEY, employee_id int4, p ersonal boolean, address_1 varchar, address_2 varchar, city varchar, state varchar(2), zi p varchar ); CREATE TABLE employee_number_type ( id int4 PRIMARY KEY, type varchar ); CRE ATE TABLE employee_number ( id int4 PRIMARY KEY, employee_id int4, type_id int4, number v archar ); CREATE TABLE employee_hr_info ( id int4 PRIMARY KEY, employee_id int4, ssn varc har, salary int4, vacation_days int2, sick_days int2 );
De esta manera esta unidad de informacin esta divida en grupos lgicos. La tabla principal contiene la informacin ms utilizada y las otras tablas almacenan el resto de informacin. El beneficio adional de este diseo es que puede tener cualquier cantidad de telfonos y direcciones asociadas a un solo empleado de la tabla principal.
Otro consejo til es utilizar los indices parciales en las columnas donde se consulta un cierto valor con mayor frecuencia que otros. Tomemos, por ejemplo, la tabla empleados de arriba. probablemente casi siempre se consultan los empleados que tengan estado activo, pero creando un indice parcial para la columna cuando el valor es verdadero ayuda a incrementar la velocidad de la consulta y puede ayudar a que el planeador decida usa el index en los casos en que de otro modo no lo hara. Un index parcial se puede crear de la siguiente manera:
CREATE INDEX employee_idx2 ON employee(active) WHERE active='t';