pgslice
Postgres partitioning as easy as pie
Install
Run:
gem install pgslice
Steps
- Specify your database credentials
export PGSLICE_URL=postgres://localhost/myapp_development
- Create an intermediate table
pgslice prep <table> <column> <period>
Period can be day
or month
.
This creates a table named <table>_intermediate
with the appropriate trigger for partitioning.
- Add partitions
pgslice add_partitions <table> --intermediate --past 3 --future 3
This creates child tables that inherit from the intermediate table.
Use the --past
and --future
options to control the number of partitions.
- Optional, for tables with data - Fill the partitions in batches with data from the original table
pgslice fill <table>
Use the --batch-size
and --sleep
options to control the speed.
- Swap the intermediate table with the original table
pgslice swap <table>
The original table is renamed <table>_retired
and the intermediate table is renamed <table>
.
- Fill the rest
pgslice fill <table> --swapped
- Archive and drop the original table
Adding Partitions
To add partitions, use:
pgslice add_partitions <table> --future 3
Additional Commands
To undo prep (which will delete partitions), use:
pgslice unprep <table>
To undo swap, use:
pgslice unswap <table>
Sample Output
pgslice
prints the SQL commands that were executed on the server. To print without executing, use the --dry-run
option.
$ pgslice prep locations created_at day
BEGIN;
CREATE TABLE locations_intermediate (
LIKE locations INCLUDING ALL
);
CREATE FUNCTION locations_insert_trigger()
RETURNS trigger AS $$
BEGIN
EXECUTE 'INSERT INTO public.locations_' || to_char(NEW.created_at, 'YYYYMMDD') || ' VALUES ($1.*)' USING NEW;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER locations_insert_trigger
BEFORE INSERT ON locations_intermediate
FOR EACH ROW EXECUTE PROCEDURE locations_insert_trigger();
COMMIT;
$ pgslice add_partitions locations --intermediate --past 1 --future 1
BEGIN;
CREATE TABLE locations_20160423 (
CHECK (created_at >= '2016-04-23'::date AND created_at < '2016-04-24'::date)
) INHERITS (locations_intermediate);
ALTER TABLE locations_20160423 ADD PRIMARY KEY (id);
CREATE INDEX ON locations_20160423 USING btree (updated_at, shopper_id);
CREATE TABLE locations_20160424 (
CHECK (created_at >= '2016-04-24'::date AND created_at < '2016-04-25'::date)
) INHERITS (locations_intermediate);
ALTER TABLE locations_20160424 ADD PRIMARY KEY (id);
CREATE INDEX ON locations_20160424 USING btree (updated_at, shopper_id);
CREATE TABLE locations_20160425 (
CHECK (created_at >= '2016-04-25'::date AND created_at < '2016-04-26'::date)
) INHERITS (locations_intermediate);
ALTER TABLE locations_20160425 ADD PRIMARY KEY (id);
CREATE INDEX ON locations_20160425 USING btree (updated_at, shopper_id);
COMMIT;
$ pgslice swap locations
BEGIN;
ALTER TABLE locations RENAME TO locations_retired;
ALTER TABLE locations_intermediate RENAME TO locations;
COMMIT;
Upgrading
Run:
gem install pgslice
To use master, run:
gem install specific_install
gem specific_install ankane/pgslice
TODO
- Command to sync index changes with partitions
- Disable indexing for faster
fill
Contributing
Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features