pgslice 0.4.2 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08f3d08e8d7f2f60615587f8c842b8a80e59f10d4f00d299422ca44caef031d7'
4
- data.tar.gz: 889bcd29c7b381ffdcdc0a32150a512243950dc106dec9d34d791f50794a3bb1
3
+ metadata.gz: 73d406b68757fa95efcc58a98249f9a8394cab3408a9ae14ef642983720f44b3
4
+ data.tar.gz: 7952c9aaa1734c76260b76a59822a4065e6184ac01bf3b1916bd217f7b368403
5
5
  SHA512:
6
- metadata.gz: 91319129faa191528b4808ade4138310969cd95c256b7beaba307947f5b962027cde2965a90122bceb84bcc5c4eafcca65d3aa27638b6cce4383963f5e5c1d10
7
- data.tar.gz: 9b270632d217dc19e74d479bf15ef9378aae34b813c56904fa8d7ccd10f8cdfc8d8db1a049826b1bb0a03539929de551510a1520a1df9c6ccb4cfbf6fb71cb56
6
+ metadata.gz: 057aeaddcf952f2bb99f657f290e03f2ec3bac2deffce0d7701a7549418d7d8211b2454cbc71039226b369fc5b355d7ad426df0c4ce032d660e8ce09ebe15eab
7
+ data.tar.gz: a36f9db976f72cc656e289ff5af6ebb89657eb739fb6ca1bc4ccba652fdfa8b93894bc2e3fde5a9fdcd63d53a24574347a280af60157d124445a565810b9839c
@@ -1,106 +1,132 @@
1
- ## 0.4.2
1
+ ## 0.4.7 (2020-08-14)
2
+
3
+ - Added `--tablespace` option to `add_partitions`
4
+ - Fixed sequence query if sequence in different schema than table
5
+
6
+ ## 0.4.6 (2020-05-29)
7
+
8
+ - Ensure correct order with multi-column primary keys
9
+ - Ensure fill always uses correct date range (bug introduced in 0.4.5)
10
+
11
+ ## 0.4.5 (2018-10-18)
12
+
13
+ - Added support for Postgres 11 foreign key improvements
14
+ - Improved versioning
15
+
16
+ ## 0.4.4 (2018-08-18)
17
+
18
+ - Added partitioning by `year`
19
+ - Fixed `--source-table` and `--dest-table` options
20
+ - Added descriptions to options
21
+
22
+ ## 0.4.3 (2018-08-16)
23
+
24
+ - Fixed sequence ownership
25
+ - Improved help
26
+
27
+ ## 0.4.2 (2018-07-23)
2
28
 
3
29
  - Added support for Postgres 11 index improvements
4
30
  - Added support for all connection options
5
31
 
6
- ## 0.4.1
32
+ ## 0.4.1 (2018-04-30)
7
33
 
8
34
  - Better support for schemas
9
35
  - Use latest partition for schema
10
36
  - Added support for composite primary keys
11
37
 
12
- ## 0.4.0
38
+ ## 0.4.0 (2017-10-07)
13
39
 
14
40
  - Added support for declarative partitioning
15
41
  - Added support for foreign keys
16
42
 
17
- ## 0.3.6
43
+ ## 0.3.6 (2017-07-10)
18
44
 
19
45
  - Fixed drop trigger on `unprep` for non-lowercase tables
20
46
  - Fixed index creation for non-lowercase tables
21
47
 
22
- ## 0.3.5
48
+ ## 0.3.5 (2017-07-06)
23
49
 
24
50
  - Added support for non-lowercase tables and columns
25
51
 
26
- ## 0.3.4
52
+ ## 0.3.4 (2017-07-06)
27
53
 
28
54
  - Added `analyze` method
29
55
  - Fixed `fill` with `--dry-run` option
30
56
  - Better error message for tables without primary key
31
57
 
32
- ## 0.3.3
58
+ ## 0.3.3 (2017-03-22)
33
59
 
34
60
  - Fixed error when creating partitions
35
61
 
36
- ## 0.3.2
62
+ ## 0.3.2 (2016-12-15)
37
63
 
38
64
  - Exit with error code on interrupt
39
65
  - Fixed `--start` option with `--swapped`
40
66
 
41
- ## 0.3.1
67
+ ## 0.3.1 (2016-12-13)
42
68
 
43
69
  - Fixed exception with `--no-partition` option
44
70
  - Use proper cast type in `fill` method for legacy `timestamptz` columns
45
71
 
46
- ## 0.3.0
72
+ ## 0.3.0 (2016-12-12)
47
73
 
48
74
  - Better query performance for `timestamptz` columns
49
75
  - Added support for schemas other than `public`
50
76
 
51
- ## 0.2.3
77
+ ## 0.2.3 (2016-10-10)
52
78
 
53
79
  - Added `--dest-table` option to `fill`
54
80
  - Fixed errors with `fill` when no partitions created
55
81
 
56
- ## 0.2.2
82
+ ## 0.2.2 (2016-10-06)
57
83
 
58
84
  - Set `lock_timeout` on `swap` to prevent bad things from happening
59
85
  - Friendlier error messages
60
86
 
61
- ## 0.2.1
87
+ ## 0.2.1 (2016-09-28)
62
88
 
63
89
  - Added `--where` option to `fill`
64
90
  - Fixed partition detection with `fill`
65
91
  - Fixed error for columns named `user` with `fill`
66
92
 
67
- ## 0.2.0
93
+ ## 0.2.0 (2016-09-22)
68
94
 
69
95
  - Switched to new trigger, which is about 20% faster
70
96
 
71
- ## 0.1.7
97
+ ## 0.1.7 (2016-09-14)
72
98
 
73
99
  - Added `--source-table` option to `fill`
74
100
 
75
- ## 0.1.6
101
+ ## 0.1.6 (2016-08-04)
76
102
 
77
103
  - Added `--no-partition` option to `prep`
78
104
  - Added `--url` option
79
105
 
80
- ## 0.1.5
106
+ ## 0.1.5 (2016-04-26)
81
107
 
82
108
  - Removed `activesupport` dependency for speed
83
109
  - Fixed `fill` for months
84
110
 
85
- ## 0.1.4
111
+ ## 0.1.4 (2016-04-24)
86
112
 
87
113
  - Added sequence ownership
88
114
  - Default to 0 for `--past` and `--future` options
89
115
  - Better `fill` with `--swapped`
90
116
 
91
- ## 0.1.3
117
+ ## 0.1.3 (2016-04-24)
92
118
 
93
119
  - Fixed table inheritance
94
120
 
95
- ## 0.1.2
121
+ ## 0.1.2 (2016-04-24)
96
122
 
97
123
  - Added `--dry-run` option
98
124
  - Print sql to stdout instead of stderr
99
125
 
100
- ## 0.1.1
126
+ ## 0.1.1 (2016-04-24)
101
127
 
102
128
  - Added sql commands to output
103
129
 
104
- ## 0.1.0
130
+ ## 0.1.0 (2016-04-24)
105
131
 
106
132
  - First release
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2016-2018 Andrew Kane
3
+ Copyright (c) 2016-2020 Andrew Kane
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # pgslice
2
2
 
3
- Postgres partitioning as easy as pie. Works great for both new and existing tables, with zero downtime and minimal app changes. Archive older data on a rolling basis to keep your database size under control.
3
+ Postgres partitioning as easy as pie. Works great for both new and existing tables, with zero downtime and minimal app changes. No need to install anything on your database server. Archive older data on a rolling basis to keep your database size under control.
4
4
 
5
5
  :tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
6
6
 
@@ -14,7 +14,7 @@ pgslice is a command line tool. To install, run:
14
14
  gem install pgslice
15
15
  ```
16
16
 
17
- This will give you the `pgslice` command.
17
+ This will give you the `pgslice` command. If installation fails, you may need to install [dependencies](#dependencies).
18
18
 
19
19
  ## Steps
20
20
 
@@ -32,18 +32,16 @@ This will give you the `pgslice` command.
32
32
  pgslice prep <table> <column> <period>
33
33
  ```
34
34
 
35
- Period can be `day` or `month`.
35
+ Period can be `day`, `month`, or `year`.
36
36
 
37
- This creates a table named `<table>_intermediate` with the appropriate trigger for partitioning.
37
+ This creates a partitioned table named `<table>_intermediate`.
38
38
 
39
- 4. Add partitions
39
+ 4. Add partitions to the intermediate table
40
40
 
41
41
  ```sh
42
42
  pgslice add_partitions <table> --intermediate --past 3 --future 3
43
43
  ```
44
44
 
45
- This creates child tables that inherit from the intermediate table.
46
-
47
45
  Use the `--past` and `--future` options to control the number of partitions.
48
46
 
49
47
  5. *Optional, for tables with data* - Fill the partitions in batches with data from the original table
@@ -80,7 +78,7 @@ This will give you the `pgslice` command.
80
78
 
81
79
  ```sql
82
80
  pg_dump -c -Fc -t <table>_retired $PGSLICE_URL > <table>_retired.dump
83
- psql -c "DROP <table>_retired" $PGSLICE_URL
81
+ psql -c "DROP TABLE <table>_retired" $PGSLICE_URL
84
82
  ```
85
83
 
86
84
  ## Sample Output
@@ -92,34 +90,13 @@ pgslice prep visits created_at month
92
90
  ```
93
91
 
94
92
  ```sql
95
- -- Postgres 10
96
-
97
93
  BEGIN;
98
94
 
99
- CREATE TABLE visits_intermediate (LIKE visits INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING STORAGE INCLUDING COMMENTS) PARTITION BY RANGE (created_at);
100
-
101
- COMMENT ON TABLE visits_intermediate is 'column:created_at,period:day';
102
-
103
- COMMIT;
104
-
105
- -- Postgres 9.6 and below
106
-
107
- BEGIN;
95
+ CREATE TABLE "public"."visits_intermediate" (LIKE "public"."visits" INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING STORAGE INCLUDING COMMENTS) PARTITION BY RANGE ("created_at");
108
96
 
109
- CREATE TABLE visits_intermediate (LIKE visits INCLUDING ALL);
97
+ CREATE INDEX ON "public"."visits_intermediate" USING btree ("created_at");
110
98
 
111
- CREATE FUNCTION visits_insert_trigger()
112
- RETURNS trigger AS $$
113
- BEGIN
114
- RAISE EXCEPTION 'Create partitions first.';
115
- END;
116
- $$ LANGUAGE plpgsql;
117
-
118
- CREATE TRIGGER visits_insert_trigger
119
- BEFORE INSERT ON visits_intermediate
120
- FOR EACH ROW EXECUTE PROCEDURE visits_insert_trigger();
121
-
122
- COMMENT ON TRIGGER visits_insert_trigger ON visits_intermediate is 'column:created_at,period:month';
99
+ COMMENT ON TABLE "public"."visits_intermediate" is 'column:createdAt,period:day,cast:date,version:3';
123
100
 
124
101
  COMMIT;
125
102
  ```
@@ -129,73 +106,19 @@ pgslice add_partitions visits --intermediate --past 1 --future 1
129
106
  ```
130
107
 
131
108
  ```sql
132
- -- Postgres 10
133
-
134
109
  BEGIN;
135
110
 
136
- CREATE TABLE visits_201608 PARTITION OF visits_intermediate FOR VALUES FROM ('2016-08-01') TO ('2016-09-01');
137
-
138
- ALTER TABLE visits_201608 ADD PRIMARY KEY (id);
111
+ CREATE TABLE "public"."visits_201808" PARTITION OF "public"."visits_intermediate" FOR VALUES FROM ('2018-08-01') TO ('2018-09-01');
139
112
 
140
- CREATE INDEX ON visits_201608 USING btree (user_id);
113
+ ALTER TABLE "public"."visits_201808" ADD PRIMARY KEY ("id");
141
114
 
142
- CREATE TABLE visits_201609 PARTITION OF visits_intermediate FOR VALUES FROM ('2016-09-01') TO ('2016-10-01');
115
+ CREATE TABLE "public"."visits_201809" PARTITION OF "public"."visits_intermediate" FOR VALUES FROM ('2018-09-01') TO ('2018-10-01');
143
116
 
144
- ALTER TABLE visits_201609 ADD PRIMARY KEY (id);
117
+ ALTER TABLE "public"."visits_201809" ADD PRIMARY KEY ("id");
145
118
 
146
- CREATE INDEX ON visits_201609 USING btree (user_id);
119
+ CREATE TABLE "public"."visits_201810" PARTITION OF "public"."visits_intermediate" FOR VALUES FROM ('2018-10-01') TO ('2018-11-01');
147
120
 
148
- CREATE TABLE visits_201610 PARTITION OF visits_intermediate FOR VALUES FROM ('2016-10-01') TO ('2016-11-01');
149
-
150
- ALTER TABLE visits_201610 ADD PRIMARY KEY (id);
151
-
152
- CREATE INDEX ON visits_201610 USING btree (user_id);
153
-
154
- COMMIT;
155
-
156
- -- Postgres 9.6 and below
157
-
158
- BEGIN;
159
-
160
- CREATE TABLE visits_201608
161
- (CHECK (created_at >= '2016-08-01'::date AND created_at < '2016-09-01'::date))
162
- INHERITS (visits_intermediate);
163
-
164
- ALTER TABLE visits_201608 ADD PRIMARY KEY (id);
165
-
166
- CREATE INDEX ON visits_201608 USING btree (user_id);
167
-
168
- CREATE TABLE visits_201609
169
- (CHECK (created_at >= '2016-09-01'::date AND created_at < '2016-10-01'::date))
170
- INHERITS (visits_intermediate);
171
-
172
- ALTER TABLE visits_201609 ADD PRIMARY KEY (id);
173
-
174
- CREATE INDEX ON visits_201609 USING btree (user_id);
175
-
176
- CREATE TABLE visits_201610
177
- (CHECK (created_at >= '2016-10-01'::date AND created_at < '2016-11-01'::date))
178
- INHERITS (visits_intermediate);
179
-
180
- ALTER TABLE visits_201610 ADD PRIMARY KEY (id);
181
-
182
- CREATE INDEX ON visits_201610 USING btree (user_id);
183
-
184
- CREATE OR REPLACE FUNCTION visits_insert_trigger()
185
- RETURNS trigger AS $$
186
- BEGIN
187
- IF (NEW.created_at >= '2016-09-01'::date AND NEW.created_at < '2016-10-01'::date) THEN
188
- INSERT INTO visits_201609 VALUES (NEW.*);
189
- ELSIF (NEW.created_at >= '2016-10-01'::date AND NEW.created_at < '2016-11-01'::date) THEN
190
- INSERT INTO visits_201610 VALUES (NEW.*);
191
- ELSIF (NEW.created_at >= '2016-08-01'::date AND NEW.created_at < '2016-09-01'::date) THEN
192
- INSERT INTO visits_201608 VALUES (NEW.*);
193
- ELSE
194
- RAISE EXCEPTION 'Date out of range. Ensure partitions are created.';
195
- END IF;
196
- RETURN NULL;
197
- END;
198
- $$ LANGUAGE plpgsql;
121
+ ALTER TABLE "public"."visits_201808" ADD PRIMARY KEY ("id");
199
122
 
200
123
  COMMIT;
201
124
  ```
@@ -206,19 +129,19 @@ pgslice fill visits
206
129
 
207
130
  ```sql
208
131
  /* 1 of 3 */
209
- INSERT INTO visits_intermediate ("id", "user_id", "ip", "created_at")
210
- SELECT "id", "user_id", "ip", "created_at" FROM visits
211
- WHERE id > 0 AND id <= 10000 AND created_at >= '2016-08-01'::date AND created_at < '2016-11-01'::date
132
+ INSERT INTO "public"."visits_intermediate" ("id", "user_id", "ip", "created_at")
133
+ SELECT "id", "user_id", "ip", "created_at" FROM "public"."visits"
134
+ WHERE "id" > 0 AND "id" <= 10000 AND "created_at" >= '2018-08-01'::date AND "created_at" < '2018-11-01'::date
212
135
 
213
136
  /* 2 of 3 */
214
- INSERT INTO visits_intermediate ("id", "user_id", "ip", "created_at")
215
- SELECT "id", "user_id", "ip", "created_at" FROM visits
216
- WHERE id > 10000 AND id <= 20000 AND created_at >= '2016-08-01'::date AND created_at < '2016-11-01'::date
137
+ INSERT INTO "public"."visits_intermediate" ("id", "user_id", "ip", "created_at")
138
+ SELECT "id", "user_id", "ip", "created_at" FROM "public"."visits"
139
+ WHERE "id" > 10000 AND "id" <= 20000 AND "created_at" >= '2018-08-01'::date AND "created_at" < '2018-11-01'::date
217
140
 
218
141
  /* 3 of 3 */
219
- INSERT INTO visits_intermediate ("id", "user_id", "ip", "created_at")
220
- SELECT "id", "user_id", "ip", "created_at" FROM visits
221
- WHERE id > 20000 AND id <= 30000 AND created_at >= '2016-08-01'::date AND created_at < '2016-11-01'::date
142
+ INSERT INTO "public"."visits_intermediate" ("id", "user_id", "ip", "created_at")
143
+ SELECT "id", "user_id", "ip", "created_at" FROM "public"."visits"
144
+ WHERE "id" > 20000 AND "id" <= 30000 AND "created_at" >= '2018-08-01'::date AND "created_at" < '2018-11-01'::date
222
145
  ```
223
146
 
224
147
  ```sh
@@ -226,13 +149,13 @@ pgslice analyze visits
226
149
  ```
227
150
 
228
151
  ```sql
229
- ANALYZE VERBOSE visits_201608;
152
+ ANALYZE VERBOSE "public"."visits_201808";
230
153
 
231
- ANALYZE VERBOSE visits_201609;
154
+ ANALYZE VERBOSE "public"."visits_201809";
232
155
 
233
- ANALYZE VERBOSE visits_201610;
156
+ ANALYZE VERBOSE "public"."visits_201810";
234
157
 
235
- ANALYZE VERBOSE visits_intermediate;
158
+ ANALYZE VERBOSE "public"."visits_intermediate";
236
159
  ```
237
160
 
238
161
  ```sh
@@ -244,11 +167,11 @@ BEGIN;
244
167
 
245
168
  SET LOCAL lock_timeout = '5s';
246
169
 
247
- ALTER TABLE visits RENAME TO visits_retired;
170
+ ALTER TABLE "public"."visits" RENAME TO "visits_retired";
248
171
 
249
- ALTER TABLE visits_intermediate RENAME TO visits;
172
+ ALTER TABLE "public"."visits_intermediate" RENAME TO "visits";
250
173
 
251
- ALTER SEQUENCE visits_id_seq OWNED BY visits.id;
174
+ ALTER SEQUENCE "public"."visits_id_seq" OWNED BY "public"."visits"."id";
252
175
 
253
176
  COMMIT;
254
177
  ```
@@ -261,7 +184,7 @@ To add partitions, use:
261
184
  pgslice add_partitions <table> --future 3
262
185
  ```
263
186
 
264
- Add this as a cron job to create a new partition each day or month.
187
+ Add this as a cron job to create a new partition each day, month, or year.
265
188
 
266
189
  ```sh
