Professional Documents
Culture Documents
Tuning PostgreSQL With Pgbench
Tuning PostgreSQL With Pgbench
When it comes to performance tuning an environment, often the first place to start is
with the database. The reason for this is that most applications rely very heavily on a
database of some sort.
Unfortunately, databases can be one of the most complex areas to tune. The reason I say
that is because tuning a database service properly often involves tuning more than the
database service itself; it often requires making hardware, OS, or even application
modifications.
On top of requiring a diverse skill set, one of the biggest challenges with tuning a
database is creating enough simulated database traffic to stress the database service.
Which is why today’s article will explore pgbench, a benchmarking tool used to measure
performance of a PostgreSQL instance.
PostgreSQL is a highly popular open-source relational database. One of the nice things
about PostgreSQL is that there are quite a few tools that have been created to assist with
the management of PostgreSQL; pgbench is one such tool.
While exploring pgbench, we will also use it to measure the performance gains/loss for a
common PostgreSQL tunable.
With the packages installed, we now have a running PostgreSQL instance. We can verify
this by using the systemctl command to check the status of PostgreSQL.
The above indicates our instance started without any issues. We can now move on to our
next step, creating a database.
Creating a database
When we installed the postgresql package, this package included the creation of a user
named postgres. This user is used as the owner of the running instance. It also serves as
the admin user for the PostgreSQL service.
In order to create a database, we will need to login to this user, which is accomplished by
executing the su command.
# su - postgres
Once switched to the postgres user, we can log in to the running instance by using the
PostgreSQL client, psql.
$ psql
psql (9.5.5)
Type "help" for help.
postgres=#
postgres-# \list
List of databases
Name | Owner | Encoding | Collate | Ctype | Access
privileges
-----------+----------+----------+-------------+-------------
+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres
+
| | | | |
postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres
+
| | | | |
postgres=CTc/postgres
(3 rows)
After issuing the \list command, three databases were returned. These are default
databases that were set up during the initial installation process.
For our testing today, we will be creating a new database. Let’s go ahead and create that
database, naming it example. We can do so by issuing the following SQL statement:
Once executed, we can validate that the database has been created by issuing
the \list command again.
postgres=# \list
List of databases
Name | Owner | Encoding | Collate | Ctype | Access
privileges
-----------+----------+----------+-------------+-------------
+-----------------------
example | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres
+
| | | | |
postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres
+
| | | | |
postgres=CTc/postgres
(4 rows)
At this point, we now have an empty database named example. From this point, we will
need to return to our bash shell to execute pgbench commands. We can do this by
issuing the \q (quit) command.
postgres-# \q
Once logged out of the PostgreSQL command line environment, we can get started
using pgbench to benchmark our database instance’s performance.
For situations such as this, tools like pgbench come in handy. With pgbench, you can
either use a sample database provided with pgbench or have pgbench run custom
queries against an application database.
In this article, we will be using the example database that comes with pgbench.
The set up of the sample database is quite easy and fairly quick. We can start this process
by executing pgbench with the -i (initialize) option.
$ pgbench -i -s 50 example
creating tables...
5000000 of 5000000 tuples (100%) done (elapsed 5.33 s, remaining 0.00 s)
vacuum...
set primary keys...
done.
table # of rows
---------------------------------
pgbench_branches 1
pgbench_tellers 10
pgbench_accounts 100000
pgbench_history 0
By default, pgbench will create the tables above with the number of rows shown above.
This creates a simple 16MB database.
The -s option is used to multiply the number of rows entered into each table. In the
command above, we entered a “scaling” option of 50. This told pgbench to create a
database with 50 times the default size.
To verify that our tables have been created successfully, let’s go ahead and run
the psql client again.
$ psql -d example
psql (9.5.5)
Type "help" for help.
example=#
In the command above, we used the -d (database) flag to tell psql to not only connect to
the PostgreSQL service but to also switch to the example database.
example=# \dt
List of relations
Schema | Name | Type | Owner
--------+------------------+-------+----------
public | pgbench_accounts | table | postgres
public | pgbench_branches | table | postgres
public | pgbench_history | table | postgres
public | pgbench_tellers | table | postgres
(4 rows)
From the table above, we can see that pgbench created the four expected tables. This
means our database is now populated and ready to be used to measure our database
instance’s performance.
Establishing a baseline
When doing any sort of performance tuning, it is best to first establish a baseline
performance. This baseline will serve as a measurement as to whether or not the changes
you have performed have increased or decreased performance.
Let’s go ahead and call pgbench to establish the baseline for our “out of the box”
PostgreSQL instance.
When calling pgbench, we add quite a few options to the command. The first is -
c (clients), which is used to define the number of clients to connect with. For this testing,
I used 10 to tell pgbench to execute with 10 clients.
What this means is that when pgbench is executing tests, it opens 10 different sessions.
The next option is the -j (threads) flag. This flag is used to define the number of worker
processes for pgbench. In the above command, I specified the value of 2. This will
tell pgbench to start two worker processes during the benchmarking.
The third option used is -t (transactions), which is used to specify the number of
transactions to execute. In the command above, I provided the value of 10,000.
However this doesn’t mean that only 10,000 transactions will be executed against our
database service. What it means is that each client session will
execute 10,000 transactions.
With that understanding, let’s take a look at the results of this first test.
The output of pgbench has quite a bit of information. Most of it describes the test
scenarios being executed. The part that we are most interested in is the following:
From these results, it seems our baseline is 2,394 database transactions per second. Let’s
go ahead and see if we can increase this number by modifying a simple configuration
parameter within PostgreSQL.
# - Memory -
Let’s go ahead and switch this value to 256MB, effectively doubling our available cache
space.
# - Memory -
Once the service is fully up and running, we can once again use pgbench to measure our
performance.
In our earlier baseline test, we were able to hit a rate of 2,394 transactions per second. In
this last run, after updating the shared_buffers parameter, we were able to
achieve 2,550 transactions per second, an increase of 156. While this is not a bad start,
we can still go further.
In the output above, we can see that the total column shows a value of 2000MB on the
row for memory. This column shows the total physical memory available to the system.
We can also see in the available column that 1223MB is showing available. This means
we have up to 1.2 GB of free memory we can use for our tuning purposes.
# - Memory -
This time, our system was able to reach 2,662 transactions per second, an additional
increase of 112 transactions per second. Since our transactions per second increased by
at least 100 both times, let’s go a step further and see what happens when changing this
value to 1GB.
# - Memory -
After updating the value, we will need to once again restart the PostgreSQL service.
Summary
Based on the results of our testing, we can see that changing the value of
the shared_buffers from 128MB to 512MB on our test system resulted in
a 268 transactions per second increase in performance. Based on our baseline results,
that is a 10 percent increase in performance.