If you want to use the LIST rule to partition, but the values of partition key fields cannot be all enumerated, or there are many enumerated values, and the corresponding data volume is small. The data distribution complies with the principle of "two eight". 20% of the partition key values contain 80% of the data, and the remaining 80% of the partition key values contain 20% of the data. In this scenario, you can choose the LIST DEFAULT HASH partition type. 80% of the data is partitioned according to the LIST rule. The data that does not conform to the LIST rule is placed in the DEFAULT partitions which partitioned according to the HASH rule.
For example, for a multi tenant business system, the amount of user data generated by each tenant is uneven. You can partition the tenants with large amounts of data according to the LIST rule, and then the tenants with small amounts of data are divided into multiple partitions according to the HASH rule
TENANT_ID | RECORDS. | PARTITION |
VIP_CUST_1 | 300billion | p1 |
VIP_CUST_2 | 260billion | p2 |
VIP_CUST_3 | 240billion | p3 |
VIP_CUST_4 | 200billion | p4 |
other custs | 300billion | p_others |
For conventional database, the table will be created like this:
CREATE TABLE cust_orders
(
customer_id VARCHAR(36),
year VARCHAR(60),
order_id INT,
order_content text
) PARTITION BY LIST COLUMNS(customer_id)
(
PARTITION p1 VALUES IN ('VIP_CUST_1'),
PARTITION p2 VALUES IN ('VIP_CUST_2'),
PARTITION p3 VALUES IN ('VIP_CUST_3'),
PARTITION p4 VALUES IN ('VIP_CUST_4'),
PARTITION p_others VALUES IN ('CUST_5', 'CUST_6',...)
);
There are too many values in partition p_others, it is not convenient to write the create table sql, and the performence of query like the following will try to find the 'cust_xx' throught amount of values to make sure it is in partition p_others in the processing of the sql execution.
select * from cust_orders where customer_id='cust_xx';
Also, the following insert sql also need to make sure 'cust_new' is one member of the list values,
insert into cust_orders values ( 'cust_new', '20221228', 232342, 'context' );
And, sometimes the list values cannot be all enumerated, so the partitions cannot be defined.
The new partition type List Default Hash is a new feature of innovation on PolarDB which can solve this kind of problem perfectly.
For List Default Hash partition type, the front partitions are the normal LIST partitions. Data not in the LIST partition is placed in the DEFAULT partition. If the DEFAULT partition is too large, it can be divided into multiple DEFAULT partitions according to HASH rules
The steps is based on that we have an PolarDB MySQL instance, and we connected a session to the instance.
create database test
create database test;
use test
create the table cust_orders with List Default Hash partitions.
CREATE TABLE cust_orders
(
customer_id VARCHAR(36),
year VARCHAR(60),
order_id INT,
order_content text
) PARTITION BY LIST COLUMNS(customer_id)
(
PARTITION p1 VALUES IN ('VIP_CUST_1'),
PARTITION p2 VALUES IN ('VIP_CUST_2'),
PARTITION p3 VALUES IN ('VIP_CUST_3'),
PARTITION p4 VALUES IN ('VIP_CUST_4'),
PARTITION p_others DEFAULT PARTITIONS 3
);
insert into cust_orders values ( 'cust_new', '20221228', 232342, 'context' );
insert into cust_orders values ( 'cust_new', '20221228', 232342, 'context' );
insert into cust_orders values ( 'cust_new1', '20221228', 232342, 'context' );
insert into cust_orders values ( 'cust_new2', '20221228', 232342, 'context' );
insert into cust_orders values ( 'cust_new3', '20221228', 232342, 'context' );
insert into cust_orders values ( 'cust_n3', '20221228', 232342, 'context' );
When the records of 'cust_new' increasing fast, and its records is so many that it can be an independent partition.
With REORGANIZE PARTITION, you can separate some values from the DEFAULT partition and add new LIST partition for them:
explain select * from cust_orders where customer_id='cust_new';
mysql> explain select * from cust_orders where customer_id='cust_new';
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | cust_orders | p_others2 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
Now customer_id 'cust_new' is in partition p_others2;
Execute the REORGANIZE PARTITION SQL to separate the value 'cust_new' from the DEFAULT partition and add new LIST partition p5 for it.
ALTER TABLE cust_orders
REORGANIZE PARTITION p_others0, p_others1,p_others2
INTO (
PARTITION p5 VALUES IN ('cust_new'),
PARTITION p_others DEFAULT PARTITIONS 2);
Show create table to see the table structure descriptions, we can see it has partition p5.
mysql> show create table cust_orders;
| Table | Create Table
| cust_orders | CREATE TABLE `cust_orders` (
`customer_id` varchar(36) DEFAULT NULL,
`year` varchar(60) DEFAULT NULL,
`order_id` int(11) DEFAULT NULL,
`order_content` text
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!99990 800020201 PARTITION BY LIST COLUMNS(customer_id)
(PARTITION p1 VALUES IN ('VIP_CUST_1') ENGINE = InnoDB,
PARTITION p2 VALUES IN ('VIP_CUST_2') ENGINE = InnoDB,
PARTITION p3 VALUES IN ('VIP_CUST_3') ENGINE = InnoDB,
PARTITION p4 VALUES IN ('VIP_CUST_4') ENGINE = InnoDB,
PARTITION p5 VALUES IN ('cust_new') ENGINE = InnoDB,
PARTITION p_others DEFAULT PARTITIONS 2 ENGINE = InnoDB) */ |
Check whether the record with the customer_id 'cust_new' is in partition p5, and not in the default partitions.
mysql> select * from cust_orders partition(p5);
+-------------+----------+----------+---------------+
| customer_id | year | order_id | order_content |
+-------------+----------+----------+---------------+
| cust_new | 20221228 | 232342 | context |
+-------------+----------+----------+---------------+
1 row in set (0.00 sec)
mysql> select * from cust_orders partition(p_others0);
+-------------+----------+----------+---------------+
| customer_id | year | order_id | order_content |
+-------------+----------+----------+---------------+
| cust_nn3 | 20221228 | 232342 | context |
| cust_n3 | 20221228 | 232342 | context |
| cust_new1 | 20221228 | 232342 | context |
| cust_new2 | 20221228 | 232342 | context |
| cust_new3 | 20221228 | 232342 | context |
+-------------+----------+----------+---------------+
5 rows in set (0.00 sec)
mysql> select * from cust_orders partition(p_others1);
Empty set (0.00 sec)
mysql> explain select * from cust_orders where customer_id='cust_new';
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | cust_orders | p5 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> select * from cust_orders where customer_id='cust_new';
+-------------+----------+----------+---------------+
| customer_id | year | order_id | order_content |
+-------------+----------+----------+---------------+
| cust_new | 20221228 | 232342 | context |
+-------------+----------+----------+---------------+
Execute the REORGANIZE PARTITION SQL to merge the LIST partition p5 into the DEFAULT partitions.
ALTER TABLE cust_orders
REORGANIZE PARTITION
p5, p_others0, p_others1
INTO (
PARTITION p_others DEFAULT PARTITIONS 2);
Check whether the record with the customer_id 'cust_new' is in the default partitions, and not in partition p5.
mysql> select * from cust_orders where customer_id='cust_new';
+-------------+----------+----------+---------------+
| customer_id | year | order_id | order_content |
+-------------+----------+----------+---------------+
| cust_new | 20221228 | 232342 | context |
+-------------+----------+----------+---------------+
1 row in set (0.00 sec)
mysql> explain select * from cust_orders where customer_id='cust_new';
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | cust_orders | p_others0 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
+----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from cust_orders;
+----+-------------+-------------+---------------------------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------------+---------------------------------+------+---------------+------+---------+------+------+----------+-------+
| 1 | SIMPLE | cust_orders | p1,p2,p3,p4,p_others0,p_others1 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
+----+-------------+-------------+---------------------------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
Now table cust_orders has 2 default partitions: p_others0,p_others1
Execute the REORGANIZE PARTITION SQL to change the number of DEFAULT partitions to 4.
ALTER TABLE cust_orders
REORGANIZE PARTITION
p_others0, p_others1
INTO(
PARTITION p_others DEFAULT PARTITIONS 4);
After REORGANIZE PARTITION operation, table cust_orders has 4 default partitions: p_others0,p_others1,p_others2,p_others3
mysql> explain select * from cust_orders;
+----+-------------+-------------+-----------------------------------------------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------------+-----------------------------------------------------+------+---------------+------+---------+------+------+----------+-------+
| 1 | SIMPLE | cust_orders | p1,p2,p3,p4,p_others0,p_others1,p_others2,p_others3 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
+----+-------------+-------------+-----------------------------------------------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.01 sec)
[Infographic] Highlights | Database New Feature in March 2023
PolarDB Hands-on | PolarDB for MySQL: Automatic Interval Partitioning
ApsaraDB - May 31, 2023
ApsaraDB - April 26, 2023
ApsaraDB - April 20, 2023
ApsaraDB - January 3, 2024
Alibaba Cloud Project Hub - April 13, 2023
ApsaraDB - April 10, 2024
Alibaba Cloud PolarDB for MySQL is a cloud-native relational database service 100% compatible with MySQL.
Learn MoreAlibaba Cloud PolarDB for PostgreSQL is an in-house relational database service 100% compatible with PostgreSQL and highly compatible with the Oracle syntax.
Learn MoreAlibaba Cloud PolarDB for Xscale (PolarDB-X) is a cloud-native high-performance distributed database service independently developed by Alibaba Cloud.
Learn MoreApsaraDB: Faster, Stronger, More Secure
Learn MoreMore Posts by ApsaraDB