CREATE TABLE (AUTO mode)

更新时间:
复制 MD 格式

This topic explains the DDL syntax, clauses, and parameters for creating partitioned tables in PolarDB-X AUTO mode databases.

Notes

  • Before using the syntax to create partitioned tables, ensure the current logical database is in auto partition mode (mode='auto'). This syntax is not supported in other modes. You can run the SHOW CREATE DATABASE db_name command to check the mode of the current logical database. For example:

    CREATE DATABASE part_db mode='auto';
    Query OK, 1 row affected (4.29 sec)
    
    SHOW CREATE DATABASE part_db;
    +----------+-----------------------------------------------+
    | DATABASE | CREATE DATABASE                               |
    +----------+-----------------------------------------------+
    | part_db  | CREATE DATABASE `part_db` /* MODE = 'auto' */ |
    +----------+-----------------------------------------------+
    1 row in set (0.18 sec)

    For details on the CREATE DATABASE syntax, see CREATE DATABASE.

  • If the primary key of a partitioned table does not include the partition key and is not an auto-increment primary key, you must ensure the primary key is unique at the application level.

  • To use the subpartitioning feature, the instance version must be 5.4.17-16952556 or later.

Syntax

CREATE [PARTITION] TABLE [IF NOT EXISTS] tbl_name
    (create_definition, ...)
    [table_options]
    [table_partition_definition]
    [local_partition_definition]

create_definition:
    col_name column_definition
  | mysql_create_definition
  | [UNIQUE] GLOBAL INDEX index_name [index_type] (index_sharding_col_name,...)
      [global_secondary_index_option]
      [index_option] ...

index_sharding_col_name:
    col_name [(length)] [ASC | DESC]

index_option:
    KEY_BLOCK_SIZE [=] value
  | index_type
  | WITH PARSER parser_name
  | COMMENT 'string'

index_type:
    USING {BTREE | HASH}

# Global secondary index options
global_secondary_index_option:
    [COVERING (col_name,...)]
    [partition_options]
    [VISIBLE|INVISIBLE]

table_options:
    table_option [[,] table_option] ...

table_option: {
# Specify a table group
    TABLEGROUP [=] value,...,}
    
# Partitioned table type definition
table_partition_definition:
		single
  |	broadcast
  | partition_options

# Partition definition
partition_options:
	partition_columns_definition
	[subpartition_columns_definition]
	[subpartition_specs_definition] /* Defines templated subpartitions. */ 
  partition_specs_definition 

# Partition key definition
partition_columns_definition:
		PARTITION BY
          HASH({column_name | partition_func(column_name)}) partitions_count
        | KEY(column_list) partitions_count
        | RANGE ({column_name | partition_func(column_name)}) 
        | RANGE COLUMNS(column_list)
        | LIST ({column_name | partition_func(column_name)}) 
        | LIST COLUMNS(column_list) 
        | CO_HASH({column_expr_list}) partitions_count 

# Subpartition key definition
subpartition_columns_definition:
		SUBPARTITION BY
          HASH({column_name | partition_func(column_name)}) subpartitions_count
        | KEY(column_list) subpartitions_count
        | RANGE ({column_name | partition_func(column_name)}) 
        | RANGE COLUMNS(column_list)
        | LIST ({column_name | partition_func(column_name)})
        | LIST COLUMNS(column_list)
        | CO_HASH({column_expr_list}) partitions_count

column_expr_list:
	{column_name | partition_func(column_name)},{column_name | partition_func(column_name)}[,{column_name | partition_func(column_name)},...]

partitions_count:
   PARTITIONS partition_count

subpartitions_count:
   SUBPARTITIONS partition_count

# Partitioning functions
partition_func:
    YEAR
  | TO_DAYS
  | TO_MONTHS
  | TO_WEEKS
  | TO_SECOND
  | UNIX_TIMESTAMP
  | MONTH
  | DAYOFWEEK
  | DAYOFMONTH
  | DAYOFYEAR
  | SUBSTR
  | SUBSTRING
  | RIGHT
  | LEFT


# Partition specification
partition_specs_definition:
	hash_partition_list
  | range_partition_list
  | list_partition_list

# Subpartition specification
subpartition_specs_definition:
	hash_subpartition_list
  | range_subpartition_list
  | list_subpartition_list

# HASH/KEY partition definition
hash_partition_list:
	  /* For HASH partitioning, individual partition definitions are optional. */
	| ( hash_partition [, hash_partition, ...] )

hash_partition:
    PARTITION partition_name [partition_spec_options] /* For partitioned tables that have no subpartitions or use templated subpartitions. */
  | PARTITION partition_name subpartitions_count [subpartition_specs_definition] /* Defines non-templated subpartitions within a partition. */

# HASH/KEY subpartition definition
hash_subpartition_list:
  | empty
  | ( hash_subpartition [, hash_subpartition, ...] )

hash_subpartition:
	SUBPARTITION subpartition_name [partition_spec_options]

# RANGE/RANGE COLUMNS partition definition
range_partition_list:
    ( range_partition [, range_partition, ... ] )

range_partition:
    	PARTITION partition_name VALUES LESS THAN (range_bound_value) [partition_spec_options] /* For partitioned tables that have no subpartitions or use templated subpartitions. */
    |	PARTITION partition_name VALUES LESS THAN (range_bound_value) [[subpartitions_count] [subpartition_specs_definition]] /* Defines non-templated subpartitions within a partition. */
   
# RANGE/RANGE COLUMNS subpartition definition
range_subpartition_list:
	( range_subpartition [, range_subpartition, ... ] )

range_subpartition:
    SUBPARTITION subpartition_name VALUES LESS THAN (range_bound_value) [partition_spec_options]
  
range_bound_value:
	  maxvalue /* Defines a MAXVALUE partition for RANGE partitioning. */
	| expr /* Boundary value for a single partition key */
	| value_list /* Boundary values for multiple partition keys */

# LIST/LIST COLUMNS partition definition
list_partition_list:
    (list_partition [, list_partition ...])

list_partition:
    	PARTITION partition_name VALUES IN (list_bound_value) [partition_spec_options] /* For partitioned tables that have no subpartitions or use templated subpartitions. */
    |	PARTITION partition_name VALUES IN (list_bound_value) [[subpartitions_count] [subpartition_specs_definition]] /* Defines non-templated subpartitions within a partition. */

# LIST/LIST COLUMNS subpartition definition
list_subpartition_list:
	(list_subpartition [, list_subpartition ...])

list_subpartition:
	SUBPARTITION subpartition_name VALUES IN (list_bound_value) [partition_spec_options]

list_bound_value:
		default  /* Defines a DEFAULT partition for LIST partitioning. */
	|	value_set

value_set:
	  value_list  /* Set of values for a single partition key */
	| (value_list) [, (value_list), ...] /* Sets of values for multiple partition keys */

value_list:
	value [, value, ...]

partition_spec_options:
	    [[STORAGE] ENGINE [=] engine_name]
        [COMMENT [=] 'string']
        [LOCALITY [=] locality_option]

table_option:
 	    [[STORAGE] ENGINE [=] engine_name]
        [COMMENT [=] 'string']
        [{CHARSET | CHARACTER SET} [=] charset]
        [COLLATE [=] collation]
        [TABLEGROUP [=] table_group_id]
        [LOCALITY [=] locality_option]  

locality_option:
    'dn=storage_inst_id_list'
    
storage_inst_id_list:
    storage_inst_id[,storage_inst_id_list]

local_partition_definition:
		LOCAL PARTITION BY RANGE (column_name)
    [STARTWITH 'yyyy-MM-dd']
    INTERVAL interval_count [YEAR|MONTH|DAY]
    [EXPIRE AFTER expire_after_count]
    [PRE ALLOCATE pre_allocate_count]
    [PIVOTDATE pivotdate_func]
    [DISABLE SCHEDULE]
    
pivotdate_func:
		NOW()
  |	DATE_ADD(...)
  | DATE_SUB(...)
Note

The PolarDB-X DDL syntax is based on MySQL. The syntax above highlights the main differences. For the complete syntax, see the MySQL documentation.

Glossary

  • Partition key: One or more columns in a partitioned table used for horizontal partitioning.

  • Partition column: A column used for partition routing and calculation in a horizontally partitioned table. It is usually part of a partition key.

  • Vector partition key: A partition key that consists of one or more partition columns.

  • Single-column partition key: A partition key that consists of a single partition column.

  • Prefix partition column: For a vector partition key with N (N > 1) partition columns, its prefix consists of the first K columns, where 1 <= K < N.

  • Partition function: A function that accepts a partition column as input. Its output provides the value for routing calculations.

  • Partition pruning: A query optimization technique that avoids scanning unnecessary partitions based on partition definitions and query conditions.

  • Hot spot splitting: A load balancing technique that splits a hot partition by using the subsequent partition column. This split is triggered when the prefix partition columns of a vector partition key experience access hot spots or an uneven data distribution.

  • Physical partition: A partition with a one-to-one mapping to a physical subtable on a DN node.

  • Logical partition: A virtual partition that maps to one or more physical partitions. For example, in a table created with subpartitioning, the first-level partitions are logical partitions.

Parameters

Parameter

Description

CHARSET | CHARACTER SET

Specifies the default character set for the columns in the table. The following character sets are supported:

  • utf8

  • utf8mb4

  • gbk

COLLATE

Specifies the default collation for the columns in the table. The following collations are supported:

  • utf8_bin

  • utf8_general_ci

  • utf8_unicode_ci

  • gbk_bin

  • gbk_chinese_ci

  • utf8mb4_general_ci

  • utf8mb4__general_cs

  • utf8mb4_bin

  • utf8mb4_unicode_ci

TABLEGROUP

Specifies the table group for the partitioned table. If omitted, the system automatically finds or creates a compatible table group that matches the table's partitioning method.

LOCALITY

Specifies the data nodes that store the partitioned table.

Single tables

In PolarDB-X, you can create non-partitioned tables by using the SINGLE keyword. For example:

CREATE TABLE single_tbl(
 id bigint not null auto_increment, 
 bid int, 
 name varchar(30), 
 primary key(id)
) SINGLE;

Broadcast tables

In PolarDB-X, you can create broadcast tables by specifying the BROADCAST keyword. A broadcast table contains an identical copy of its data on all data nodes. For example:

CREATE TABLE broadcast_tbl(
 id bigint not null auto_increment, 
 bid int, 
 name varchar(30), 
 primary key(id)
) BROADCAST;

Partitioned table

Partition types

PolarDB-X lets you create partitioned tables to meet your business requirements by specifying a partition clause. PolarDB-X supports the following four types of partitioning:

  • Hash partitioning: This strategy routes data by applying a built-in consistent hashing algorithm to the value of a partition column or partition function expression. Hash partitioning is subdivided into two strategies, Key partitioning and Hash partitioning, depending on whether a partition function expression or multiple partition columns can be used as the partition key.

  • Range partitioning: This strategy routes data by comparing the value of a partition column or partition function expression against predefined partition ranges. Range partitioning is subdivided into two strategies, Range Columns partitioning and Range partitioning, depending on whether a partition function expression or multiple partition columns can be used as the partition key.

  • List partitioning: Similar to Range partitioning, this strategy routes data by checking if the value of a partition column or partition function expression is in a predefined list of values for a partition. List partitioning is subdivided into two strategies, List Columns partitioning and List partitioning, based on whether and how multiple partition columns are used as the partition key.

  • CoHash. This is an extended hash partitioning strategy from PolarDB-X, designed for specific, common application scenarios. This strategy enables the horizontal partitioning of a table based on multiple, correlated partition columns.

Hash type

In PolarDB-X, there are two types of hash-based partitioning: hash partitioning and key partitioning. Both are part of the standard partitioning syntax in native MySQL. To enable flexible partition management features—such as partition split, merge, and migration—and to support hot-spot splitting for vector partition keys, PolarDB-X redefines the routing for hash and key partitioning; while it remains syntactically compatible with the MySQL CREATE TABLE syntax, its underlying partition routing implementation is different from that of MySQL. The following table describes the differences between key partitioning and hash partitioning:

Table 1. Comparison of the key and hash partitioning strategies

Partitioning strategy

Partition key support

Partitioning function support

Syntax example

Features and limitations

Routing (point query)

Key (the default partitioning strategy)

single-column partition key

No

PARTITION BY KEY(c1)

  • Does not support hotspot splitting.

  • Uses at most one partitioning column for routing.

  1. Calculates a hash value, c1_hash, for the value in the c1 column using a consistent hashing algorithm.

  2. Routes data to a partition based on the c1_hash value.

vector partition key

No

PARTITION BY KEY(c1, c2, ..., cn)

  • Supports hotspot splitting.

  • By default, routing uses only the first partitioning column, c1. Additional partitioning columns, such as c2 through cn, can be used during hotspot splitting.

  • Routing can use up to n partitioning columns simultaneously.

  • By default, the number of partitioning columns (n) cannot exceed 5.

  1. Combines the values from columns (c1, c2, ..., cn) into a partition key vector, and then applies a consistent hashing algorithm to each value in the vector to create a corresponding hash value vector (c1_hash, c2_hash, ..., cn_hash).

  2. Uses range-based routing on the hash value vector (c1_hash, c2_hash, ..., cn_hash) to locate the target partition.

Hash

single-column partition key

No

PARTITION BY HASH(c1)

  • Does not support hotspot splitting.

  • Routing uses one partitioning column.

  • Currently supports 11 partitioning functions:

    • YEAR

    • MONTH

    • DAYOFMONTH

    • DAYOFWEEK

    • DAYOFYEAR

    • TO_DAYS

    • TO_MONTHS

    • TO_WEEKS

    • TO_SECONDS

    • UNIX_TIMESTAMP

    • SUBSTR/SUBSTRING

PARTITION BY HASH(c1) is equivalent to PARTITION BY KEY(c1) and uses an identical routing algorithm.

Yes

PARTITION BY HASH(YEAR(c1))

  1. Calculates the year from the value in the c1 column using the YEAR partitioning function.

  2. Calculates a hash value, year_hash, for the year using a consistent hashing algorithm.

  3. Routes data to a partition based on the year_hash value.

vector partition key

No