267
190
  # day
@@ -269,6 +192,9 @@ Add this as a cron job to create a new partition each day or month.
269
192
 
270
193
  # month
271
194
  0 0 1 * * pgslice add_partitions <table> --future 3 --url ...
195
+
196
+ # year
197
+ 0 0 1 1 * pgslice add_partitions <table> --future 3 --url ...
272
198
  ```
273
199
 
274
200
  Add a monitor to ensure partitions are being created.
@@ -283,21 +209,22 @@ WHERE
283
209
  n.nspname = 'public' AND
284
210
  c.relname = '<table>_' || to_char(NOW() + INTERVAL '3 days', 'YYYYMMDD')
285
211
  -- for months, use to_char(NOW() + INTERVAL '3 months', 'YYYYMM')
212
+ -- for years, use to_char(NOW() + INTERVAL '3 years', 'YYYY')
286
213
  ```
287
214
 
288
215
  ## Archiving Partitions
289
216
 
290
- Back up and drop older partitions each day or month.
217
+ Back up and drop older partitions each day, month, or year.
291
218
 
292
219
  ```sh
293
- pg_dump -c -Fc -t <table>_201609 $PGSLICE_URL > <table>_201609.dump
294
- psql -c "DROP <table>_201609" $PGSLICE_URL
220
+ pg_dump -c -Fc -t <table>_201809 $PGSLICE_URL > <table>_201809.dump
221
+ psql -c "DROP TABLE <table>_201809" $PGSLICE_URL
295
222
  ```
296
223
 
