项目作者: aliou

项目描述 :
Rails + Postgres partitions
高级语言: Ruby
项目地址: git://github.com/aliou/tablature.git
创建时间: 2018-06-23T18:27:41Z
项目社区:https://github.com/aliou/tablature

开源协议:MIT License

下载


Tablature

Tablature is a library built on top of ActiveRecord to simplify management of partitioned tables in Rails applications.
It ships with Postgres support and can easily supports other databases through adapters.

Status

Tablature is a learning project is not currently used in production. It is probably not production-ready, YMMV.

Installation

Requirements

Tablature requires Ruby 2.5+, Rails 5+ and Postgres 10+.

Installation

Add this line to your application’s Gemfile:

  1. gem 'tablature'

And then execute:

  1. $ bundle

Or install it yourself as:

  1. $ gem install tablature

Usage

Partitioning a table

  1. class CreateEvents < ActiveRecord::Migration[5.0]
  2. def up
  3. # Create the events table as a partitioned table using range as partitioning method
  4. # and `event_date` as partition key.
  5. create_range_partition :events_by_range, partition_key: 'event_date' do |t|
  6. t.string :event_type, null: false
  7. t.integer :value, null: false
  8. t.date :event_date, null: false
  9. end
  10. # Create partitions with the bounds of the partition.
  11. create_range_partition_of :events_by_range,
  12. name: 'events_range_y2018m12', range_start: '2018-12-01', range_end: '2019-01-01'
  13. # Create the events table as a partitioned table using list as partitioning method
  14. # and `event_date` as partition key.
  15. create_list_partition :events_by_list, partition_key: 'event_date' do |t|
  16. t.string :event_type, null: false
  17. t.integer :value, null: false
  18. t.date :event_date, null: false
  19. end
  20. # Create partitions with the bounds of the partition.
  21. create_list_partition_of :events_by_list,
  22. name: 'events_list_y2018m12', values: (Date.parse('2018-12-01')..Date.parse('2018-12-31')).to_a
  23. end
  24. def down
  25. drop_table :events_by_range
  26. drop_table :events_by_list
  27. end
  28. end

Having a partition back a model

In your migration:

  1. # db/migrate/create_events.rb
  2. class CreateEvents < ActiveRecord::Migration
  3. def change
  4. # You can use blocks when the partition key are SQL expression instead of
  5. # being only a field.
  6. create_range_partition :events, partition_key: -> { '(timestamp::DATE)' } do |t|
  7. t.string :event_type, null: false
  8. t.integer :value, null: false
  9. t.datetime :timestamp, null: false
  10. t.timestamps
  11. end
  12. create_range_partition_of :events,
  13. name: 'events_y2018m12', range_start: '2018-12-01', range_end: '2019-01-01'
  14. create_range_partition_of :events,
  15. name: 'events_y2019m01', range_start: '2019-01-01', range_end: '2019-02-01'
  16. end
  17. end

In your model, calling one of range_partition or list_partition to inject
methods:

  1. # app/models/event.rb
  2. class Event < ApplicationRecord
  3. range_partition
  4. end

Finally, you can now list the partitions :

  1. >> Event.partitions
  2. # => ["events_y2018m12", "events_y2019m01"]

You can also create new partitions directly from the model :

  1. >> Event.create_range_partition(
  2. name: 'events_y2019m02',
  3. range_start: '2019-02-01'.to_date,
  4. range_end: '2019-03-01'.to_date
  5. )
  6. # => ...
  7. >> Event.partitions
  8. # => ["events_y2018m12", "events_y2019m01", "events_y2019m02"]

Partitioning an existing table

Start by renaming your table and create the partition table:

  1. class PartitionEvents < ActiveRecord::Migration
  2. def change
  3. # Get the bounds of the events.
  4. min_month = Event.minimum(:timestamp).beginning_of_month.to_date
  5. max_month = Event.maximum(:timestamp).beginning_of_month.to_date
  6. # Create the partition bounds based on the existing data. In this example,
  7. # we generate an array with the ranges.
  8. months = min_month.upto(max_month).uniq(&:beginning_of_month)
  9. # Rename the existing table.
  10. rename_table :events, :old_events
  11. # Create the partitioned table.
  12. create_range_partition :events, partition_key: -> { '(timestamp::DATE)' } do |t|
  13. t.string :event_type, null: false
  14. t.integer :value, null: false
  15. t.datetime :timestamp, null: false
  16. t.timestamps
  17. end
  18. # Create the partitions based on the bounds generated before:
  19. months.each do |month|
  20. # Creates a name like "events_y2018m12"
  21. partition_name = "events_y#{month.year}m#{month.month}"
  22. create_range_partition_of :events,
  23. name: partition_name, range_start: month, range_end: month.next_month
  24. end
  25. # Finally, add the rows from the old table to the new partitioned table.
  26. # This might take some time depending on the size of your old table.
  27. execute(<<~SQL)
  28. INSERT INTO events
  29. SELECT * FROM old_events
  30. SQL
  31. end
  32. end

Development

After checking out the repo, run bin/setup to install dependencies.
Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Acknowledgements

Tablature’s structure is heavily inspired by Scenic and F(x).
Tablature’s features are heavily inspired by PgParty.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/aliou/tablature.

License

The gem is available as open source under the terms of the MIT License.