PARTITION BY HASH(c1, c2, ..., cn)

  • Does not support hotspot splitting.

  • After table creation, routing simultaneously uses all n partitioning columns.

  • By default, the number of partitioning columns (n) cannot exceed 5.

  1. Combines the values from the n partitioning columns (c1, c2, ..., cn) into a vector, and then uses a consistent hashing algorithm to calculate a single hash value, hashVal, for the entire vector.

  2. Routes data to a partition based on the hashVal value.

Example 1-1: Key partition

Key partitioning is also the default partitioning method in PolarDB-X. This method supports vector partition keys. For example, the following statement creates a table partitioned by the user name (name) and user ID (id) into eight partitions:

CREATE TABLE key_tbl(
 id bigint not null auto_increment,
 bid int,
 name varchar(30),
 birthday datetime not null,
 primary key(id)
)
PARTITION BY KEY(name, id)
PARTITIONS 8;

For a partitioned table that uses a KEY partition with a vector partition key, routing by default depends only on the first partition column (name). Therefore, partition pruning is triggered when the WHERE clause contains an equality condition for this first partition column. For example:

## This query triggers partition pruning and scans only a single partition.
SELECT id from key_tbl where name='Jack';

If the first partition column, name, causes data imbalance or a data hotspot, you can perform a partition split using the next partition column, such as id. For details, see Modify a table group level partition (AUTO mode).

If a vector partition key with N partition columns uses its first K columns for routing (1 ≤ K ≤ N), including conditions on the prefix partition columns (the first K columns) in the WHERE clause enables partition pruning.

Example 1-2: Hash partitioning

To use a user ID as the partition key for horizontal partitioning, create the table using hash partitioning and specify 8 partitions:

CREATE TABLE hash_tbl(
 id bigint not null auto_increment,
 bid int,
 name varchar(30),
 birthday datetime not null,
 primary key(id)
)
partition by hash(id)
partitions 8;

Hash partitioning supports partitioning function expressions, such as YEAR() and TO_DAYS(), to convert values of time types to integer types. For example, to partition a table by the birthday column into 8 hash partitions, use the following statement:

CREATE TABLE hash_tbl_todays(
 id bigint not null auto_increment,
 bid int,
 name varchar(30),
 birthday datetime not null,
 primary key(id)
)
PARTITION BY HASH(TO_DAYS(birthday))
PARTITIONS 8;

Currently, PolarDB-X supports the following partitioning functions:

  • YEAR

  • MONTH

  • DAYOFMONTH

  • DAYOFWEEK

  • DAYOFYEAR

  • TO_DAYS

  • TO_MONTHS

  • TO_WEEKS

  • TO_SECONDS

  • UNIX_TIMESTAMP

  • SUBSTR/SUBSTRING

For SUBSTR/SUBSTRING functions, the partition key must be a string type; for all other partition functions, it must be a time type (such as DATE, DATETIME, or TIMESTAMP).

Example 1-3: Hash partition expansion

PolarDB-X extends hash partitioning syntax to support a vector partition key. Unlike native MySQL's standard partitioning syntax, PolarDB-X lets you partition by multiple columns with the HASH method. Use the following statement:

CREATE TABLE hash_tbl2(
 id bigint not null auto_increment,
 bid int,
 name varchar(30),
 birthday datetime not null,
 primary key(id)
)
PARTITION BY HASH(name, birthday)
PARTITIONS 8;

Unlike key partitioning, hash partitioning uses a vector partition key, where all partition columns contribute to both the hash and routing calculations during partition routing. Therefore, to enable partition pruning, the WHERE clause of an SQL query must specify equality conditions for all partition columns. For example, SQL1 can trigger partition pruning on the hash_tbl2 table, but SQL2 cannot:

##SQL1 (This query triggers partition pruning, scanning only a single partition)
SELECT id from hash_tbl2 where name='Jack' and birthday='1990-11-11';

##SQL2 (This query does not trigger partition pruning, resulting in a full partition scan)
SELECT id from hash_tbl2 where name='Jack';

Because hash partitioning uses the entire partition key to calculate the hash value up front, it theoretically distributes data more evenly than key partitioning using a vector partitioning key. However, it cannot support hotspot splitting, as there are no subsequent columns available to split a hot partition.

Limitations

  • Data type limitations

    • Integer types: BIGINT, BIGINT UNSIGNED, INT, INT UNSIGNED, MEDIUMINT, MEDIUMINT UNSIGNED, SMALLINT, SMALLINT UNSIGNED, TINYINT, and TINYINT UNSIGNED.

    • Time types: DATETIME, DATE, and TIMESTAMP.

    • String types: CHAR and VARCHAR.

  • Syntax limitations

    • When using a partition function with a single-column partition key for a hash partition, the key must be a time type.

    • A vector partition key for a hash partition does not support partition functions or hotspot splitting.

    • By default, the maximum number of partitions is 8,192.

    • By default, the maximum number of partition columns is 5.

Data Uniformity

  • The built-in consistent hash algorithm for key partitioning and hash partitioning is MurmurHash3, a high-performance algorithm with a low collision probability.

  • With MurmurHash3, data distribution for key partitioning and hash partitioning typically becomes balanced only when the number of distinct partition key values (N) exceeds 3000. The larger the value of N, the more balanced the data distribution.

Range type

In PolarDB-X, there are two types of range partitioning: range partition and range columns partition. Both are part of the standard partitioning syntax of native MySQL. The following table compares these two partition types.

Table 2. Comparison of Range Columns and Range partitioning strategies

Partitioning strategy

Partition key support

Partition function support

Syntax example

Features and limitations

Routing (point query)

Range Columns

single-column and vector partition keys

No

PARTITION BY RANGE COLUMNS (c1,c2,...,cn) ( PARTITION p1 VALUES LESS THAN (1,10,...,1000), PARTITION p2 VALUES LESS THAN (2,20,...,2000) ...)

Supports hotspot splitting. For example, if column c1 has a hotspot at value 88, you can use column c2 to split the partition and resolve the hotspot.

  1. Creates a partition key vector from the values in columns (c1, c2, ..., cn).

  2. Uses a binary search on this partition key vector (c1, c2, ..., cn) to find the corresponding predefined partition, then routes to that partition.

Range

single-column partition key

Yes

PARTITION BY RANGE(YEAR(c1)) ( PARTITION p1 VALUES LESS THAN (2019), PARTITION p2 VALUES LESS THAN (2021) ...)

  • Does not support hotspot splitting.

  • Supported partition functions:

    • YEAR

    • MONTH

    • DAYOFMONTH

    • DAYOFWEEK

    • DAYOFYEAR

    • TO_DAYS

    • TO_MONTHS

    • TO_WEEKS

    • TO_SECONDS

    • UNIX_TIMESTAMP

    • SUBSTR/SUBSTRING

  1. Uses the YEAR partition function to calculate the year from the value in column c1.

  2. Uses a binary search on the calculated year to find the corresponding predefined partition, then routes to that partition.

Example 2-1: Range columns partitioning

Range columns partitioning supports a vector partition key but not a partition function. For example, to partition a table by order ID and order date, you can use the following CREATE TABLE syntax:

CREATE TABLE orders(
 order_id int,
 order_time datetime not null)
PARTITION BY RANGE COLUMNS(order_id,order_time)
(
  PARTITION p1 VALUES LESS THAN (10000,'2021-01-01'),
  PARTITION p2 VALUES LESS THAN (20000,'2021-01-01'),
  PARTITION p3 VALUES LESS THAN (30000,'2021-01-01'),
  PARTITION p4 VALUES LESS THAN (40000,'2021-01-01'),
  PARTITION p5 VALUES LESS THAN (50000,'2021-01-01'),
  PARTITION p6 VALUES LESS THAN (MAXVALUE,MAXVALUE)
);
Important

range columns partitioning does not support time zone-aware data types, such as TIMESTAMP and TIME, as a partition key.

Example 2-2: range partitioning

Range partitioning supports only a single-column partition key. However, for a datetime partition column, you can use partitioning functions such as YEAR, TO_DAYS, TO_SECONDS, or MONTH to convert its values to integers.

Important

Range partitioning does not directly support a string type as the partitioning column.

For example, to create quarterly partitions on the order_time column using range partitioning, use the following syntax:

CREATE TABLE orders_todays(
 id int,
 order_time datetime not null)
PARTITION BY RANGE(to_days(order_time))
(
  PARTITION p1 VALUES LESS THAN (to_days('2021-01-01')),
  PARTITION p2 VALUES LESS THAN (to_days('2021-04-01')),
  PARTITION p3 VALUES LESS THAN (to_days('2021-07-01')),
  PARTITION p4 VALUES LESS THAN (to_days('2021-10-01')),
  PARTITION p5 VALUES LESS THAN (to_days('2022-01-01')),
  PARTITION p6 VALUES LESS THAN (MAXVALUE)
);
Important

Range partitioning only supports a single, integer-type column as the partition key.

Limits

  • Data type restrictions

    • Integer types: BIGINT, BIGINT UNSIGNED, INT, INT UNSIGNED, MEDIUMINT, MEDIUMINT UNSIGNED, SMALLINT, SMALLINT UNSIGNED, TINYINT, and TINYINT UNSIGNED.

    • Datetime types: DATETIME and DATE.

    • String types: CHAR and VARCHAR.

  • Syntax restrictions

    • RANGE COLUMNS partitioning and RANGE partitioning do not support using a NULL value as a boundary value.

    • RANGE COLUMNS partitioning does not support the TIMESTAMP data type.

    • RANGE partitioning supports only integer types. If the partitioning key uses the TIMESTAMP type, you must use the UNIX_TIMESTAMP function to ensure time zone consistency.

    • RANGE partitioning does not support hot spot splitting.

    • During queries, NULL values are treated as the minimum value for partition routing.

    • By default, the maximum number of partitions is 8,192.

    • By default, the maximum number of partitioning columns is 5.

List type

Similar to the range type, PolarDB-X further subdivides the list partitioning policy into two types: list partitioning and list columns partitioning. Both types use the standard partitioning syntax of native MySQL. Additionally, PolarDB-X supports a default partition for both list partitioning and list columns partitioning. This table compares these two types:

Table 3. Comparison of the List Columns and List partitioning strategies

Partitioning strategy

Partition key support

Partitioning function support

Syntax example

Features and limitations

Routing (point query)

List Columns

single-column partition key and vector partition key

No

PARTITION BY LIST COLUMNS (c1,c2,...,cn) ( PARTITION p1 VALUES IN ((1,10,...,1000),(2,20,...,2000) ), PARTITION p2 VALUES IN ((3,30,...,3000),(3,30,...,3000) ), ...)

Hotspot splitting is not supported.

  1. Creates a partition key vector from the values of the N columns (c1,c2,...,cn).

  2. Uses a binary search algorithm on the partition key vector (c1,c2,...,cn) to find the predefined partition and route the query to the target partition.

List

single-column partition key

Yes

PARTITION BY LIST(YEAR(c1)) ( PARTITION p1 VALUES IN (2018,2019), PARTITION p2 VALUES IN (2020,2021) ...)

Hotspot splitting is not supported.

Example 3-1: List columns partitioning

list columns partitioning supports vector partition keys. For example, list columns partitioning lets you partition orders by country and city. The table creation syntax is as follows:

CREATE TABLE orders_region(
 id int,
 country varchar(64),
 city varchar(64),
 order_time datetime not null)
PARTITION BY LIST COLUMNS(country,city)
(
  PARTITION p1 VALUES IN (('China','Hangzhou'), ('China','Beijing')),
  PARTITION p2 VALUES IN (('United States','New York'),('United States','Chicago')),
  PARTITION p3 VALUES IN (('Russia','Moscow'))
);
Important

List Columns partitioning currently does not support data types with time zone information, such as TIMESTAMP and TIME, as a partition key.

Example 3-2: list partitioning

Although list partitioning supports only a single-column partition key, for a time-type partition column, you can use partition function expressions such as YEAR, MONTH, DAYOFMONTH, TO_DAYS, and TO_SECONDS to convert its values to an integer type.

For example, to create a list partition based on the year of the order_time column, use the following create table syntax:

CREATE TABLE orders_years(
 id int,
 country varchar(64),
 city varchar(64),
 order_time datetime not null)
PARTITION BY LIST(YEAR(order_time))
(
  PARTITION p1 VALUES IN (1990,1991,1992,1993,1994,1995,1996,1997,1998,1999),
  PARTITION p2 VALUES IN (2000,2001,2002,2003,2004,2005,2006,2007,2008,2009),
  PARTITION p3 VALUES IN (2010,2011,2012,2013,2014,2015,2016,2017,2018,2019)
);
Important

Partitioning only supports the integer type as the partition key. The string type is not supported as a partition column.

Example 3-3: List columns and list partitions with a default partition

PolarDB-X supports creating list columns partitions and list partitions that include a default partition, where data not defined in the regular partitions is routed.

Important

You can define at most one default partition, which must be the last partition.

CREATE TABLE orders_region(
 id int,
 country varchar(64),
 city varchar(64),
 order_time datetime not null)
PARTITION BY LIST COLUMNS(country,city)
(
  PARTITION p1 VALUES IN (('China','Hangzhou'), ('China','Beijing')),
  PARTITION p2 VALUES IN (('United States','New York'),('United States','Chicago')),
  PARTITION p3 VALUES IN (('Russia','Moscow')),
  PARTITION pd VALUES IN (DEFAULT)
);

CREATE TABLE orders_years(
 id int,
 country varchar(64),
 city varchar(64),
 order_time datetime not null)
PARTITION BY LIST(YEAR(order_time))
(
  PARTITION p1 VALUES IN (1990,1991,1992,1993,1994,1995,1996,1997,1998,1999),
  PARTITION p2 VALUES IN (2000,2001,2002,2003,2004,2005,2006,2007,2008,2009),
  PARTITION p3 VALUES IN (2010,2011,2012,2013,2014,2015,2016,2017,2018,2019),
  PARTITION pd VALUES IN (DEFAULT)
);

Limits

  • Data type restrictions

    • Integer types: BIGINT, BIGINT UNSIGNED, INT, INT UNSIGNED, MEDIUMINT, MEDIUMINT UNSIGNED, SMALLINT, SMALLINT UNSIGNED, TINYINT, and TINYINT UNSIGNED.

    • Time types: DATETIME and DATE.

    • String types: CHAR and VARCHAR.

  • Syntax restrictions

    • List Columns partitioning does not support the TIMESTAMP data type.

    • List partitioning supports only integer types.

    • Neither List Columns partitioning nor List partitioning supports hotspot splitting.

    • By default, the maximum number of partitions is 8,192.

    • By default, the maximum number of partition columns is 5.

CoHash type

The CoHash partitioning policy of PolarDB-X is a partitioning policy unique to PolarDB-X.

Version requirements

Use version 5.4.18-17047709 or later.

Use cases

This partitioning strategy is commonly used for the following business scenarios:

If a table has correlated columns, such as c1 and c2 whose last four characters are always identical, you can partition it horizontally on both columns to route SQL queries with an equality condition on either column to a single partition.

Therefore, this partitioning strategy requires that values remain consistent across multiple partition columns in the same partitioned table.

Example 4-1: Define co-location with independent partition functions

Suppose your application has an orders table where the order_id and buyer_id columns share the same last six digits in each row. To partition this table by these shared digits and ensure that an equality query on either column is routed to the same partition, use the following syntax:

CREATE TABLE t_orders(
 id bigint not null auto_increment, 
 order_id bigint, 
 buyer_id bigint,
 order_time datetime not null,
 primary key(id)
) 
PARTITION BY CO_HASH(
 	RIGHT(`order_id`,6) /* The last 6 characters of order_id */,
 	RIGHT(`buyer_id`,6) /* The last 6 characters of buyer_id */
) 
PARTITIONS 8;

Example 4-2: Using Range_Hash syntactic sugar for user migration from 1.0 to 2.0

For a migration from 1.0 to 2.0, consider an orders table sharded by database and table using range_hash, defined as follows: DBPARTIITION BY RANGE_HASH(`order_id`,`buyer_id`, 6) . Its corresponding partitioned table in the 2.0 AUTO database is defined as follows:

CREATE TABLE orders(
 id bigint not null auto_increment, 
 buyer_id bigint,
 order_id bigint,
 ...
 primary key(id)
) 
PARTITION BY RANGE_HASH(order_id, buyer_Id,6) 
PARTITIONS 8;

PolarDB-X automatically converts RANGE_HASH syntax to a CO_HASH partition definition. For example, RANGE_HASH(order_id, buyer_Id, 6) becomes the following CO_HASH definition:

CREATE TABLE orders(
 id bigint not null auto_increment, 
 buyer_id bigint,
 order_id bigint,
 ...
 primary key(id)
) 
PARTITION BY CO_HASH(
 	RIGHT(`order_id`,6) /* Uses the last 6 characters of order_id */,
 	RIGHT(`buyer_id`,6) /* Uses the last 6 characters of buyer_id */
) 
PARTITIONS 8;

Key differences from hash/key partitioning

Since the CoHash and hash/key partitioning strategies are similar, this section outlines their key similarities and differences in usage.

Key differences

CO_HASH

KEY

HASH

Syntax example

PARTITION BY

CO_HASH(c1, c2)

PARTITIONS 8

PARTITION BY

KEY(c1, c2)

PARTITIONS 8

PARTITION BY

HASH(c1, c2)

PARTITIONS 8

Single-column partition key

Not supported

Supported

Supported

Vector partition key

Supported

Supported

Supported

Using partition functions on vector partition columns

Supported. For example:

PARTITION BY

CO_HASH(

Extracts the last 4 characters of c1

RIGHT(c1, 4),

/ Extracts the last 4 characters of c2 /

RIGHT(c2, 4)

)

PARTITIONS 8

Not supported

Not supported

Relationship between partition columns

A co-location relationship. The application must provide and maintain this relationship between the partition column values. For example:

  • If the values of c1 and c2 are always identical, use CO_HASH(c1, c2).

  • If the last four characters of c1 and c2 are always identical, use CO_HASH(RIGHT(c1,4), RIGHT(c2,4)).

Similar to the prefix relationship of a composite index.

Similar to the prefix relationship of a composite index.

Partition pruning for prefix-column equality queries

Supported. For example:

  • c1='x': Supports partition pruning, routing the query to a single partition.

  • c1='x' and c2='y': Supports partition pruning. The query is routed to one partition if the values map to the same partition, or zero partitions if they map to different ones.

Supported. For example:

  • c1='x': Supports partition pruning, routing the query to one or more partitions. If the value x has undergone hot spot splitting, the query targets multiple partitions.

  • c1='x' and c2='y': Supports partition pruning, routing the query to a single partition.

Not supported. Partition pruning requires equality conditions on all partition columns. For example:

  • c1='x': Does not support partition pruning and results in a full partition scan.

  • c1='x' and c2='y': Supports partition pruning, routing the query to a single partition.

Partition pruning for non-prefix column equality queries

Supported. Equality conditions on any partition column can independently trigger partition pruning. For example:

  • c2='x': Supports partition pruning, routing the query to a single partition.

  • c1='x' or c2='y': Supports partition pruning. The system scans one partition if c1='x' and c2='y' route to the same partition; otherwise, it scans two.

Not supported. Equality conditions on non-prefix partition columns require a full partition scan. For example:

  • c2='x': Results in a full partition scan.

  • c1='x' or c2='y': Results in a full partition scan.

Not supported. Equality conditions on non-prefix partition columns require a full partition scan. For example:

  • c2='x': Results in a full partition scan.

  • c1='x' or c2='y': Results in a full partition scan.

Range queries

Not supported. Results in a full partition scan.

Not supported. Results in a full partition scan.

Not supported. Results in a full partition scan.

Routing description (point query)

  1. Extract the value, v1, from the equality condition on a partition column (e.g., c1).

  2. If a partition function applies to the column, calculate f1 = partFunc(v1); otherwise, f1 is v1.

  3. Calculate the hash value of f1 using the consistent hashing algorithm to get c1_hash, a long integer.

  4. Route the query to a partition based on the c1_hash value.

See the comparison of KEY and HASH partitioning in the rows above.

See the comparison of KEY and HASH partitioning in the rows above.

Hot spot splitting

Not supported. You cannot further split a partition based on a specific hot spot value, such as c1='88'.

Supported

Not supported

Partition management (e.g., partition splitting, merging, and migration)

Supported

Supported

Supported

Subpartitioning

Supported

Supported

Supported

Considerations

  • Your service must maintain the coordinated relationship between partition column values; PolarDB-X only validates routing results.When you use CO_HASH partitioning, PolarDB-X verifies that all specified partition column values for a row route to the same shard. However, it does not validate whether the values themselves adhere to the coordinated relationship. This enforcement is the responsibility of your service.

    For example, assume your service requires the last four characters of columns c1 and c2 to be identical. If a value for c1, such as 100234, and a value for c2, such as 1320, both route to shard 0, PolarDB-X permits the insert (c1,c2) values (100234,1320) operation because the routing is consistent. However, this operation violates the service rule, as the last four characters of c1 (0234) and c2 (1320) are not the same.

  • DML restrictions on modifying partition columns Because CO_HASH partitioning correlates the values of multiple partition columns, PolarDB-X enforces the following restrictions on DML operations that modify these columns to prevent incorrect data distribution:

    • For insert and replace statements, if the values for different partition columns in a single row of the VALUES clause resolve to different partitions, PolarDB-X rejects the operation.

    • For update and upsert statements, you must modify all partition columns simultaneously in the SET clause. For example, if c1 and c2 are partition columns, you must use a statement like UPDATE t1 SET c1='xx',c2='yy' WHERE id=1. If the new values for different partition columns in a single row resolve to different partitions, PolarDB-X rejects the statement.

    • When CO_HASH is the partitioning strategy for a global secondary index (GSI), PolarDB-X also rejects any DML operation on the primary table that causes the values for different partition columns in a single GSI row to resolve to different partitions.

  • Handling leading zeros for integer types. Because partition columns in a CO_HASH strategy are correlated, you often define them using a partition function such as SUBSTR, LEFT, or RIGHT. This process can result in leading zeros when integers are truncated. For example, suppose your business logic requires the last four characters of c1 and c2 to be identical. If c1 is 1000034, the last four characters are the string '0034'. For a partition column of an integer type, CO_HASH automatically casts any truncated value to that column's integer type before routing. As a result, CO_HASH casts the string '0034' to the integer 34, computes the hash value, and routes the row. This process automatically handles leading zeros.

Partition function limitations

  • RIGHT

  • LEFT

  • SUBSTR

Data type restrictions

  • integer types: BIGINT, BIGINT UNSIGNED, INT, INT UNSIGNED, MEDIUMINT, MEDIUMINT UNSIGNED, SMALLINT, SMALLINT UNSIGNED, TINYINT, and TINYINT UNSIGNED

  • fixed-point type: DECIMAL (with a scale of 0)

  • time types: Not supported

  • string types: CHAR and VARCHAR

Syntax restrictions

  • You cannot use nested partition functions, such as SUBSTR(SUBSTR(c1,-6),-4), on a partition column.

  • When using the RANGE_HASH syntax sugar, the length parameter must not be negative.

  • All partition columns must have the exact same data type, including the following properties:

    • Character set and collation

    • Length and precision

  • By default, the maximum number of partitions is 8,192.

  • By default, the maximum number of partition columns is 5.

Subpartition

Like MySQL, PolarDB-X supports subpartitioning syntax to create partitioned tables with subpartitions. Subpartitioning further divides each partition based on a specified partitioning column and partitioning strategy.

  • In a two-level partitioned table, each first-level partition is a logical partition that maps to a set of second-level partitions.

  • Each second-level partition is a physical partition that maps to a specific physical table shard on a DN node.

Templated and non-templated

PolarDB-X second-level partitions fall into two main categories: templated and non-templated:

  • templated subpartition: The number of subpartitions and their partition boundary values are the same for every partition.

  • non-templated subpartition: The number of subpartitions and their partition boundary values can be different for each partition.

Syntax restrictions

  • By default, a partitioned table that uses subpartitioning cannot have more than 8,192 physical partitions.

  • When you use non-templated partitions, all subpartition names must be unique and must not match any partition names.

  • When you use templated partitions, all subpartition names in the template must be unique and must not match any partition names.

  • With subpartitioning, the total number of physical partitions in a table is the total count of subpartitions across all partitions. This number can increase rapidly. Therefore, carefully manage the number of partitions and subpartitions to avoid performance degradation from over-partitioning or errors from exceeding the total partition limit.

Example 5-1: Templated secondary partition

/*
 * This example defines templated subpartitions by using a LIST-KEY composite strategy.
 * The table is first partitioned by LIST COLUMNS into three partitions.
 * Each partition is then subpartitioned by KEY into four subpartitions, resulting in a total of 12 physical partitions.
*/
CREATE TABLE sp_tbl_list_key_tp(
 id int, 
 country varchar(64),
 city varchar(64),
 order_time datetime not null,
 PRIMARY KEY(id)
)
PARTITION BY LIST COLUMNS(country,city) 
SUBPARTITION BY KEY(id) SUBPARTITIONS 4
(
  PARTITION p1 VALUES IN (('China','Hangzhou')),
  PARTITION p2 VALUES IN (('Russian','Moscow')),
  PARTITION pd VALUES IN (DEFAULT)
);

Example 5-2: Non-templated subpartition

/*
 * This example uses a LIST-KEY composite strategy to define non-templated subpartitions.
 * The table is partitioned by LIST COLUMNS into three first-level partitions, each of which is then subpartitioned by KEY.
 * The first-level partitions have 2, 3, and 4 subpartitions, respectively.
 * This results in a total of 9 physical partitions (2 + 3 + 4).
*/
CREATE TABLE sp_tbl_list_key_ntp(
 id int, 
 country varchar(64),
 city varchar(64),
 order_time datetime not null,
 PRIMARY KEY(id)
)
PARTITION BY LIST COLUMNS(country,city) 
SUBPARTITION BY KEY(id)
(
  PARTITION p1 VALUES IN (('China','Hangzhou')) SUBPARTITIONS 2,
  PARTITION p2 VALUES IN (('Russia','Moscow')) SUBPARTITIONS 3,
  PARTITION pd VALUES IN (DEFAULT) SUBPARTITIONS 4
);

Automatic partitioning

Note

By default, automatic partitioning is disabled for databases in AUTO mode. To enable this feature, run the following command:

SET GLOBAL AUTO_PARTITION=true;

With automatic partitioning enabled:

  • When you create a table without specifying a partitioning key, PolarDB-X partitions the table by default using its primary key. If the table has no primary key, it uses the implicit primary key instead. This process uses KEY partitioning, resulting in a level-1 partitioned table.

    By default, the number of partitions is eight times the number of logical nodes in the instance. For example, if a PolarDB-X instance is created with two logical nodes, the default number of partitions is 16.

  • In addition to partitioning the primary table, PolarDB-X also partitions all its indexes by default. The partitioning key for an index consists of the index columns and the table's primary key columns.

The following example shows the standard MySQL syntax for creating a table, where id is the primary key and name is the indexed column:

CREATE TABLE auto_part_tbl(
 id bigint not null auto_increment,
 bid int,
 name varchar(30),
 primary key(id),
 index idx_name (name)
);

Running the SHOW CREATE TABLE statement displays the standard MySQL table creation syntax and automatically hides all partition information:

show create table auto_part_tbl;
+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TABLE         | CREATE TABLE                                                                                                                                                                                                                     |
+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| auto_part_tbl | CREATE TABLE `auto_part_tbl` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `bid` int(11) DEFAULT NULL,
    `name` varchar(30) DEFAULT NULL,
    PRIMARY KEY (`id`),
    INDEX `idx_name` (`name`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8 |
+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.06 sec)

Running the SHOW FULL CREATE TABLE statement displays all partition information for the main table and its index tables:

show full create table auto_part_tbl;
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TABLE         | CREATE TABLE                                                                                                                                                                                                                                                                                                                                                                                                              |
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| auto_part_tbl | CREATE PARTITION TABLE `auto_part_tbl` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `bid` int(11) DEFAULT NULL,
    `name` varchar(30) DEFAULT NULL,
    PRIMARY KEY (`id`),
    GLOBAL INDEX /* idx_name_$a870 */ `idx_name` (`name`) PARTITION BY KEY (`name`, `id`) PARTITIONS 16,
    LOCAL KEY `_local_idx_name` (`name`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8
PARTITION BY KEY(`id`)
PARTITIONS 16
/* table group = `tg108` */ |
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.03 sec)

The output shows the following:

  • By default, the main table auto_part_tbl is partitioned by the id column using KEY partitioning into 16 partitions.

  • By default, the index idx_name on the main table is a global index that uses the name and id columns as its partitioning key and has 16 partitions.

Manual partitioning

You can create a manually partitioned table by specifying a partition column, partition function, and partition type in the CREATE TABLE statement. For more information about partition types, see Create a partitioned table manually (AUTO mode).

Data types

Table 4. Supported data types for partition key columns by partitioning type

Data type

Hash partitioning

Range partitioning

List partitioning

Hash

Key

Range

Range columns

List

List columns

Single partition key column

Multiple partition key columns

Integer type

TINYINT

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

TINYINT UNSIGNED

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

SMALLINT

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

SMALLINT UNSIGNED

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

MEDIUMINT

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

MEDIUMINT UNSIGNED

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

INT

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

INT UNSIGNED

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

BIGINT

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

BIGINT UNSIGNED

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

正确Supported

Fixed-point type

DECIMAL

正确Supported

(Partition functions not supported.)

正确Supported

正确Supported

错误Not supported

正确Supported (Scale must be 0 when used as a RANGE COLUMNS key.)

错误Not supported

正确Supported (Scale must be 0 when used as a LIST COLUMNS key.)

Date and time type

DATE

正确Supported

正确Supported

正确Supported

正确Supported (Requires a partition function.)

正确Supported

正确Supported (Requires a partition function.)

正确Supported

DATETIME

正确Supported

正确Supported

正确Supported

正确Supported (Requires a partition function.)

正确Supported

正确Supported (Requires a partition function.)

正确Supported

TIMESTAMP

正确Supported

正确Supported

正确Supported

错误Not supported

错误Not supported

错误Not supported

错误Not supported

String type

CHAR

正确Supported (Partition functions not supported.)

正确Supported

正确Supported

错误Not supported

正确Supported

错误Not supported

正确Supported

VARCHAR

正确Supported (Partition functions not supported.)

正确Supported

正确Supported

错误Not supported

正确Supported

错误Not supported

正确Supported

Binary type

BINARY

正确Supported (Partition functions not supported.)

正确Supported

正确Supported

错误Not supported

错误Not supported

错误Not supported

错误Not supported

VARBINARY

正确Supported (Partition functions not supported.)

正确Supported

正确Supported

错误Not supported

错误Not supported

错误Not supported

错误Not supported

Partition key data types and routing

A partitioned table's routing depends directly on the partition key's data type, especially for key and hash partitions. Different data types use different hashing algorithms or comparison logic (such as case sensitivity), which results in different routing behavior. (Note: Partition routing in MySQL is also strongly type-dependent.)

This example shows two tables, tbl_int and tbl_bigint, both with 1,024 partitions. The tbl_int table uses an int partition key, while tbl_bigint uses a bigint partition key. Although both are integer types, this difference causes the same query value (12345678) to be routed to different partitions:

show create table tbl_int;
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TABLE   | CREATE TABLE                                                                                                                                                                |
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tbl_int | CREATE TABLE `tbl_int` (
    `a` int(11) NOT NULL,
    KEY `auto_shard_key_a` USING BTREE (`a`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4
PARTITION BY KEY(`a`)
PARTITIONS 1024 |
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.02 sec)

show create table tbl_bigint;
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TABLE      | CREATE TABLE                                                                                                                                                                      |
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tbl_bigint | CREATE TABLE `tbl_bigint` (
    `a` bigint(20) NOT NULL,
    KEY `auto_shard_key_a` USING BTREE (`a`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4
PARTITION BY KEY(`a`)
PARTITIONS 1024 |
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.10 sec)mysql> create table if not exists tbl_bigint(a bigint not null)
    -> partition by key(a) partitions 1024;
Query OK, 0 rows affected (28.41 sec)

explain select * from tbl_int where a=12345678;
+---------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN                                                                             |
+---------------------------------------------------------------------------------------------------+
| LogicalView(tables="tbl_int[p260]", sql="SELECT `a` FROM `tbl_int` AS `tbl_int` WHERE (`a` = ?)") |
| HitCache:false                                                                                    |
| Source:PLAN_CACHE                                                                                 |
| TemplateId: c90af636                                                                              |
+---------------------------------------------------------------------------------------------------+
4 rows in set (0.45 sec)

explain select * from tbl_bigint where a=12345678;
+------------------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN                                                                                      |
+------------------------------------------------------------------------------------------------------------+
| LogicalView(tables="tbl_bigint[p477]", sql="SELECT `a` FROM `tbl_bigint` AS `tbl_bigint` WHERE (`a` = ?)") |
| HitCache:false                                                                                             |
| Source:PLAN_CACHE                                                                                          |
| TemplateId: 9b2fa47c                                                                                       |
+------------------------------------------------------------------------------------------------------------+
4 rows in set (0.02 sec)
            

Case sensitivity, character set, and collation

Note

The character set and collation of a partition key directly affect the routing algorithm of a partitioned table. For example, they determine whether routing is case-sensitive. If a table's collation is case-sensitive, hashing and comparison during routing are also case-sensitive. Conversely, if the collation is case-insensitive, these operations are also case-insensitive. By default, a string partition key uses the utf8 character set and the case-insensitive utf8_general_ci collation.

Example 1

To make partition key routing case-sensitive, set the table's collation to a case-sensitive one, such as utf8_bin, when you create the table. In the example below, the tbl_varchar_cs table uses CHARACTER SET utf8 COLLATE utf8_bin. As a result, it routes the strings 'AbcD' and 'abcd', which differ only in case, to different partitions:

show create table tbl_varchar_cs;
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TABLE          | CREATE TABLE                                                                                                                                                                                                          |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tbl_varchar_cs | CREATE TABLE `tbl_varchar_cs` (
    `a` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
    KEY `auto_shard_key_a` USING BTREE (`a`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8
PARTITION BY KEY(`a`)
PARTITIONS 64 |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.07 sec)

explain select a from tbl_varchar_cs where a in ('AbcD');
+-------------------------------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN                                                                                                   |
+-------------------------------------------------------------------------------------------------------------------------+
| LogicalView(tables="tbl_varchar_cs[p29]", sql="SELECT `a` FROM `tbl_varchar_cs` AS `tbl_varchar_cs` WHERE (`a` IN(?))") |
| HitCache:false                                                                                                          |
| Source:PLAN_CACHE                                                                                                       |
| TemplateId: 2c49c244                                                                                                    |
+-------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.11 sec)

explain select a from tbl_varchar_cs where a in ('abcd');
+-------------------------------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN                                                                                                   |
+-------------------------------------------------------------------------------------------------------------------------+
| LogicalView(tables="tbl_varchar_cs[p11]", sql="SELECT `a` FROM `tbl_varchar_cs` AS `tbl_varchar_cs` WHERE (`a` IN(?))") |
| HitCache:true                                                                                                           |
| Source:PLAN_CACHE                                                                                                       |
| TemplateId: 2c49c244                                                                                                    |
+-------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.02 sec)

Example 2

To make partition key routing case-insensitive, set the table's collation to a case-insensitive one, such as utf8_general_ci, when you create the table. In the example below, the tbl_varchar_ci table uses CHARACTER SET utf8 COLLATE utf8_general_ci. As a result, it routes the strings 'AbcD' and 'abcd' to the same partition:

show create table tbl_varchar_ci;
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TABLE          | CREATE TABLE                                                                                                                                                                      |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tbl_varchar_ci | CREATE TABLE `tbl_varchar_ci` (
    `a` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    KEY `auto_shard_key_a` USING BTREE (`a`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8
PARTITION BY KEY(`a`)
PARTITIONS 64 |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.06 sec)

explain select a from tbl_varchar_ci where a in ('AbcD');
+------------------------------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN                                                                                                  |
+------------------------------------------------------------------------------------------------------------------------+
| LogicalView(tables="tbl_varchar_ci[p4]", sql="SELECT `a` FROM `tbl_varchar_ci` AS `tbl_varchar_ci` WHERE (`a` IN(?))") |
| HitCache:false                                                                                                         |
| Source:PLAN_CACHE                                                                                                      |
| TemplateId: 5c97178e                                                                                                   |
+------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.15 sec)

explain select a from tbl_varchar_ci where a in ('abcd');
+------------------------------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN                                                                                                  |
+------------------------------------------------------------------------------------------------------------------------+
| LogicalView(tables="tbl_varchar_ci[p4]", sql="SELECT `a` FROM `tbl_varchar_ci` AS `tbl_varchar_ci` WHERE (`a` IN(?))") |
| HitCache:true                                                                                                          |
| Source:PLAN_CACHE                                                                                                      |
| TemplateId: 5c97178e                                                                                                   |
+------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.02 sec)

Changes to character set and collation

Because a partitioned table's routing algorithm is determined by its partition key's data type, modifying the character set or collation of the partition key triggers a redistribution of all data in the table. Therefore, be cautious when modifying the data type of a partition key.

Type truncation and conversion for partition columns

Type truncation for partition columns

If a constant expression in a query or an INSERT statement exceeds the valid range for the partition column's data type, PolarDB-X first truncates the value and then uses it for routing calculation.

For example, the tbl_smallint table has a partition column of type smallint, which has a valid range of -32768 to 32767. If you try to insert a value outside this range, such as 12345678 or -12345678, PolarDB-X first truncates the value to the maximum or minimum value of the smallint type (32767 or -32768, respectively). The following example demonstrates this process.

show create table tbl_smallint;
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TABLE        | CREATE TABLE                                                                                                                                                                        |
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tbl_smallint | CREATE TABLE `tbl_smallint` (
    `a` smallint(6) NOT NULL,
    KEY `auto_shard_key_a` USING BTREE (`a`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4
PARTITION BY KEY(`a`)
PARTITIONS 128 |
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.06 sec)
set sql_mode='';
Query OK, 0 rows affected (0.00 sec)

insert into tbl_smallint values (12345678),(-12345678);
Query OK, 2 rows affected (0.07 sec)

select * from tbl_smallint;
+--------+
| a      |
+--------+
| -32768 |
|  32767 |
+--------+
2 rows in set (3.51 sec)

explain select * from tbl_smallint where a=12345678;
+------------------------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN                                                                                            |
+------------------------------------------------------------------------------------------------------------------+
| LogicalView(tables="tbl_smallint[p117]", sql="SELECT `a` FROM `tbl_smallint` AS `tbl_smallint` WHERE (`a` = ?)") |
| HitCache:false                                                                                                   |
| Source:PLAN_CACHE                                                                                                |
| TemplateId: afb464d5                                                                                             |
+------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.16 sec)

explain select * from tbl_smallint where a=32767;
+------------------------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN                                                                                            |
+------------------------------------------------------------------------------------------------------------------+
| LogicalView(tables="tbl_smallint[p117]", sql="SELECT `a` FROM `tbl_smallint` AS `tbl_smallint` WHERE (`a` = ?)") |
| HitCache:true                                                                                                    |
| Source:PLAN_CACHE                                                                                                |
| TemplateId: afb464d5                                                                                             |
+------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.03 sec)

Similarly, if a constant value in a query exceeds the type's range, PolarDB-X also truncates it before routing. Therefore, for the tbl_smallint table, PolarDB-X routes queries for a=12345678 and a=32767 to the same partition.

Type conversion for partition columns

If a constant expression in a query or INSERT statement has a different data type than the partition column, PolarDB-X performs implicit type conversion on the constant expression and then uses the converted value for routing calculation. However, type conversion can fail. For example, the string abc cannot be converted to an integer.

When type conversion for a partition column occurs or fails, PolarDB-X behaves differently depending on whether the statement is a DQL, DML, or DDL statement:

  • DQL (specifically for type conversion involving a partition column in a WHERE clause)

    • Successful conversion: PolarDB-X uses the converted value for partition routing.

    • Failed conversion: PolarDB-X ignores the condition on the partition column, resulting in a full table scan.

  • DML (specifically for INSERT or REPLACE statements)

    • Successful conversion: PolarDB-X uses the converted value for partition routing.

    • Failed conversion: PolarDB-X rejects the statement and returns an error.

  • DDL (specifically for DDL statements related to partitioned tables, such as CREATE TABLE and SPLIT PARTITION)

    • Successful conversion: PolarDB-X rejects the statement and returns an error. DDL statements do not allow implicit type conversion.

    • Failed conversion: PolarDB-X rejects the statement and returns an error.

Syntax differences from MySQL partitioned tables

Difference

MySQL

PolarDB-X

Primary key inclusion in the partitioning key

Required.

Not required.

Key partitioning

Routing algorithm: Modulo operation on the number of partitions.

Routing algorithm: Consistent hashing algorithm.

Hash partitioning

  1. Routing algorithm: Modulo operation on the number of partitions.

  2. Does not support multiple partitioning columns.

  3. Supports linear hash partitioning.

  4. For a single-column partitioning key, HASH(col) and KEY(col) use different routing algorithms.

  1. Routing algorithm: Consistent hashing algorithm.

  2. Supports multiple partitioning columns (extended syntax).

  3. Does not support linear hash partitioning.

  4. For a single-column partitioning key, HASH(col) and KEY(col) use the same routing algorithm.

Partitioning function

Supported. For PARTITION BY HASH(expr(col)), the expr can be any valid arithmetic expression, such as YEAR(col) + 1.

Supported with limitations. For PARTITION BY HASH(expr(col)), expr is restricted to the following functions, and the expression cannot include arithmetic operators such as +, -, *, or /:

  • YEAR

  • MONTH

  • DAYOFMONTH

  • DAYOFWEEK

  • DAYOFYEAR

  • TO_DAYS

  • TO_MONTHS

  • TO_WEEKS

  • TO_SECONDS

  • UNIX_TIMESTAMP

  • SUBSTR/SUBSTRING

Partitioning column data types

Key partitioning supports all data types.

Key partitioning only supports integer, date and time, and string data types.

Partitioning column character set

Supports all common character sets.

Supports only the following character sets:

  • utf8

  • utf8mb4

  • gbk

Subpartitioning

Supported.

Supported.