huansong
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
> [color=#7ddb3b] This blog is one of a series of blogs to introduce partitioning in Greenplum 7: > * What's New: https://hackmd.io/FnJGS2d_RW-aNAm8K6mHeQ > * Recursion and Inheritance: https://hackmd.io/x6zxrkXkQ_2LILkI-UxM1w > * [WIP] Subpartition template: https://hackmd.io/IV9BKBcUSXibyVfwwReD0A # Partition in Greenplum 7: What's New Greenplum 7 is a huge milestone for partitioned tables. Besides several improvements and fixes, this is the first Greenplum version that will be aligned with partitioned tables from PostgreSQL world. A little background: before PostgreSQL 10, table partitioning could be done in very limited form in PostgreSQL, which is basically just [a use case of table inheritance](https://www.postgresql.org/docs/9.6/ddl-partitioning.html#:~:text=Implementing%20Partitioning). In PostgreSQL 10 and onwards, users can start use *declarative* syntax to define their partition paradigm. For example: ```sql! CREATE TABLE sales (id int, date date, amt decimal(10,2)) PARTITION BY RANGE (date); ``` On the other hand, table partitioning as we know it today has been in Greenplum for a long time. As part of the merge with PostgreSQL 12, Greenplum 7 has absorbed all the PostgreSQL syntax for table partitioning, while still supporting the Greenplum legacy syntax. As a result, Greenplum 7 has a chance to take the best of both worlds. This blog is going to talk about them, including the additions, removals and trade-offs in Greenplum 7, especially concerning what's different than prior versions of Greenplum. This blog will primarily focus on the differences between Greenplum 7 and legacy Greenplum. So if you are entirely new to Greenplum (or even PostgreSQL) and have never used partitioning in Greenplum 6 before, you might find [these articles](#reference) which only talk about PostgreSQL-style partitioning more interesting. So without further ado, let's dive right in. # 1. New Syntax Before we start to look at the new things in Greenplum 7, let's take a look at what's *not* new: PostgreSQL has the same declaration for partition key as Greenplum which is the `PARTITION BY` clause. So in Greenplum 7 that remains unchanged. Also, PostgreSQL has the same `RANGE` and `LIST` partitioning strategies which legacy Greenplum supports. Those continue to be there. However, one important difference is that now Greenplum 7 allows you to define a partitioned table **without** giving definition for any child partition, like below: ```sql! CREATE TABLE sales (id int, date date, amt decimal(10,2)) DISTRIBUTED BY (id) PARTITION BY RANGE (date); ``` The `CREATE TABLE ... PARTITION BY` command above creates just the parent partitioned table without any child partition. Child partitions in Greenplum 7 are first-class tables that can be created via separate commands, which will be covered in later sections. ## 1.1 `HASH` partitioning strategy Besides the existing `range` and `list` partitioning strategy, Greenplum 7 also supports `hash` partitioning. They work the same way as in PostgreSQL. Example to create a hash partitioned table and its child partitions: ```sql -- create a tabled partitioned by hash strategy CREATE TABLE sales_by_hour (id int, date date, hour int, amt decimal(10,2)) DISTRIBUTED BY (id) PARTITION BY HASH (hour); -- every hash partition modulus must be a factor of the next larger modulus CREATE TABLE sales_by_hour_1 PARTITION OF sales_by_hour FOR VALUES WITH (MODULUS 24, REMAINDER 0); CREATE TABLE sales_by_hour_2 PARTITION OF sales_by_hour FOR VALUES WITH (MODULUS 24, REMAINDER 1); CREATE TABLE sales_by_hour_3 PARTITION OF sales_by_hour FOR VALUES WITH (MODULUS 24, REMAINDER 2); ...... ``` <!-- (Huansong: removed below because: I guess it's not entirely correct to say that the benefit of hash partitioning is to evenly distribute: range and list can achieve the same as long as the partition key is uniformly distributed. The benefit of hash partitioning is that if the partitioning key is uniformly distributed tuples can be evenly placed among partitions, as demonstrated in below example: Insert 1000 rows and count number of rows in each partition: ```sql INSERT INTO sales_by_hour SELECT i, i FROM generate_series(1, 1000)i; SELECT 'hp1' AS partition, count(*) AS row_count FROM hpart_1 UNION ALL SELECT 'hp2', count(*) FROM hpart_2 UNION ALL SELECT 'hp3', count(*) from hpart_3; ``` Result: ``` partition | row_count -----------+----------- hp1 | 324 hp2 | 333 hp3 | 343 (3 rows) ``` --> ## 1.2 New Partition DDL So the main additions in Greenplum 7 are the following new partition DDLs, same as PostgreSQL. We will talk about them in details later, but let's take a peek at what they do: ### (1) `CREATE TABLE PARTITION OF` For creating a new table and adding it as a new child partition: ```sql CREATE TABLE jan_sales PARTITION OF sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01'); ``` ### (2) `ALTER TABLE ATTACH PARTITION` For adding an existing table as a new child partition: ```sql CREATE TABLE feb_sales (LIKE sales); ALTER TABLE sales ATTACH PARTITION feb_sales FOR VALUES FROM ('2024-02-01') TO ('2024-03-01'); ``` ### (3) `ALTER TABLE DETACH PARTITION` For removing a table from the partitioning hierarchy (without dropping the table itself): ```sql! ALTER TABLE sales DETACH PARTITION jan_sales; ``` ## 1.3 New Catalog and Helper Functions Partitioning information is now stored in the upstream [`pg_partitioned_table` catalog](https://www.postgresql.org/docs/12/catalog-pg-partitioned-table.html), and in additional fields in `pg_class` (`relispartition` and `relpartbound`). You can also use these new [helper functions from upstream](https://www.postgresql.org/docs/current/functions-admin.html#:~:text=Partitioning%20Information%20Functions): `pg_partition_ancestors(rel))`, `pg_partition_root(rel)` and `pg_partition_tree(rel)`. On that note, the old partitioning-related catalog tables, `pg_partition` and `pg_partition_rule` are gone, as well as the `pg_partition_def()` function. ```sql -- New catalog for partitioned tables select * from pg_partitioned_table where partrelid = 'sales'::regclass; partrelid | partstrat | partnatts | partdefid | partattrs | partclass | partcollation | partexprs -----------+-----------+-----------+-----------+-----------+-----------+---------------+----------- 156181 | r | 1 | 0 | 2 | 3122 | 0 | (1 row) -- A convenient helper routine to check the partition hierarchy select pg_partition_tree('sales'); pg_partition_tree ----------------------------------- (sales,,f,0) (jan_sales,sales,t,1) (sales_1_prt_feb_sales,sales,t,1) (sales_1_prt_mar_sales,sales,t,1) (4 rows) ``` # 2. New Workflows For an existing Greenplum user, one of the most important things to learn about the new syntaxes is that they provide alternative workflows to what the legacy Greenplum commands used to do. It does not necessarily mean that the new syntax is more complex. In fact, it is quite the other way around: the new syntaxes are more general and easy to use. In most cases, it is more straightforward to implement certain partition paradigms, including performing the exactly same tasks that the old commands can do. We will see a few examples below. However, worth mentioning that the new syntaxes are not replacement of the old. If one understands both legacy and new syntaxes well, especially the [differences](#3\.-other-differences) between them (we'll cover more in Section 3), they can always choose the most suitable commands for their need. ## Create child partition along with parent Greenplum has been able to create child partitions along with the parent table. For example: ```sql CREATE TABLE sales (id int, date date, amt decimal(10,2)) DISTRIBUTED BY (id) PARTITION BY RANGE (date) (PARTITION jan_sales START ('2023-01-01') END ('2023-02-01'), PARTITION feb_sales START ('2023-02-01') END ('2023-03-01'), DEFAULT PARTITION other_sales); ``` PostgreSQL does not have a counterpart command. Instead, it creates the parent partitioned table first and then add the child partitions separately: ```sql CREATE TABLE sales (id int, date date, amt decimal(10,2)) DISTRIBUTED BY (id) PARTITION BY RANGE (date); -- Add partition individually CREATE TABLE jan_sales PARTITION OF sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01'); CREATE TABLE feb_sales PARTITION OF sales FOR VALUES FROM ('2023-02-01') TO ('2023-03-01'); CREATE TABLE other_sales PARTITION OF sales DEFAULT; ``` ## Create and add child partitions The `ALTER TABLE ... ADD PARTITION` and `CREATE TABLE ... PARTITION OF` both create and add a new child table at the same time. However, since `CREATE TABLE PARTITION OF` is a `CREATE TABLE` command, unlike `ADD PARTITION` which is a `ALTER TABLE` subcommand, with `CREATE TABLE ... PARTITION OF` you can specify more tables creation options. `ADD PARTITION` in general only inherits whatever the parent table has. ```sql -- CREATE TABLE allows you to specify more options CREATE TABLE jan_sales PARTITION OF sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01') USING ao_row WITH(compresstype=zlib); -- ADD PARTITION does the creation but have to specify options in separate commands ALTER TABLE sales ADD PARTITION jan_sales START ('2023-01-01') END ('2023-02-01'); ALTER TABLE sales_1_prt_jan_sales SET ACCESS METHOD ao_row; ALTER TABLE sales_1_prt_jan_sales SET WITH (compresstype=zlib); ``` ## Swap existing partition with another table The `EXCHANGE PARTITION` command in legacy syntax swaps an existing child partition with a regular table. With new syntaxes one can simply use `DETACH PARTITION` and `ATTACH PARTITION` to achieve the same. In fact, internally in Greenplum 7, it is precisely doing `DETACH` and then `ATTACH PARTITION`, with some name swapping. ```sql -- 1. Using EXCHANGE PARTITION ALTER TABLE sales EXCHANGE jan_sales WITH TABLE jan_sales_new; -- 2. Using ATTACH PARTITION ALTER TABLE sales DETACH PARTITION jan_sales; ALTER TABLE sales ATTACH PARTITION jan_sales_new; ``` ## Remove a child partition It was used to be pretty difficult to remove a child partition without dropping the table. The legacy Greenplum only has the `ALTER TABLE ... DROP PARTITION` command which drops the table too. You would have to create a dummy table first, exchange the partition you would like to remove with the dummy table, and then drop the swapped partition. Now with the `ALTER TABLE ... DETACH PARTITION` one can easily perform the same task: ```sql -- Lengthy operations to remove an unwanted child partition w/o dropping it: CREATE TABLE dummy (LIKE sales); ALTER TABLE sales EXCHANGE PARTITION archived_sales WITH dummy; ALTER TABLE sales DROP PARTITION archived_sales; DROP TABLE dummy; -- Can just "DETACH PARTITION" now: ALTER TABLE sales DETACH PARTITION archived_sales; ``` As you may have noticed, `ALTER TABLE ... DROP PARTITION` essentially performs the exact same task as`DROP TABLE`. Then why `ALTER TABLE ... DROP PARTITION` is still there? That is because the two syntaxes treat the table name differently. See later section of "partition name vs table name". ## Split a child partition `SPLIT PARTITION` is a special command that performs an interesting task: dividing a leaf partition and creating two partitions out of it. It is another syntax without a simple alternative in the PostgreSQL. You have to manually detach the partition and add two partitions corresponding to the splited ranges. But the good news is that if you do not wish to perform the small steps, you can still just use `SPLIT PARTITION` in Greenplum 7. <details> <summary>Table of comparison: (Click) </summary> | Use Case | Legacy Syntax| Alternative New/Existing Syntax | | - | - | - | | Create child partition along with parent| `CREATE TABLE ... (PARTITION ...)` | `CREATE TABLE` + `ATTACH PARTITION` \| `CREATE TABLE ... PARTITION OF` | | Create & add partition| `ALTER TABLE ... ADD PARTITION` | `CREATE TABLE ... PARTITION OF` | | Swap existing partition child with regular table | `ALTER TABLE ... EXCHANGE PARTITION` | `ALTER TABLE ... DETACH PARTITION` +`ATTACH PARTITION` | | Remove partition | `ALTER TABLE ... DROP PARTITION` | `DROP TABLE` | | Split partition | `ALTER TABLE ... SPLIT PARTITION` | `DETACH` partition and `ATTACH` new ones separately | </details> <br> > [color=#7ddb3b] In general, the new syntaxes are less *specialized* but their *generality* would be able to implement more complex hierarchies more easily, once you get familiar with the usage. # 3. Other Differences ## 3.1 Partition name vs. Table name Historically, the name that one specifies in the Greenplum's partition DDLs is so-called "*partition* name" which is not the same as *table* name. Basically, Greenplum will add special prefix that is corrsponding to the parent partition to the child table name. For example, when using the legacy syntax to add partitions: ```sql CREATE TABLE sales (id int, date date, amt decimal(10,2)) DISTRIBUTED BY (id) PARTITION BY RANGE (date) (PARTITION jan_sales START ('2023-01-01') END ('2023-02-01')); ALTER TABLE sales ADD PARTITION feb_sales START ('2023-02-01') END ('2023-03-01'); \d+ sales Partitioned table "public.sales" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description --------+---------------+-----------+----------+---------+---------+--------------+------------- id | integer | | | | plain | | date | date | | | | plain | | amt | numeric(10,2) | | | | main | | Partition key: RANGE (date) Partitions: sales_1_prt_feb_sales FOR VALUES FROM ('2023-02-01') TO ('2023-03-01'), sales_1_prt_jan_sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01') Distributed by: (id) Access method: heap ``` As shown above, both child partitions have a prefix `sales_1_prt_` to the names we specifies for them (`jan_sales` and `feb_sales`). In contrast, the new syntax simply treat the names specified as the table name: ```sql CREATE TABLE sales (id int, date date, amt decimal(10,2)) DISTRIBUTED BY (id) PARTITION BY RANGE (date); CREATE TABLE jan_sales PARTITION OF sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01'); CREATE TABLE feb_sales (LIKE sales); ALTER TABLE sales ATTACH PARTITION feb_sales FOR VALUES FROM ('2024-02-01') TO ('2024-03-01'); \d+ sales Partitioned table "public.sales" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description --------+---------------+-----------+----------+---------+---------+--------------+------------- id | integer | | | | plain | | date | date | | | | plain | | amt | numeric(10,2) | | | | main | | Partition key: RANGE (date) Partitions: feb_sales FOR VALUES FROM ('2024-02-01') TO ('2024-03-01'), jan_sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01') Distributed by: (id) Access method: heap ``` This difference, however, is consistent among the old and new syntaxes themselves. For example, we do not need to specify the prefix when using the legacy `DROP PARTITION` syntax. But we will need to if we use `DETACH PARTITION` to do the same: ```sql -- Assuming we have the 'sales' partition with Jan and Feb -- child partitions, created using legacy syntax. \d+ sales Partitioned table "public.sales" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description --------+---------------+-----------+----------+---------+---------+--------------+------------- id | integer | | | | plain | | date | date | | | | plain | | amt | numeric(10,2) | | | | main | | Partition key: RANGE (date) Partitions: sales_1_prt_feb_sales FOR VALUES FROM ('2023-02-01') TO ('2023-03-01'), sales_1_prt_jan_sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01') Distributed by: (id) Access method: heap -- drop partition 'jan_sales', no problem ALTER TABLE sales DROP PARTITION jan_sales; -- but couldn't detach, because there's no table named 'feb_sales' ALTER TABLE sales DETACH PARTITION feb_sales; ERROR: relation "feb_sales" does not exist -- have to specify full name using DETACH ALTER TABLE sales DETACH PARTITION sales_1_prt_feb_sales; ``` > [color=#7ddb3b] Therefore, it is highly recommended, at least for the same partitioned table, to stick to using either the new syntaxes or the legacy syntaxes to avoid name ambiguity. For convenience let's use a table to see the difference outright: <details> <summary> Table (Click) </summary> | Syntax | Add prefix or not| Legacy or New | | - | - | - | | `ADD PARTITION`| Yes | Legacy | | `DROP PARTITION`| Yes | Legacy | | `EXCHANGE PARTITION`| Yes | Legacy | | `SPLIT PARTITION`| Yes | Legacy | | `CREATE TABLE (PARTITION ...)`| Yes | Legacy | | `CREATE TABLE (EVERY ...)`| Yes | Legacy | | `CREATE TABLE ... PARTITION OF` | No | New | | `ATTACH PARTITION` | No | New | | `DETACH PARTITION` | No | New | </details> ## 3.2 `START|END` vs `FROM|TO` From the SQL examples that have shown before, you probably have noticed that the new syntax also have different keywords for range partition definition: `FOR VALUES FROM ... TO ...`. The Greenplum legacy syntax has `START ... END ()`. Both definitions will work only in the corresponding legacy or new DDLs: ```sql -- Both these work: ALTER TABLE sales ADD PARTITION mar_sales START ('2023-03-01') END ('2023-03-31'); CREATE TABLE mar_sales PARTITION OF sales FOR VALUES FROM ('2023-03-01') TO ('2023-03-31'); -- But these won't: ALTER TABLE sales ADD PARTITION mar_sales FOR VALUES FROM ('2023-03-01') TO ('2023-03-31'); CREATE TABLE mar_sales PARTITION OF sales START ('2023-03-01') END ('2023-03-31'); ``` **`EXCLUSIVE` / `INCLUSIVE`** The legacy syntax also has `EXCLUSIVE` and `INCLUSIVE` keywords for range partitioning. In PostgreSQL, there's no such thing and **the start boundary is always inclusive and end exclusive**. Greenplum 7 continues to support `EXCLUSIVE`|`INCLUSIVE` by implicitly adding "$+1$" to the start or end range. As a result, they now only work for datatypes that have a suitable "$+$" operator, like `integer` and `timestamp`, but not `float` or `text`. ```sql ALTER TABLE sales ADD PARTITION mar_sales START ('2023-03-01') INCLUSIVE END ('2023-03-31') INCLUSIVE; ``` ## 3.3 Less locking in `ATTACH PARTITION` The locking behavior in partition deserves another blog, but one of the most important things that users should be aware is less restricted locking with `ATTACH PARTITION`. `ATTACH PARTITION` only requires a Share Update Exclusive Lock on the parent table. This lock type is a [relatively less restrictive one](https://www.postgresql.org/docs/current/explicit-locking.html#TABLE-LOCK-COMPATIBILITY) that doesn't conflict with many other queries, including `SELECT`, `INSERT` and sometimes `UPDATE`. This basically means that, only until Greenplum 7 it becomes possible to add partition to a partition hierarchy without disrupting many normal query executions on the partition (and vice versa). For example: ```sql -- Assuming there's long-running insert INSERT INTO sales SELECT * FROM ext_sales_data; -- This will be blocked ALTER TABLE sales ADD PARTITION march_sales START ('2023-03-01') END ('2023-04-01'); -- This will go through ALTER TABLE sales ATTACH PARTITION march_sales FOR VALUES FROM ('2023-03-01') TO ('2023-04-01'); ``` Check this [demo video](https://www.youtube.com/watch?v=x--keiUJCf0&feature=youtu.be) to see it in effect. <details> <summary>(Click) A lock table for partition DDLs </summary> Without going into too much details, here is a table for what lock is acquired on partition DDLs and what query is allowed on the partitioned table when those DDLs are being executed at the same time: | Command | Highest Lock Type| Allowed Query | | - | - | - | | `ADD PARTITION`| AccessExclusiveLock | None | | `DROP PARTITION`| AccessExclusiveLock | None | | `EXCHANGE PARTITION`| AccessExclusiveLock | None | | `SPLIT PARTITION`| AccessExclusiveLock | None | | `CREATE TABLE ... PARTITION OF` | AccessExclusiveLock | None | | `ATTACH PARTITION` | ShareUpdateExclusiveLock | SELECT, INSERT, UPDATE** | | `DETACH PARTITION` | AccessExclusiveLock* | None | > **In PG14 and later, it is ShareUpdateExclusiveLock if executed `CONCURRENTLY`.* > **When `gp_enable_global_deadlock_detector` is ON and the table is not append-optimized. </details> ## 3.4 Partition constraints vs Check constraints Partition boundaries are no longer represented as CHECK constraints. Partition constraints is a completely separate concept now. ```sql -- same partition definition in Greenplum 6 and 7 -- Greenplum 6 \d+ sales_1_prt_jan_sales Table "public.sales_1_prt_jan_sales" Column | Type | Modifiers | Storage | Stats target | Description --------+---------------+-----------+---------+--------------+------------- id | integer | | plain | | date | date | | plain | | amt | numeric(10,2) | | main | | Check constraints: "sales_1_prt_jan_sales_check" CHECK (date >= '2023-01-01'::date AND date < '2023-02-01'::date) Inherits: sales Distributed by: (id) -- Greenplum 7 \d+ jan_sales Table "public.jan_sales" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description --------+---------------+-----------+----------+---------+---------+--------------+------------- id | integer | | | | plain | | date | date | | | | plain | | amt | numeric(10,2) | | | | main | | Partition of: sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01') Partition constraint: ((date IS NOT NULL) AND (date >= '2023-01-01'::date) AND (date < '2023-02-01'::date)) Distributed by: (id) ``` ## 3.5 Multi-column `PARTITION BY` Multi-column list partitioning is no longer supported. As a workaround, you can create a composite type and use that as the partitioning key, e.g.: ```sql -- This is no longer working: CREATE TABLE foo (a int, b int, c int) PARTITION BY list (b,c); ERROR: cannot use "list" partition strategy with more than one column -- Alternatively: CREATE TYPE partkey as (b int, c int); CREATE TABLE foo (a int, b int, c int) PARTITION BY LIST ((row(b, c)::partkey)); ``` <!-- Removed. Just keeping here for future reference. ~~# 3. Comparison with PostgreSQL~~ As mentioned, Greenplum 7 strives to get the best out of both Greenplum and PostgreSQL worlds. In previous sections, we have covered what we get from PostgreSQL. This section talks about what traditional Greenplum behaviors are kept whereas it becomes different from PostgreSQL. ~~## 3.1 `COPY`~~ Greenplum supports the `COPY` command on partitioned table. Therefore, for our examples we can do: ```sql COPY sales FROM 'sales_in.csv'; COPY sales TO 'sales_out.csv'; ``` ~~## 3.2 `REINDEX TABLE|INDEX`~~ Greenplum supports `REINDEX` on partitioned tables and partitioned indexes. Therefore, we can do: ```sql CREATE INDEX sales_i ON sales(id); REINDEX TABLE sales; REINDEX INDEX sales_i; ``` ~~## 3.3 Triggers~~ The use of triggers in Greenplum is [quite limited](https://docs.vmware.com/en/VMware-Tanzu-Greenplum/6/greenplum-database/GUID-ref_guide-sql_commands-CREATE_TRIGGER.html#:~:text=The%20CREATE%20TRIGGER%20statement%20in%20Greenplum%20Database%20implements%20a%20subset%20of%20the%20SQL%20standard.%20The%20following%20functionality%20is%20currently%20missing). But in case it works, triggers *can* being fired on partitioned tables as same as regular tables: ```sql CREATE FUNCTION insert_notice_func() RETURNS TRIGGER AS $$ BEGIN RAISE NOTICE 'INSERT trigger fired on % for %', TG_TABLE_NAME, TG_OP; RETURN new; END; $$ LANGUAGE plpgsql; CREATE TRIGGER insert_notice_trig AFTER INSERT ON sales FOR EACH ROW EXECUTE PROCEDURE insert_notice_func(); -- The above trigger will raise a NOTICE for every INSERT on the partitioned table: INSERT INTO sales VALUES(1, '2023-01-01', 0.10); NOTICE: INSERT trigger fired on jan_sales for INSERT INSERT 0 1 ``` --> # References Regarding use of PostgreSQL partitioning: * PostgreSQL documentation on table partitioning: https://www.postgresql.org/docs/12/ddl-partitioning.html * PostgreSQL partitioning tutorial: https://www.youtube.com/watch?v=oJj-pltxBUM * "Beginner’s Guide to Table Partitioning In PostgreSQL": https://medium.com/swlh/beginners-guide-to-table-partitioning-in-postgresql-5a014229042

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully