partitioned 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +17 -0
- data/LICENSE +30 -0
- data/PARTITIONING_EXPLAINED.txt +351 -0
- data/README +111 -0
- data/Rakefile +27 -0
- data/examples/README +23 -0
- data/examples/company_id.rb +417 -0
- data/examples/company_id_and_created_at.rb +689 -0
- data/examples/created_at.rb +590 -0
- data/examples/created_at_referencing_awards.rb +1000 -0
- data/examples/id.rb +475 -0
- data/examples/lib/by_company_id.rb +11 -0
- data/examples/lib/command_line_tool_mixin.rb +71 -0
- data/examples/lib/company.rb +29 -0
- data/examples/lib/get_options.rb +44 -0
- data/examples/lib/roman.rb +41 -0
- data/examples/start_date.rb +621 -0
- data/init.rb +1 -0
- data/lib/monkey_patch_activerecord.rb +92 -0
- data/lib/monkey_patch_postgres.rb +73 -0
- data/lib/partitioned.rb +26 -0
- data/lib/partitioned/active_record_overrides.rb +34 -0
- data/lib/partitioned/bulk_methods_mixin.rb +288 -0
- data/lib/partitioned/by_created_at.rb +13 -0
- data/lib/partitioned/by_foreign_key.rb +21 -0
- data/lib/partitioned/by_id.rb +35 -0
- data/lib/partitioned/by_integer_field.rb +32 -0
- data/lib/partitioned/by_monthly_time_field.rb +23 -0
- data/lib/partitioned/by_time_field.rb +65 -0
- data/lib/partitioned/by_weekly_time_field.rb +30 -0
- data/lib/partitioned/multi_level.rb +20 -0
- data/lib/partitioned/multi_level/configurator/data.rb +14 -0
- data/lib/partitioned/multi_level/configurator/dsl.rb +32 -0
- data/lib/partitioned/multi_level/configurator/reader.rb +162 -0
- data/lib/partitioned/multi_level/partition_manager.rb +47 -0
- data/lib/partitioned/partitioned_base.rb +354 -0
- data/lib/partitioned/partitioned_base/configurator.rb +6 -0
- data/lib/partitioned/partitioned_base/configurator/data.rb +62 -0
- data/lib/partitioned/partitioned_base/configurator/dsl.rb +628 -0
- data/lib/partitioned/partitioned_base/configurator/reader.rb +209 -0
- data/lib/partitioned/partitioned_base/partition_manager.rb +138 -0
- data/lib/partitioned/partitioned_base/sql_adapter.rb +286 -0
- data/lib/partitioned/version.rb +3 -0
- data/lib/tasks/desirable_tasks.rake +4 -0
- data/partitioned.gemspec +21 -0
- data/spec/dummy/.rspec +1 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +9 -0
- data/spec/dummy/app/assets/stylesheets/application.css +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +51 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +32 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +30 -0
- data/spec/dummy/config/environments/production.rb +60 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/spec/spec_helper.rb +27 -0
- data/spec/monkey_patch_posgres_spec.rb +176 -0
- data/spec/partitioned/bulk_methods_mixin_spec.rb +512 -0
- data/spec/partitioned/by_created_at_spec.rb +62 -0
- data/spec/partitioned/by_foreign_key_spec.rb +95 -0
- data/spec/partitioned/by_id_spec.rb +97 -0
- data/spec/partitioned/by_integer_field_spec.rb +143 -0
- data/spec/partitioned/by_monthly_time_field_spec.rb +100 -0
- data/spec/partitioned/by_time_field_spec.rb +182 -0
- data/spec/partitioned/by_weekly_time_field_spec.rb +100 -0
- data/spec/partitioned/multi_level/configurator/dsl_spec.rb +88 -0
- data/spec/partitioned/multi_level/configurator/reader_spec.rb +147 -0
- data/spec/partitioned/partitioned_base/configurator/dsl_spec.rb +459 -0
- data/spec/partitioned/partitioned_base/configurator/reader_spec.rb +513 -0
- data/spec/partitioned/partitioned_base/sql_adapter_spec.rb +204 -0
- data/spec/partitioned/partitioned_base_spec.rb +173 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/shared_example_spec_helper_for_integer_key.rb +137 -0
- data/spec/support/shared_example_spec_helper_for_time_key.rb +147 -0
- data/spec/support/tables_spec_helper.rb +47 -0
- metadata +250 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
begin
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
rescue LoadError
|
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
6
|
+
end
|
|
7
|
+
begin
|
|
8
|
+
require 'rdoc/task'
|
|
9
|
+
rescue LoadError
|
|
10
|
+
require 'rdoc/rdoc'
|
|
11
|
+
require 'rake/rdoctask'
|
|
12
|
+
RDoc::Task = Rake::RDocTask
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
17
|
+
rdoc.title = 'Partitioned'
|
|
18
|
+
rdoc.options << '--line-numbers'
|
|
19
|
+
rdoc.rdoc_files.include('README')
|
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
Bundler::GemHelper.install_tasks
|
|
27
|
+
|
data/examples/README
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
The directory holds examples of how to use the partitioned gem.
|
|
2
|
+
|
|
3
|
+
The lib directory contains:
|
|
4
|
+
by_company_id.rb - a partitioned model where the partition's key is the column company_id that references companies.
|
|
5
|
+
company.rb - an ActiveRecord model for the table companies.
|
|
6
|
+
roman.rb - some helper routines for generating roman numerals.
|
|
7
|
+
|
|
8
|
+
This directory holds executable rails scripts that create and populate partitioned tables. The scripts accept the following
|
|
9
|
+
parameters:
|
|
10
|
+
--force delete used tables before starting
|
|
11
|
+
--cleanup delete used tables and exit
|
|
12
|
+
|
|
13
|
+
The scripts are:
|
|
14
|
+
company_id.rb - table 'employees' partitioned by company_id
|
|
15
|
+
company_id_and_created_at.rb - table 'employees' has multi-level partitioning by company_id then created_at
|
|
16
|
+
created_at is grouped by week where weeks start on Monday.
|
|
17
|
+
created_at.rb - table 'employees' partitioned by created_at
|
|
18
|
+
created_at is grouped by week where weeks start on Monday.
|
|
19
|
+
created_at_referencing_awards.rb - table 'employees' partitioned by created_at and table 'awards' is partitioned
|
|
20
|
+
by created_at which a reference to specific child table of employees with the
|
|
21
|
+
created_at range.
|
|
22
|
+
id.rb - partitioned on 'id' grouping each 10 records into separate child tables.
|
|
23
|
+
start_date.rb - grouped by column start_date which is a date grouped by month.
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
#!/usr/bin/env ../spec/dummy/script/rails runner
|
|
2
|
+
# if you use linux, please change previous line to the
|
|
3
|
+
# "#! ../spec/dummy/script/rails runner"
|
|
4
|
+
|
|
5
|
+
# Before running this example you should execute "bundle install" and "rake db:create".
|
|
6
|
+
# To run this example you should open 'example' directory and execute example with one of the following flags:
|
|
7
|
+
# -C cleanup data in database and exit;
|
|
8
|
+
# -F cleanup data in database before creating new data;
|
|
9
|
+
#
|
|
10
|
+
# For example:
|
|
11
|
+
# ./company_id.rb - F
|
|
12
|
+
|
|
13
|
+
# Initial data:
|
|
14
|
+
#
|
|
15
|
+
# Companies table is completed by four companies:
|
|
16
|
+
#
|
|
17
|
+
# create table companies (
|
|
18
|
+
# id serial not null primary key,
|
|
19
|
+
# created_at timestamp not null default now(),
|
|
20
|
+
# updated_at timestamp,
|
|
21
|
+
# name text null
|
|
22
|
+
# );
|
|
23
|
+
#
|
|
24
|
+
# insert into companies (created_at,id,name) values
|
|
25
|
+
# ('2012-03-13 13:26:52.184347',1,'Fluent Mobile, inc.'),
|
|
26
|
+
# ('2012-03-13 13:26:52.184347',2,'Fiksu, inc.'),
|
|
27
|
+
# ('2012-03-13 13:26:52.184347',3,'AppExchanger, inc.'),
|
|
28
|
+
# ('2012-03-13 13:26:52.184347',4,'FreeMyApps, inc.');
|
|
29
|
+
#
|
|
30
|
+
# id | created_at | updated_at | name
|
|
31
|
+
# ---+----------------------------+------------+---------------------
|
|
32
|
+
# 1 | 2012-03-11 13:26:52.184347 | | Fluent Mobile, inc.
|
|
33
|
+
# 2 | 2012-03-11 13:26:52.184347 | | Fiksu, inc.
|
|
34
|
+
# 3 | 2012-03-11 13:26:52.184347 | | AppExchanger, inc.
|
|
35
|
+
# 4 | 2012-03-11 13:26:52.184347 | | FreeMyApps, inc.
|
|
36
|
+
#
|
|
37
|
+
# Employees table is associated with companies table via key - id:
|
|
38
|
+
#
|
|
39
|
+
# create table employees (
|
|
40
|
+
# id serial not null primary key,
|
|
41
|
+
# created_at timestamp not null default now(),
|
|
42
|
+
# updated_at timestamp,
|
|
43
|
+
# name text not null,
|
|
44
|
+
# salary money not null,
|
|
45
|
+
# company_id integer not null
|
|
46
|
+
# );
|
|
47
|
+
#
|
|
48
|
+
# id | created_at | updated_at | name | salary | company_id
|
|
49
|
+
# ----+------------+------------+------+--------+------------
|
|
50
|
+
#
|
|
51
|
+
# Task:
|
|
52
|
+
#
|
|
53
|
+
# To increase the speed of requests to the database and to reduce the time
|
|
54
|
+
# of the request, need to split the Employees table to the partition tables.
|
|
55
|
+
# Break criterion is a company (company_id).
|
|
56
|
+
#
|
|
57
|
+
# Implementation:
|
|
58
|
+
#
|
|
59
|
+
# Class Employee inherits from the abstract class ByCompanyId,
|
|
60
|
+
# which supports partitioning.
|
|
61
|
+
#
|
|
62
|
+
# class Employee < ByCompanyId
|
|
63
|
+
#
|
|
64
|
+
# Indicates a relationship to the companies table.
|
|
65
|
+
# belongs_to :company, :class_name => 'Company'
|
|
66
|
+
#
|
|
67
|
+
# Create a rules for each partition.
|
|
68
|
+
# Id is a unique index. Foreign key is company_id.
|
|
69
|
+
# This imposes a restriction on each of partition, that
|
|
70
|
+
# the column company_id associated with the table of companies
|
|
71
|
+
# and can not have values that are not in the table companies.
|
|
72
|
+
# In this example, set up only 4 records in the table companies,
|
|
73
|
+
# so company_id can not be equal to 5 in any partition
|
|
74
|
+
# until it is an established company with id = 5.
|
|
75
|
+
# end
|
|
76
|
+
#
|
|
77
|
+
# Create a schema employees_partitions, within which to store all of our partitions:
|
|
78
|
+
#
|
|
79
|
+
# Employee.create_infrastructure
|
|
80
|
+
#
|
|
81
|
+
# Create a partitions for each company:
|
|
82
|
+
#
|
|
83
|
+
# company_ids = Company.all.map(&:id)
|
|
84
|
+
# Employee.create_new_partition_tables(company_ids)
|
|
85
|
+
#
|
|
86
|
+
# Each of partition has the same structure as that of the employees table:
|
|
87
|
+
#
|
|
88
|
+
# id | created_at | updated_at | name | salary | company_id
|
|
89
|
+
# ----+------------+------------+------+--------+------------
|
|
90
|
+
#
|
|
91
|
+
# CREATE TABLE "employees_partitions"."p1" (CHECK (( company_id = 1 ))) INHERITS (employees);
|
|
92
|
+
# CREATE UNIQUE INDEX "index_employees_partitions.p1_on_id" ON "employees_partitions"."p1" ("id");
|
|
93
|
+
# ALTER TABLE employees_partitions.p1 add foreign key (company_id) references companies(id);
|
|
94
|
+
#
|
|
95
|
+
# CREATE TABLE "employees_partitions"."p2" (CHECK (( company_id = 2 ))) INHERITS (employees);
|
|
96
|
+
# CREATE UNIQUE INDEX "index_employees_partitions.p2_on_id" ON "employees_partitions"."p2" ("id");
|
|
97
|
+
# ALTER TABLE employees_partitions.p2 add foreign key (company_id) references companies(id);
|
|
98
|
+
#
|
|
99
|
+
# CREATE TABLE "employees_partitions"."p3" (CHECK (( company_id = 3 ))) INHERITS (employees);
|
|
100
|
+
# CREATE UNIQUE INDEX "index_employees_partitions.p3_on_id" ON "employees_partitions"."p3" ("id");
|
|
101
|
+
# ALTER TABLE employees_partitions.p3 add foreign key (company_id) references companies(id);
|
|
102
|
+
#
|
|
103
|
+
# CREATE TABLE "employees_partitions"."p4" (CHECK (( company_id = 4 ))) INHERITS (employees);
|
|
104
|
+
# CREATE UNIQUE INDEX "index_employees_partitions.p4_on_id" ON "employees_partitions"."p4" ("id");
|
|
105
|
+
# ALTER TABLE employees_partitions.p4 add foreign key (company_id) references companies(id);
|
|
106
|
+
#
|
|
107
|
+
# Since we have done four records of companies in the table,
|
|
108
|
+
# we have four partitions:
|
|
109
|
+
#
|
|
110
|
+
# employees_partitions.p1
|
|
111
|
+
# employees_partitions.p2
|
|
112
|
+
# employees_partitions.p3
|
|
113
|
+
# employees_partitions.p4
|
|
114
|
+
#
|
|
115
|
+
# Each of partitions inherits from employees table,
|
|
116
|
+
# thus a new row will automatically be added to the employees table .
|
|
117
|
+
#
|
|
118
|
+
# To add data, we use the following constructions,
|
|
119
|
+
# in which employees and employee_data - a random data:
|
|
120
|
+
#
|
|
121
|
+
# create_many - allows you to add multiple records
|
|
122
|
+
# Employee.create_many(employees)
|
|
123
|
+
# create - allows you to add one record
|
|
124
|
+
# Employee.create(employee_data)
|
|
125
|
+
# new/save! - allows you to add one record without using "create" method
|
|
126
|
+
# employee = Employee.new(employee_data)
|
|
127
|
+
# employee.save!
|
|
128
|
+
#
|
|
129
|
+
# For update data, we use the following constructions,
|
|
130
|
+
# in which updates - a random data:
|
|
131
|
+
#
|
|
132
|
+
# update_many - allows you to update multiple records.
|
|
133
|
+
# :set_array - additional option, you may read the description
|
|
134
|
+
# of the method in the file update_many bulk_methods_mixin.rb about this option.
|
|
135
|
+
# Employee.update_many(updates, { :set_array => '"salary = #{table_name}.salary +
|
|
136
|
+
# datatable.salary, updated_at = now()"' })
|
|
137
|
+
#
|
|
138
|
+
# This construction using for update one record. You also may use update method.
|
|
139
|
+
# employee = Employee.from_partition(employee_record[:company_id]).find(employee_record[:id])
|
|
140
|
+
# employee.save
|
|
141
|
+
#
|
|
142
|
+
# The data get into the employees table ONLY through partition tables.
|
|
143
|
+
# You can not do an insert row into a table employees directly.
|
|
144
|
+
# For this purpose special restrictions are imposed on the table employees.
|
|
145
|
+
#
|
|
146
|
+
# Result:
|
|
147
|
+
#
|
|
148
|
+
# We have table companies:
|
|
149
|
+
#
|
|
150
|
+
# id | created_at | updated_at | name
|
|
151
|
+
# ---+----------------------------+------------+---------------------
|
|
152
|
+
# 1 | 2012-03-11 13:26:52.184347 | | Fluent Mobile, inc.
|
|
153
|
+
# 2 | 2012-03-11 13:26:52.184347 | | Fiksu, inc.
|
|
154
|
+
# 3 | 2012-03-11 13:26:52.184347 | | AppExchanger, inc.
|
|
155
|
+
# 4 | 2012-03-11 13:26:52.184347 | | FreeMyApps, inc.
|
|
156
|
+
#
|
|
157
|
+
# Table employees with random data from 1 to 5000:
|
|
158
|
+
#
|
|
159
|
+
# id | created_at | updated_at | name | salary | company_id
|
|
160
|
+
#------+----------------------------+----------------------------+-------------------------------------+-------------+------------
|
|
161
|
+
# 1 | 2012-03-26 11:26:30.704959 | 2012-03-26 11:26:45.519874 | Winston J. Sillypants, I | $106,363.00 | 4
|
|
162
|
+
# 2 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, II | $103,767.00 | 3
|
|
163
|
+
# 3 | 2012-03-26 11:26:30.704959 | 2012-03-26 11:26:43.250032 | Winston J. Sillypants, III | $128,998.00 | 1
|
|
164
|
+
# ...
|
|
165
|
+
# 4998 | 2012-03-26 11:26:40.43347 | 2012-03-26 11:26:44.570338 | Picholine Pimplenad, MMMMCMXCVIII | $93,628.00 | 3
|
|
166
|
+
# 4999 | 2012-03-26 11:26:40.437824 | 2012-03-26 11:26:40.437824 | Picholine Pimplenad, MMMMCMXCIX | $133,964.00 | 3
|
|
167
|
+
# 5000 | 2012-03-26 11:26:40.441958 | 2012-03-26 11:26:40.441958 | Picholine Pimplenad, _V | $76,519.00 | 4
|
|
168
|
+
#
|
|
169
|
+
# Partition employees_partitions.p1 - partition where company_id = 1:
|
|
170
|
+
#
|
|
171
|
+
# id | created_at | updated_at | name | salary | company_id
|
|
172
|
+
#------+----------------------------+----------------------------+-------------------------------------+-------------+------------
|
|
173
|
+
# 3 | 2012-03-26 11:26:30.704959 | 2012-03-26 11:26:43.250032 | Winston J. Sillypants, III | $128,998.00 | 1
|
|
174
|
+
# 5 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, V | $134,319.00 | 1
|
|
175
|
+
# 8 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, VIII | $82,995.00 | 1
|
|
176
|
+
# ...
|
|
177
|
+
# 4988 | 2012-03-26 11:26:40.392319 | 2012-03-26 11:26:44.077802 | Picholine Pimplenad, MMMMCMLXXXVIII | $132,535.00 | 1
|
|
178
|
+
# 4994 | 2012-03-26 11:26:40.416951 | 2012-03-26 11:26:40.416951 | Picholine Pimplenad, MMMMCMXCIV | $105,119.00 | 1
|
|
179
|
+
# 4996 | 2012-03-26 11:26:40.425268 | 2012-03-26 11:26:40.425268 | Picholine Pimplenad, MMMMCMXCVI | $81,403.00 | 1
|
|
180
|
+
#
|
|
181
|
+
# Partition employees_partitions.p2 - partition where company_id = 2:
|
|
182
|
+
#
|
|
183
|
+
# id | created_at | updated_at | name | salary | company_id
|
|
184
|
+
#------+----------------------------+----------------------------+-------------------------------------+-------------+------------
|
|
185
|
+
# 4 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, IV | $136,540.00 | 2
|
|
186
|
+
# 12 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, XII | $103,200.00 | 2
|
|
187
|
+
# 13 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, XIII | $139,077.00 | 2
|
|
188
|
+
# ...
|
|
189
|
+
# 4991 | 2012-03-26 11:26:40.40451 | 2012-03-26 11:26:42.057637 | Picholine Pimplenad, MMMMCMXCI | $122,115.00 | 2
|
|
190
|
+
# 4992 | 2012-03-26 11:26:40.408519 | 2012-03-26 11:26:40.408519 | Picholine Pimplenad, MMMMCMXCII | $90,176.00 | 2
|
|
191
|
+
# 4995 | 2012-03-26 11:26:40.421126 | 2012-03-26 12:26:49.969993 | Picholine Pimplenad, MMMMCMXCV | $86,410.00 | 2
|
|
192
|
+
#
|
|
193
|
+
#
|
|
194
|
+
# Partition employees_partitions.p3 - partition where company_id = 3:
|
|
195
|
+
#
|
|
196
|
+
# id | created_at | updated_at | name | salary | company_id
|
|
197
|
+
#------+----------------------------+----------------------------+-------------------------------------+-------------+------------
|
|
198
|
+
# 2 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, II | $103,767.00 | 3
|
|
199
|
+
# 6 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, VI | $67,280.00 | 3
|
|
200
|
+
# 9 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, IX | $75,396.00 | 3
|
|
201
|
+
# ...
|
|
202
|
+
# 4990 | 2012-03-26 11:26:40.400746 | 2012-03-26 11:26:43.604349 | Picholine Pimplenad, MMMMCMXC | $95,882.00 | 3
|
|
203
|
+
# 4998 | 2012-03-26 11:26:40.43347 | 2012-03-26 11:26:44.570338 | Picholine Pimplenad, MMMMCMXCVIII | $93,628.00 | 3
|
|
204
|
+
# 4999 | 2012-03-26 11:26:40.437824 | 2012-03-26 11:26:40.437824 | Picholine Pimplenad, MMMMCMXCIX | $133,964.00 | 3
|
|
205
|
+
#
|
|
206
|
+
#
|
|
207
|
+
# Partition employees_partitions.p4 - partition where company_id = 4:
|
|
208
|
+
#
|
|
209
|
+
# id | created_at | updated_at | name | salary | company_id
|
|
210
|
+
#------+----------------------------+----------------------------+-------------------------------------+-------------+------------
|
|
211
|
+
# 1 | 2012-03-26 11:26:30.704959 | 2012-03-26 11:26:45.519874 | Winston J. Sillypants, I | $106,363.00 | 4
|
|
212
|
+
# 7 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, VII | $111,585.00 | 4
|
|
213
|
+
# 17 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, XVII | $135,812.00 | 4
|
|
214
|
+
# ...
|
|
215
|
+
# 4993 | 2012-03-26 11:26:40.412815 | 2012-03-26 11:26:40.412815 | Picholine Pimplenad, MMMMCMXCIII | $95,851.00 | 4
|
|
216
|
+
# 4997 | 2012-03-26 11:26:40.429356 | 2012-03-26 11:26:40.429356 | Picholine Pimplenad, MMMMCMXCVII | $84,564.00 | 4
|
|
217
|
+
# 5000 | 2012-03-26 11:26:40.441958 | 2012-03-26 11:26:40.441958 | Picholine Pimplenad, _V | $76,519.00 | 4
|
|
218
|
+
#
|
|
219
|
+
|
|
220
|
+
require File.expand_path(File.dirname(__FILE__) + "/lib/command_line_tool_mixin")
|
|
221
|
+
require File.expand_path(File.dirname(__FILE__) + "/lib/get_options")
|
|
222
|
+
|
|
223
|
+
include CommandLineToolMixin
|
|
224
|
+
|
|
225
|
+
$cleanup = false
|
|
226
|
+
$force = false
|
|
227
|
+
$create_many = 3000
|
|
228
|
+
$create_individual = 1000
|
|
229
|
+
$new_individual = 1000
|
|
230
|
+
$update_many = 1000
|
|
231
|
+
$update_individual = 1000
|
|
232
|
+
|
|
233
|
+
@options = {
|
|
234
|
+
"--cleanup" => {
|
|
235
|
+
:short => "-C",
|
|
236
|
+
:argument => GetoptLong::NO_ARGUMENT,
|
|
237
|
+
:note => "cleanup data in database and exit"
|
|
238
|
+
},
|
|
239
|
+
"--force" => {
|
|
240
|
+
:short => "-F",
|
|
241
|
+
:argument => GetoptLong::NO_ARGUMENT,
|
|
242
|
+
:note => "cleanup data in database before creating new data"
|
|
243
|
+
},
|
|
244
|
+
"--create-many" => {
|
|
245
|
+
:short => "-m",
|
|
246
|
+
:argument => GetoptLong::REQUIRED_ARGUMENT,
|
|
247
|
+
:note => "how many objects to create via create_many",
|
|
248
|
+
:argument_note => "NUMBER"
|
|
249
|
+
},
|
|
250
|
+
"--create-individual" => {
|
|
251
|
+
:short => "-i",
|
|
252
|
+
:argument => GetoptLong::REQUIRED_ARGUMENT,
|
|
253
|
+
:note => "how many objects to create via create",
|
|
254
|
+
:argument_note => "NUMBER"
|
|
255
|
+
},
|
|
256
|
+
"--new-individual" => {
|
|
257
|
+
:short => "-I",
|
|
258
|
+
:argument => GetoptLong::REQUIRED_ARGUMENT,
|
|
259
|
+
:note => "how many objects to create via new/save",
|
|
260
|
+
:argument_note => "NUMBER"
|
|
261
|
+
},
|
|
262
|
+
"--update-individual" => {
|
|
263
|
+
:short => "-u",
|
|
264
|
+
:argument => GetoptLong::REQUIRED_ARGUMENT,
|
|
265
|
+
:note => "how many objects to update individually",
|
|
266
|
+
:argument_note => "NUMBER"
|
|
267
|
+
},
|
|
268
|
+
"--update-many" => {
|
|
269
|
+
:short => "-U",
|
|
270
|
+
:argument => GetoptLong::REQUIRED_ARGUMENT,
|
|
271
|
+
:note => "how many objects to update via update_many",
|
|
272
|
+
:argument_note => "NUMBER"
|
|
273
|
+
},
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
command_line_options(@options) do |option,argument|
|
|
277
|
+
if option == '--cleanup'
|
|
278
|
+
$cleanup = true
|
|
279
|
+
elsif option == '--force'
|
|
280
|
+
$force = true
|
|
281
|
+
elsif option == '--create-many'
|
|
282
|
+
$create_many = argument.to_i
|
|
283
|
+
elsif option == '--create-individual'
|
|
284
|
+
$create_individual = argument.to_i
|
|
285
|
+
elsif option == '--new-individual'
|
|
286
|
+
$new_individual = argument.to_i
|
|
287
|
+
elsif option == '--update-individual'
|
|
288
|
+
$update_individual = argument.to_i
|
|
289
|
+
elsif option == '--update-many'
|
|
290
|
+
$update_many = argument.to_i
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
if $cleanup || $force
|
|
295
|
+
ActiveRecord::Base.connection.drop_schema("employees_partitions", :cascade => true) rescue nil
|
|
296
|
+
ActiveRecord::Base.connection.drop_table("employees") rescue nil
|
|
297
|
+
ActiveRecord::Base.connection.drop_table("companies") rescue nil
|
|
298
|
+
exit(0) if $cleanup
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
$total_records = $create_many + $create_individual + $new_individual
|
|
302
|
+
|
|
303
|
+
puts "total records: #{$total_records}"
|
|
304
|
+
|
|
305
|
+
# the ActiveRecord classes
|
|
306
|
+
|
|
307
|
+
require File.expand_path(File.dirname(__FILE__) + "/lib/company")
|
|
308
|
+
require File.expand_path(File.dirname(__FILE__) + "/lib/by_company_id")
|
|
309
|
+
|
|
310
|
+
class Employee < ByCompanyId
|
|
311
|
+
belongs_to :company, :class_name => 'Company'
|
|
312
|
+
attr_accessible :salary, :company_id, :name
|
|
313
|
+
|
|
314
|
+
connection.execute <<-SQL
|
|
315
|
+
create table employees
|
|
316
|
+
(
|
|
317
|
+
id serial not null primary key,
|
|
318
|
+
created_at timestamp not null default now(),
|
|
319
|
+
updated_at timestamp,
|
|
320
|
+
name text not null,
|
|
321
|
+
salary money not null,
|
|
322
|
+
company_id integer not null
|
|
323
|
+
);
|
|
324
|
+
SQL
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# You should have the following tables:
|
|
328
|
+
# public.companies
|
|
329
|
+
# public.employees
|
|
330
|
+
|
|
331
|
+
# create the infrastructure for EMPLOYEES table which includes the schema and partition tables
|
|
332
|
+
|
|
333
|
+
Employee.create_infrastructure
|
|
334
|
+
|
|
335
|
+
# You should have the following schema:
|
|
336
|
+
# employees_partitions
|
|
337
|
+
|
|
338
|
+
# add some companies
|
|
339
|
+
|
|
340
|
+
Company.create_many(COMPANIES)
|
|
341
|
+
company_ids = Company.all.map(&:id)
|
|
342
|
+
|
|
343
|
+
# create the employees partitions dependant on the all companies
|
|
344
|
+
|
|
345
|
+
Employee.create_new_partition_tables(company_ids)
|
|
346
|
+
|
|
347
|
+
# You should have the following tables:
|
|
348
|
+
# employees_partitions.p1
|
|
349
|
+
# employees_partitions.p2
|
|
350
|
+
# employees_partitions.p3
|
|
351
|
+
# employees_partitions.p4
|
|
352
|
+
|
|
353
|
+
employees = []
|
|
354
|
+
|
|
355
|
+
require File.expand_path(File.dirname(__FILE__) + "/lib/roman")
|
|
356
|
+
|
|
357
|
+
# generates data for employees_partitions and employees tables
|
|
358
|
+
|
|
359
|
+
base = 0
|
|
360
|
+
(1..$create_many).each do |i|
|
|
361
|
+
employees << {
|
|
362
|
+
:name => "Winston J. Sillypants, #{to_roman(base+i)}",
|
|
363
|
+
:salary => rand(80000) + 60000,
|
|
364
|
+
:company_id => company_ids[rand company_ids.length]
|
|
365
|
+
}
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
puts "creating many #{$create_many}"
|
|
369
|
+
Employee.create_many(employees)
|
|
370
|
+
base += $create_many
|
|
371
|
+
|
|
372
|
+
puts "creating individual #{$create_individual}"
|
|
373
|
+
(1..$create_individual).each do |i|
|
|
374
|
+
employee_data = {
|
|
375
|
+
:name => "Jonathan Crabapple, #{to_roman(base+i)}",
|
|
376
|
+
:salary => rand(80000) + 60000,
|
|
377
|
+
:company_id => company_ids[rand company_ids.length]
|
|
378
|
+
}
|
|
379
|
+
employees << Employee.create(employee_data)
|
|
380
|
+
end
|
|
381
|
+
base += $create_individual
|
|
382
|
+
|
|
383
|
+
puts "new individual #{$new_individual}"
|
|
384
|
+
(1..$new_individual).each do |i|
|
|
385
|
+
employee_data = {
|
|
386
|
+
:name => "Picholine Pimplenad, #{to_roman(base+i)}",
|
|
387
|
+
:salary => rand(80000) + 60000,
|
|
388
|
+
:company_id => company_ids[rand company_ids.length]
|
|
389
|
+
}
|
|
390
|
+
employee = Employee.new(employee_data)
|
|
391
|
+
employee.save!
|
|
392
|
+
employees << employee
|
|
393
|
+
end
|
|
394
|
+
base += $new_individual
|
|
395
|
+
|
|
396
|
+
updates = {}
|
|
397
|
+
puts "update many #{$update_many}"
|
|
398
|
+
(1..$update_many).each do |i|
|
|
399
|
+
employee_record = employees[rand(employees.length)]
|
|
400
|
+
updates[{
|
|
401
|
+
:id => employee_record[:id],
|
|
402
|
+
:company_id => employee_record[:company_id]
|
|
403
|
+
}] = {
|
|
404
|
+
:salary => 100
|
|
405
|
+
}
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
Employee.update_many(updates, {:set_array => '"salary = #{table_name}.salary + datatable.salary, updated_at = now()"'})
|
|
409
|
+
|
|
410
|
+
puts "update individual #{$update_individual}"
|
|
411
|
+
(1..$update_individual).each do |i|
|
|
412
|
+
employee_record = employees[rand(employees.length)]
|
|
413
|
+
employee = Employee.from_partition(employee_record[:company_id]).find(employee_record[:id])
|
|
414
|
+
employee.salary += 1000
|
|
415
|
+
employee.save
|
|
416
|
+
end
|
|
417
|
+
|