297
224
  If you use [Amazon S3](https://aws.amazon.com/s3/) for backups, [s3cmd](https://github.com/s3tools/s3cmd) is a nice tool.
298
225
 
299
226
  ```sh
300
- s3cmd put <table>_201609.dump s3://<s3-bucket>/<table>_201609.dump
227
+ s3cmd put <table>_201809.dump s3://<s3-bucket>/<table>_201809.dump
301
228
  ```
302
229
 
303
230
  ## Additional Commands
@@ -318,16 +245,9 @@ pgslice unswap <table>
318
245
 
319
246
  This set up allows you to read and write with the original table name with no knowledge it’s partitioned. However, there are a few things to be aware of.
320
247
 
321
- ### Writes
322
-
323
- Before Postgres 10, if you use `INSERT` statements with a `RETURNING` clause (as frameworks like Rails do), you’ll no longer receive the id of the newly inserted record(s) back. If you need this, you can either:
324
-
325
- 1. Insert directly into the partition
326
- 2. Get value before the insert with `SELECT nextval('sequence_name')` (for multiple rows, append `FROM generate_series(1, n)`)
327
-
328
248
  ### Reads
329
249
 
330
- When possible, queries should include the column you partition on to limit the number of partitions the database needs to check. For instance, if you partition on `created_at`, try to include it in queries:
250
+ When possible, queries should include the column you partition on to limit the number of partitions the database needs to check. For instance, if you partition on `created_at`, try to include it in queries:
331
251
 
332
252
  ```sql
333
253
  SELECT * FROM
@@ -335,7 +255,7 @@ SELECT * FROM
335
255
  WHERE
336
256
  user_id = 123 AND
337
257
  -- for performance
338
- created_at >= '2016-09-01' AND created_at < '2016-09-02'
258
+ created_at >= '2018-09-01' AND created_at < '2018-09-02'
339
259
  ```
340
260
 
341
261
  For this to be effective, ensure `constraint_exclusion` is set to `partition` (default value) or `on`.
@@ -344,6 +264,33 @@ For this to be effective, ensure `constraint_exclusion` is set to `partition` (d
344
264
  SHOW constraint_exclusion;
345
265
  ```
346
266
 
267
+ ### Writes
268
+
269
+ Before Postgres 10, if you use `INSERT` statements with a `RETURNING` clause (as frameworks like Rails do), you’ll no longer receive the id of the newly inserted record(s) back. If you need this, you can either:
270
+
271
+ 1. Insert directly into the partition
272
+ 2. Get value before the insert with `SELECT nextval('sequence_name')` (for multiple rows, append `FROM generate_series(1, n)`)
273
+
274
+ ## Rails
275
+
276
+ For Postgres 10+, specify the primary key for partitioned models to ensure it’s returned.
277
+
278
+ ```ruby
279
+ class Visit < ApplicationRecord
280
+ self.primary_key = "id"
281
+ end
282
+ ```
283
+
284
+ Before Postgres 10, preload the value.
285
+
286
+ ```ruby
287
+ class Visit < ApplicationRecord
288
+ before_create do
289
+ self.id ||= self.class.connection.select_all("SELECT nextval('#{self.class.sequence_name}')").first["nextval"]
290
+ end
291
+ end
292
+ ```
293
+
347
294
  ## One Off Tasks
348
295
 
349
296
  You can also use pgslice to reduce the size of a table without partitioning by creating a new table, filling it with a subset of records, and swapping it in.
@@ -358,13 +305,38 @@ pgslice swap <table>
358
305
 
359
306
  Once a table is partitioned, here’s how to change the schema:
360
307
 
361
- - To add, remove, or modify a column, make the update on the master table only
362
- - To add or remove an index, make the update on the master table and all partitions (for Postgres 11, make the update on the master table only)
308
+ To add, remove, or modify a column, make the update on the master table only.
309
+
310
+ To add or remove an index or foreign key:
311
+
312
+ - For Postgres 11+, make the update on the master table only.
313
+ - For Postgres 10, make the update on partitions only.
314
+ - For Postgres < 10, make the update on the master table and all partitions.
363
315
 
364
316
  ## Declarative Partitioning
365
317
 
366
318
  Postgres 10 introduces [declarative partitioning](https://www.postgresql.org/docs/10/static/ddl-partitioning.html#ddl-partitioning-declarative). A major benefit is `INSERT` statements with a `RETURNING` clause work as expected. If you prefer to use trigger-based partitioning instead (not recommended), pass the `--trigger-based` option to the `prep` command.
367
319
 
320
+ ## Data Protection
321
+
322
+ Always make sure your [connection is secure](https://ankane.org/postgres-sslmode-explained) when connecting to a database over a network you don’t fully trust. Your best option is to connect over SSH or a VPN. Another option is to use `sslmode=verify-full`. If you don’t do this, your database credentials can be compromised.
323
+
324
+ ## Dependencies
325
+
326
+ If installation fails, your system may be missing Ruby or libpq.
327
+
328
+ On Mac, run:
329
+
330
+ ```sh
331
+ brew install postgresql
332
+ ```
333
+
334
+ On Ubuntu, run:
335
+
336
+ ```sh
337
+ sudo apt-get install ruby-dev libpq-dev build-essential
338
+ ```
339
+
368
340
  ## Upgrading
369
341
 
370
342
  Run:
@@ -398,6 +370,7 @@ This will give you the `pgslice` command.
398
370
 
399
371
  Also check out:
400
372
 
373
+ - [Dexter](https://github.com/ankane/dexter) - The automatic indexer for Postgres
401
374
  - [PgHero](https://github.com/ankane/pghero) - A performance dashboard for Postgres
402
375
  - [pgsync](https://github.com/ankane/pgsync) - Sync Postgres data to your local machine
403
376
 
@@ -410,14 +383,14 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
410
383
  - Write, clarify, or fix documentation
411
384
  - Suggest or add new features
412
385
 
413
- To run tests, do:
386
+ To get started with development:
414
387
 
415
388
  ```sh
416
389
  git clone https://github.com/ankane/pgslice.git
417
390
  cd pgslice
418
391
  bundle install
419
392
  createdb pgslice_test
420
- bundle exec rake
393
+ bundle exec rake test
421
394
  ```
422
395
 
423
396
  To test against different versions of Postgres with Docker, use: