arrow-left

All pages
gitbookPowered by GitBook
1 of 16

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Partitioning Tables

Optimize large tables in MariaDB Server with partitioning. Learn how to divide tables into smaller, manageable parts for improved performance, easier maintenance, and scalability.

Partitioning Overviewchevron-right

Complete Partitioning Overview guide for MariaDB. Complete reference documentation for implementation, configuration, and usage for production use.

Partition Pruning and Selectionchevron-right

Understand how the optimizer automatically prunes irrelevant partitions and how to explicitly select partitions in your queries for efficiency.

Discover administrative tasks for managing partitions, such as adding, dropping, reorganizing, and coalescing them to keep your data optimized.

An introduction to the various partitioning strategies available in MariaDB, helping you choose the right method for your data distribution needs. For a complete list of partitioning types, .

This page outlines constraints when using partitioning, such as the maximum number of partitions and restrictions on foreign keys and query cache usage.

Learn how MariaDB stores partitioned tables on the filesystem, typically creating separate .ibd files for each partition when using InnoDB.

Understand how to retrieve metadata about partitions using the INFORMATION_SCHEMA.PARTITIONS table to monitor row counts and storage usage.

Partition Pruning and Selection

Understand how the optimizer automatically prunes irrelevant partitions and how to explicitly select partitions in your queries for efficiency.

When a WHERE clause is related to the partitioning expression, the optimizer knows which partitions are relevant for the query. Other partitions will not be read. This optimization is called partition pruning.

EXPLAIN PARTITIONS can be used to know which partitions are read for a given query. A column called partitions will contain a comma-separated list of the accessed partitions. For example:

EXPLAIN PARTITIONS SELECT * FROM orders WHERE id < 15000000;
+------+-------------+--------+------------+-------+---------------+---------+---------+------+------+-------------+
| id   | select_type | table  | partitions | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+------+-------------+--------+------------+-------+---------------+---------+---------+------+------+-------------+
|    1 | SIMPLE      | orders | p0,p1      | range | PRIMARY       | PRIMARY | 4       | NULL |    2 | Using where |
+------+-------------+--------+------------+-------+---------------+---------+---------+------+------+-------------+

Sometimes the WHERE clause does not contain the necessary information to use partition pruning, or the optimizer cannot infer this information. However, we may know which partitions are relevant for the query. We can force MariaDB to only access the specified partitions by adding a PARTITION clause. This feature is called partition selection. For example:

SELECT * FROM orders PARTITION (p3) WHERE user_id = 50;
SELECT * FROM orders PARTITION (p2,p3) WHERE user_id >= 40;

The PARTITION clause is supported for all DML statements:

hashtag
Partition Pruning and Triggers

In general, partition pruning is applied to statements contained in .

However, note that if a BEFORE INSERT or BEFORE UPDATE trigger is defined on a table, MariaDB doesn't know in advance if the columns used in the partitioning expression are changed. For this reason, it is forced to lock all partitions.

This page is licensed: CC BY-SA / Gnu FDL

Partitioning Types Overview

An introduction to the various partitioning strategies available in MariaDB, helping you choose the right method for your data distribution needs.

A partitioning type determines how a partitioned table's rows are distributed across partitions. Some partition types require the user to specify a partitioning expression that determines in which partition a row are stored.

The size of individual partitions depends on the partitioning type. Read and write performance are affected by the partitioning expression. Therefore, these choices should be made carefully.

hashtag
Partitioning Types

MariaDB supports the following partitioning types:

hashtag
See Also

This page is licensed: CC BY-SA / Gnu FDL

LINEAR HASH Partitioning Type

Explore LINEAR HASH partitioning, a variation of HASH that uses a powers-of-two algorithm for faster partition management at the cost of distribution.

hashtag
Syntax

PARTITION BY LINEAR HASH (partitioning_expression)
[PARTITIONS(number_of_partitions)]

hashtag
Description

LINEAR HASH partitioning is a form of , similar to , in which the server takes care of the partition in which to place the data, ensuring a relatively even distribution among the partitions.

LINEAR HASH partitioning makes use of a powers-of-two algorithm, while HASH partitioning uses the modulus of the hashing function's value. Adding, dropping, merging and splitting partitions is much faster than with the , however, data is less likely to be evenly distributed over the partitions.

hashtag
Example

This page is licensed: CC BY-SA / Gnu FDL

Partitioning Limitations

This page outlines constraints when using partitioning, such as the maximum number of partitions and restrictions on foreign keys and query cache usage.

The following limitations apply to partitioning in MariaDB:

  • Each table can contain a maximum of 8192 partitions.

  • Queries are never parallelized, even when they involve multiple partitions.

  • A table can only be partitioned if the storage engine supports partitioning.

  • All partitions must use the same storage engine. For a workaround, see .

  • A partitioned table cannot contain, or be referenced by, .

  • The is not aware of partitioning and partition pruning. Modifying a partition will invalidate the entries related to the whole table.

  • Updates can run more slowly when and a partitioned table is updated than an equivalent update of a non-partitioned table.

  • All columns used in the partitioning expression for a partitioned table must be part of every unique key that the table may have.

  • In versions prior to , it is not possible to create partitions on tables that contain .

hashtag
See Also

  • contains information about existing partitions.

  • for suggestions on using partitions

This page is licensed: CC BY-SA / Gnu FDL

Partitions Files

Learn how MariaDB stores partitioned tables on the filesystem, typically creating separate .ibd files for each partition when using InnoDB.

A partitioned table is stored in multiple files. By default, these files are stored in the MariaDB (or InnoDB) data directory. It is possible to keep them in different paths by specifying DATA_DIRECTORY and INDEX_DIRECTORY table options. This is useful to store different partitions on different devices.

Note that, if the innodb_file_per_table server system variable is set to 0 at the time of the table creation, all partitions are stored in the system tablespace.

The following files exist for each partitioned tables:

File name
Notes

For example, an InnoDB table with 4 partitions will have the following files:

If we convert the table to MyISAM, we will have these files:

This page is licensed: CC BY-SA / Gnu FDL

Partitions Metadata

Understand how to retrieve metadata about partitions using the INFORMATION_SCHEMA.PARTITIONS table to monitor row counts and storage usage.

The PARTITIONS table in the INFORMATION_SCHEMA database contains information about partitions.

The SHOW TABLE STATUS statement contains a Create_options column, that contains the string 'partitioned' for partitioned tables.

The SHOW CREATE TABLE statement returns the CREATE TABLE statement that can be used to re-create a table, including the partitions definition.

This page is licensed: CC BY-SA / Gnu FDL

Partition Maintenance

Learn to maintain MariaDB partitions using ALTER TABLE. Includes syntax for optimizing and repairing partitions, plus best practices for managing time-series data and performance.

hashtag
Maintenance Instructions

You can perform several maintenance tasks on partitioned tables using standard SQL statements or specific ALTER TABLE extensions.

KEY Partitioning Type

Understand KEY partitioning, similar to HASH but using MariaDB's internal hashing function on one or more columns to distribute data.

hashtag
Syntax

  • MYSQL51 and MYSQL55 are existing algorithms, with MYSQL55

LIST Partitioning Type

Understand LIST partitioning, where rows are assigned to partitions based on whether a column value matches one in a defined list of values.

LIST partitioning is conceptually similar to . In both cases you decide a partitioning expression (a column, or a slightly more complex calculation) and use it to determine which partitions will contain each row. However, with the RANGE type, partitioning is done by assigning a range of values to each partition. With the LIST type, we assign a set of values to each partition. This is usually preferred if the partitioning expression can return a limited set of values.

A variant of this partitioning method, , allows us to use multiple columns and more datatypes.

RANGE COLUMNS and LIST COLUMNS Partitioning Types

Discover these variants that allow partitioning based on multiple columns and non-integer types, offering greater flexibility than standard RANGE/LIST.

RANGE COLUMNS and LIST COLUMNS are variants of, respectively, and . With these partitioning types, there is not a single partitioning expression; instead, a list of one or more columns is accepted. The following rules apply:

  • The list can contain one or more columns.

  • Columns can be of any

RANGE Partitioning Type

The RANGE partitioning type assigns rows to partitions based on whether column values fall within contiguous, non-overlapping ranges.

The RANGE partitioning type is used to assign each partition a range of values generated by the partitioning expression. Ranges must be ordered, contiguous and non-overlapping. The minimum value is always included in the first range. The highest value may or may not be included in the last range.

A variant of this partitioning method, , allows us to use multiple columns and more datatypes.

hashtag
Syntax

The last part of a

Partition Maintenancechevron-right
Partitioning Types Overviewchevron-right
see this page
Partitioning Limitationschevron-right
Partitions Fileschevron-right
Partitions Metadatachevron-right
spinner

REPLACE

SELECT
INSERT
UPDATE
DELETE
triggers
spinner
RANGE
LIST
RANGE COLUMNS and LIST COLUMNS
HASH
LINEAR HASH
KEY
LINEAR KEY
SYSTEM_TIME
Partitioning Overview
spinner
CREATE OR REPLACE TABLE t1 (c1 INT, c2 DATETIME) 
  PARTITION BY LINEAR HASH(TO_DAYS(c2)) 
  PARTITIONS 5;
partitioning
HASH partitioning
HASH partitioning type
spinner

table_name.frm

Contains the table definition. Non-partitioned tables have this file, too.

table_name.par

Contains the partitions definitions.

table_name#P#partition_name.ext

Normal files created by the storage engine use this pattern for names. The extension depends on the storage engine.

orders.frm
orders.par
orders#P#p0.ibd
orders#P#p1.ibd
orders#P#p2.ibd
orders#P#p3.ibd
spinner
being the default, also used by default before 12.3
  • CRC32C, XXH32, and XXH3 use the established hash algorithms of the same names. These are recommended algorithms to use.

  • BASE31 uses a base-31 representation of the bytes and serves as a simple baseline that is more evenly distributed than MYSQL51 or MYSQL55 for simple sequential data.

  • PARTITION BY KEY ([column_names])
    [PARTITIONS (number_of_partitions)]

    hashtag
    Description

    Partitioning by key is a type of partitioning that is similar to and can be used in a similar way as partitioning by hash.

    KEY takes an optional list of column_names, and the hashing function is given by the server.

    Compared to HASH partitioning, KEY partitioning distributes data using a preset hash algorithms on the specified columns, rather than an expression specified by the user.

    If no column_names are specified, the table's primary key is used if present, or not null unique key if no primary key is present. If neither of these keys are present, not specifying any column_names will result in an error:

    Unlike other partitioning types, columns used for partitioning by KEY are not limited to integer or NULL values.

    KEY partitions do not support column index prefixes. Any columns in the partitioning key that make use of column prefixes are not used.

    hashtag
    Examples

    The unique key must be NOT NULL:

    KEY requires column_values if no primary key or not null unique key is present:

    Primary key columns with index prefixes are silently ignored, so the following two queries are equivalent:

    a(5) and c(5) are silently ignored in the former.

    If all columns use index prefixes, the statement fails with a slightly misleading error:

    This page is licensed: CC BY-SA / Gnu FDL

    PARTITION BY KEY
    [ALGORITHM={MYSQL51|MYSQL55|BASE31|CRC32C|XXH32|XXH3}]
    ([column_names])
    [PARTITIONS (number_of_partitions)]
    spinner
    hashtag
    Syntax

    The last part of a CREATE TABLE statement can be the definition of the new table's partitions. In the case of LIST partitioning, the syntax is as follows:

    PARTITION BY LIST indicates that the partitioning type is LIST.

    The partitioning_expression is an SQL expression that returns a value from each row. In the simplest cases, it is a column name. This value is used to determine which partition should contain a row.

    partition_name is the name of a partition.

    value_list is a list of values. If partitioning_expression returns one of these values, the row are stored in this partition. If we try to insert something that does not belong to any of these value lists, the row are rejected with an error.

    The DEFAULT partition catches all records which do not fit into other partitions.

    hashtag
    Use Cases

    LIST partitioning can be useful when we have a column that can only contain a limited set of values. Even in that case, RANGE partitioning could be used instead; but LIST partitioning allows us to equally distribute the rows by assigning a proper set of values to each partition.

    hashtag
    Example

    This page is licensed: CC BY-SA / Gnu FDL

    RANGE partitioning
    LIST COLUMNS
    spinner
    ,
    ,
    , and
    types.
  • Only bare columns are permitted; no expressions.

  • All the specified columns are compared to the specified values to determine which partition should contain a specific row. See below for details.

    hashtag
    Syntax

    The last part of a CREATE TABLE statement can be definition of the new table's partitions. In the case of RANGE COLUMNS partitioning, the syntax is as follows:

    The syntax for LIST COLUMNS is as follows:

    partition_name is the name of a partition.

    hashtag
    Comparisons

    To determine which partition should contain a row, all specified columns are compared to each partition definition.

    With LIST COLUMNS, a row matches a partition if all row values are identical to the specified values. At most one partition can match the row.

    With RANGE COLUMNS, a row matches a partition if it is less than the specified value tuple in lexicographic order. The first partition that matches the row values are used.

    The DEFAULT partition catches all records which do not fit in other partitions. Only one DEFAULT partition is allowed.

    hashtag
    Examples

    RANGE COLUMNS partition:

    LIST COLUMNS partition:

    This page is licensed: CC BY-SA / Gnu FDL

    RANGE
    LIST
    integer
    string
    DATE
    DATETIME
    spinner
    orders.frm
    orders.par
    orders#P#p0.MYD
    orders#P#p0.MYI
    orders#P#p1.MYD
    orders#P#p1.MYI
    orders#P#p2.MYD
    orders#P#p2.MYI
    orders#P#p3.MYD
    orders#P#p3.MYI
     ERROR 1488 (HY000): Field in list of fields for partition function not found in table
    CREATE OR REPLACE TABLE t1 (v1 INT)
      PARTITION BY KEY (v1)
      PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (v1 INT, v2 INT)
      PARTITION BY KEY (v1,v2)
      PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (
        id INT NOT NULL PRIMARY KEY,
        name VARCHAR(5)
    )
    PARTITION BY KEY()
    PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (
        id INT NOT NULL UNIQUE KEY,
        name VARCHAR(5)
    )
    PARTITION BY KEY()
    PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (
        id INT NULL UNIQUE KEY,
        name VARCHAR(5)
    )
    PARTITION BY KEY()
    PARTITIONS 2;
    ERROR 1488 (HY000): Field in list of fields for partition function not found in table
    CREATE OR REPLACE TABLE t1 (
        id INT NULL UNIQUE KEY,
        name VARCHAR(5)
    )
    PARTITION BY KEY()
    PARTITIONS 2;
    ERROR 1488 (HY000): Field in list of fields for partition function not found in table
    CREATE OR REPLACE TABLE t1 (
        id INT NULL UNIQUE KEY,
        name VARCHAR(5)
    )
    PARTITION BY KEY(name)
    PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (
        a VARCHAR(10),
        b VARCHAR(10),
        c VARCHAR(10),
        PRIMARY KEY (a(5), b, c(5))
    ) PARTITION BY KEY() PARTITIONS 2;
    
    CREATE OR REPLACE TABLE t1 (
        a VARCHAR(10),
        b VARCHAR(10),
        c VARCHAR(10),
        PRIMARY KEY (b)
    ) PARTITION BY KEY() PARTITIONS 2;
    CREATE OR REPLACE TABLE t1 (
        a VARCHAR(10),
        b VARCHAR(10),
        c VARCHAR(10),
        PRIMARY KEY (a(5), b(5), c(5))
    ) PARTITION BY KEY() PARTITIONS 2;
    ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function
    PARTITION BY LIST (partitioning_expression)
    (
    	PARTITION partition_name VALUES IN (value_list),
    	[ PARTITION partition_name VALUES IN (value_list), ... ]
            [ PARTITION partition_name DEFAULT ]
    )
    CREATE OR REPLACE TABLE t1 (
      num TINYINT(1) NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY LIST (num) (
        PARTITION p0 VALUES IN (0,1),
        PARTITION p1 VALUES IN (2,3),
        PARTITION p2 DEFAULT
      );
    PARTITION BY RANGE COLUMNS (col1, col2, ...)
    (
    	PARTITION partition_name VALUES LESS THAN (value1, value2, ...),
    	[ PARTITION partition_name VALUES LESS THAN (value1, value2, ...), ... ]
    )
    PARTITION BY LIST COLUMNS (partitioning_expression)
    (
    	PARTITION partition_name VALUES IN (value1, value2, ...),
    	[ PARTITION partition_name VALUES IN (value1, value2, ...), ... ]
            [ PARTITION partititon_name DEFAULT ]
    )
    CREATE OR REPLACE TABLE t1 (
      date1 DATE NOT NULL,
      date2 DATE NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE COLUMNS (date1,date2) (
        PARTITION p0 VALUES LESS THAN ('2013-01-01', '1994-12-01'),
        PARTITION p1 VALUES LESS THAN ('2014-01-01', '1995-12-01'),
        PARTITION p2 VALUES LESS THAN ('2015-01-01', '1996-12-01')
    );
    CREATE OR REPLACE TABLE t1 (
      num TINYINT(1) NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY LIST COLUMNS (num) (
        PARTITION p0 VALUES IN (0,1),
        PARTITION p1 VALUES IN (2,3),
        PARTITION p2 DEFAULT
      );
    hashtag
    Table-Level Maintenance

    For general maintenance, MariaDB supports the following statements on partitioned tables just as it does for non-partitioned tables:

    • CHECK TABLE

    • OPTIMIZE TABLE

    • ANALYZE TABLE

    • REPAIR TABLE

    hashtag
    Partition-Specific Operations

    To target one or more specific partitions rather than the entire table, use the ALTER TABLE extensions listed below. In the SQL syntaxes below, partition_names is a comma-separated list of partitions, like p0, p1, p2.

    circle-info

    For an operation to be performed on all partitions, you can use the ALL keyword instead of specifying all the partitions in a comma-separated list. Example:

    ALTER TABLE table_name REBUILD PARTITION ALL

    hashtag
    Rebuilding Partitions

    Use this to defragment a partition. This operation drops all records in the partition and re-inserts them:

    hashtag
    Optimizing Partitions

    If you have deleted many rows or modified variable-length columns (such as VARCHAR, BLOB, or TEXT), use this statement to reclaim unused space and defragment the data file:

    circle-info

    Some storage engines, including InnoDB, do not support per-partition optimization. When you run OPTIMIZE PARTITION on an InnoDB table, MariaDB rebuilds and analyzes the entire table instead.

    hashtag
    Analyzing Partitions

    Use this to read and store the key distributions for specific partitions:

    hashtag
    Repairing Partitions

    Use this to fix corrupted partitions:

    hashtag
    Checking Partitions

    You can verify the integrity of data and indexes within a partition:

    hashtag
    Truncating Partitions

    To remove all rows from specific partitions while keeping the table structure, use the TRUNCATE PARTITION clause:

    hashtag
    Reorganizing Partitions

    Reorganizing partitions isn't just maintenance, but it can help with making future maintenance easier. Use the following statement to change the structure of existing partitions without losing data. This is particularly useful for splitting a partition that contains a MAXVALUE range into a new specific range and a new MAXVALUE partition. Use the following syntax:

    Example: If you have a partition p_future defined as VALUES LESS THAN MAXVALUE, you can split it to add a specific range for the year 2026:

    hashtag
    Best Practices and Considerations

    When managing partitioned tables, follow these guidelines to ensure optimal performance and maintainability.

    hashtag
    Managing Time-Series Data

    Partitioning is most effective for tables containing time-series data where you periodically remove old records.

    • Efficient Deletion: Use DROP PARTITION instead of DELETE to remove expired data. This is a metadata operation and is significantly faster than row-by-row deletion.

    • The Future Partition: When using RANGE partitioning, define a "future" partition using VALUES LESS THAN MAXVALUE. To add a new specific range, use REORGANIZE PARTITION to split the "future" partition into a new range and a new MAXVALUE partition. See for the syntax.

    • The Start Partition: Consider creating a small, empty "start" partition (for example, VALUES LESS THAN (0)) to catch NULL values or invalid data. Because the partition pruner often scans the first partition by default, keeping it empty improves query efficiency.

    hashtag
    Performance and Scale

    • Table Size: Partitioning generally provides noticeable benefits only for tables with more than one million rows.

    • Partition Limits: Aim to keep the number of partitions below 50. While MariaDB supports up to 8192 partitions, high partition counts can increase the time required for the server to open the table or perform status checks.

    • Index Efficiency: Partitioning is not a substitute for proper indexing. Point queries (finding a single row) are often just as fast with a proper index on a non-partitioned table.

    This page is licensed: CC BY-SA / Gnu FDL

    ALTER TABLE table_name REBUILD PARTITION partition_names
    ALTER TABLE table_name OPTIMIZE PARTITION partition_names
    ALTER TABLE table_name ANALYZE PARTITION partition_names
    ALTER TABLE table_name REPAIR PARTITION partition_names
    ALTER TABLE table_name CHECK PARTITION partition_names
    ALTER TABLE table_name TRUNCATE PARTITION partition_names
    ALTER TABLE table_name REORGANIZE PARTITION partition_names INTO (PARTITION partition_definition, ...)
    ALTER TABLE tbl REORGANIZE PARTITION p_future INTO (PARTITION p_2026 VALUES LESS THAN (2027), PARTITION p_future VALUES LESS THAN MAXVALUE)
    spinner
    statement can be definition of the new table's partitions. In the case of RANGE partitioning, the syntax is the following:

    PARTITION BY RANGE indicates that the partitioning type is RANGE.

    • partitioning_expression is an SQL expression that returns a value from each row. In the simplest cases, it is a column name. This value is used to determine which partition should contain a row.

    • partition_name is the name of a partition.

    • value indicates the upper bound for that partition. The values must be ascending. For the first partition, the lower limit is NULL. When trying to insert a row, if its value is higher than the upper limit of the last partition, the row are rejected (with an error, if the keyword is not used).

    As a catchall, MAXVALUE can be specified as a value for the last partition. Note, however, that in order to append a new partition, it is not possible to use ADD PARTITION; instead, REORGANIZE PARTITION must be used.

    hashtag
    Use Cases

    A typical use case is when we want to partition a table whose rows refer to a moment or period in time; for example commercial transactions, blog posts, or events of some kind. We can partition the table by year, to keep all recent data in one partition and distribute historical data in big partitions that are stored on slower disks. Or, if our queries always read rows which refer to the same month or week, we can partition the table by month or year week (in this case, historical data and recent data are stored together).

    AUTO_INCREMENT values also represent a chronological order. So, these values can be used to store old data in separate partitions. However, partitioning by id is not the best choice if we usually query a table by date.

    hashtag
    Examples

    Partitioning a log table by year:

    Partitioning the table by both year and month:

    In the last example, the UNIX_TIMESTAMP function is used to accomplish the purpose. Also, the first two partitions cover longer periods of time (probably because the logged activities were less intensive).

    In both cases, when our tables become huge and we don't need to store all historical data any more, we can drop the oldest partitions in this way:

    We will still be able to drop a partition that does not contain the oldest data, but all rows stored in it will disappear.

    Example of an error when inserting outside a defined partition range:

    To avoid the error, use the IGNORE keyword:

    An alternative definition with MAXVALUE as a catchall:

    This page is licensed: CC BY-SA / Gnu FDL

    RANGE COLUMNS
    PARTITION BY RANGE (partitioning_expression)
    (
    	PARTITION partition_name VALUES LESS THAN (value),
    	[ PARTITION partition_name VALUES LESS THAN (value), ... ]
    	[ PARTITION partition_name VALUES LESS THAN MAXVALUE ]
    )
    CREATE TABLE log
    (
    	id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    	dt DATETIME NOT NULL,
    	user INT UNSIGNED,
    	PRIMARY KEY (id, dt)
    )
    	ENGINE = InnoDB
    PARTITION BY RANGE (YEAR(dt))
    (
    	PARTITION p0 VALUES LESS THAN (2013),
    	PARTITION p1 VALUES LESS THAN (2014),
    	PARTITION p2 VALUES LESS THAN (2015),
    	PARTITION p3 VALUES LESS THAN (2016)
    );
    CREATE TABLE log2
    (
    	id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    	ts TIMESTAMP NOT NULL,
    	user INT UNSIGNED,
    	PRIMARY KEY (id, ts)
    )
    	ENGINE = InnoDB
    PARTITION BY RANGE (UNIX_TIMESTAMP(ts))
    (
    	PARTITION p0 VALUES LESS THAN (UNIX_TIMESTAMP('2014-08-01 00:00:00')),
    	PARTITION p1 VALUES LESS THAN (UNIX_TIMESTAMP('2014-11-01 00:00:00')),
    	PARTITION p2 VALUES LESS THAN (UNIX_TIMESTAMP('2015-01-01 00:00:00')),
    	PARTITION p3 VALUES LESS THAN (UNIX_TIMESTAMP('2015-02-01 00:00:00'))
    );
    ALTER TABLE log DROP PARTITION p0;
    INSERT INTO log(id,dt) VALUES 
      (1, '2016-01-01 01:01:01'), 
      (2, '2015-01-01 01:01:01');
    ERROR 1526 (HY000): Table has no partition for value 2016
    INSERT IGNORE INTO log(id,dt) VALUES 
      (1, '2016-01-01 01:01:01'), 
      (2, '2015-01-01 01:01:01');
    
    SELECT * FROM log;
    +----+---------------------+------+
    | id | timestamp           | user |
    +----+---------------------+------+
    |  2 | 2015-01-01 01:01:01 | NULL |
    +----+---------------------+------+
    CREATE TABLE log
    (
    	id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    	dt DATETIME NOT NULL,
    	user INT UNSIGNED,
    	PRIMARY KEY (id, dt)
    )
    	ENGINE = InnoDB
    PARTITION BY RANGE (YEAR(dt))
    (
    	PARTITION p0 VALUES LESS THAN (2013),
    	PARTITION p1 VALUES LESS THAN (2014),
    	PARTITION p2 VALUES LESS THAN (2015),
    	PARTITION p3 VALUES LESS THAN (2016),
    	PARTITION p4 VALUES LESS THAN MAXVALUE
    );
    CREATE TABLE
    spinner
    Using CONNECT - Partitioning and Sharding
    foreign keys
    query cache
    binlog_format=ROW
    GEOMETRY types
    INFORMATION_SCHEMA.PARTITIONS
    Partition Maintenance
    spinner

    Partitioning Overview

    Complete Partitioning Overview guide for MariaDB. Complete reference documentation for implementation, configuration, and usage for production use.

    In MariaDB, a table can be split in smaller subsets. Both data and indexes are partitioned.

    hashtag
    Uses for Partitioning

    There can be several reasons to use this feature:

    • If you often need to delete a large set of rows, such as all rows for a given year, using partitions can help, as dropping a partition with many rows is very fast, while deleting a lot of rows can be very slow.

    • Very large tables and indexes can be slow even with optimized queries. But if the target table is partitioned, queries that read a small number of partitions can be much faster. However, this means that the queries have to be written carefully in order to only access a given set of partitions.

    • Partitioning allows one to distribute files over multiple storage devices. For example, we can have historical data on slower, larger disks (historical data are not supposed to be frequently read); and current data can be on faster disks, or SSD devices.

    • In case we separate historical data from recent data, we will probably need to take regular backups of one partition, not the whole table.

    hashtag
    Partitioning Types

    When partitioning a table, the use should decide:

    • a partitioning type;

    • a partitioning expression.

    A partitioning type is the method used by MariaDB to decide how rows are distributed over existing partitions. Choosing the proper partitioning type is important to distribute rows over partitions in an efficient way.

    With some partitioning types, a partitioning expression is also required. A partitioning function is an SQL expression returning an integer or temporal value, used to determine which partition will contain a given row. The partitioning expression is used for all reads and writes on involving the partitioned table, thus it should be fast.

    MariaDB supports the following partitioning types:

    hashtag
    Enabling Partitioning

    By default, MariaDB permits partitioning. You can determine this by using the statement, for example:

    If partition is listed as DISABLED:

    MariaDB has either been built without partitioning support, or has been started with the option, or one of its variants:

    and you will not be able to create partitions.

    hashtag
    Using Partitions

    It is possible to create a new partitioned table using .

    allows one to:

    • Partition an existing table;

    • Remove partitions from a partitioned table (with all data in the partition);

    • Add/remove partitions, or reorganize them, as long as the partitioning function allows these operations (see below);

    hashtag
    Adding Partitions

    can be used to add partitions to an existing table:

    With partitions, it is only possible to add a partition to the high end of the range, not the low end. For example, the following results in an error:

    You can work around this by using REORGANIZE PARTITION to split the partition instead. See .

    hashtag
    Coalescing Partitions

    is used to reduce the number of HASH or KEY partitions by the specified number. For example, given the following table with 5 partitions:

    The following statement reduces the number of partitions by 2, leaving the table with 3 partitions:

    hashtag
    Converting Partitions to/from Tables

    circle-info

    This feature is available from MariaDB 10.7.

    can be used to convert partitions in an existing table to a standalone table:

    CONVERT TABLE does the reverse, converting a table into a partition:

    hashtag
    CONVERT TABLE ... WITH / WITHOUT VALIDATION

    circle-info

    This feature is available from MariaDB 11.4.

    When converting tables to a partition, validation is performed on each row to ensure it meets the partition requirements. This can be very slow in the case of larger tables. It is possible to disable this validation by specifying the WITHOUT VALIDATION option.

    WITH VALIDATION will result in the validation being performed, and is the default behaviour.

    An alternative to convert partitions to tables is to use . This requires having to manually do the following steps:

    1. Create an empty table with the same structure as the partition.

    2. Exchange the table with the partition.

    3. Drop the empty partition.

    For example:

    Similarly, to do the reverse and convert a table into a partition [ALTER TABLE](../../reference/sql-statements-and-structure/sql-statements/data-definition/alter/alter-table.md) ... EXCHANGE PARTITION can also be used, with the following manual steps required:

    • create the partition

    • exchange the partition with the table

    • drop the old table:

    For example:

    hashtag
    Dropping Partitions

    can be used to drop specific partitions (and discard all data within the specified partitions) for and partitions. It cannot be used on or partitions. To rather remove all partitioning, while leaving the data unaffected, see .

    hashtag
    Exchanging Partitions

    ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t2 allows to exchange a partition or subpartition with another table.

    The following requirements must be met:

    • Table t1 must be partitioned, and table t2 cannot be partitioned.

    • Table t2 cannot be a temporary table.

    • Table t1 and t2 must otherwise be identical.

    • Any existing row in t2 must match the conditions for storage in the exchanged partition p1 unless, from

    By default, MariaDB performs the validation to see that each row meets the partition requirements, and the statement fails if a row does not fit.

    This attempted exchange fails, as the value is already in t2, and 2015-05-05 is outside of the partition conditions:

    hashtag
    WITH / WITHOUT VALIDATION

    circle-info

    This feature is available from MariaDB 11.4.

    This validation is performed for each row, and can be very slow in the case of larger tables. It is possible to disable this validation by specifying the WITHOUT VALIDATION option:

    WITH VALIDATION results in the validation being performed, and is the default behavior.

    hashtag
    Removing Partitioning

    removes all partitioning from the table, while leaving the data unaffected. To rather drop a particular partition (and discard all of its data), see .

    hashtag
    Reorganizing Partitions

    Reorganizing partitions allows one to adjust existing partitions, without losing data. Specifically, the statement can be used for:

    • Splitting an existing partition into multiple partitions.

    • Merging a number of existing partitions into a new, single, partition.

    • Changing the ranges for a subset of existing partitions defined using VALUES LESS THAN.

    hashtag
    Splitting Partitions

    An existing partition can be split into multiple partitions. This can also be used to add a new partition at the low end of a partition (which is not possible by ).

    Similarly, if MAXVALUE binds the high end:

    hashtag
    Merging Partitions

    A number of existing partitions can be merged into a new partition, for example:

    hashtag
    Changing Ranges

    hashtag
    Renaming Partitions

    The statement can also be used for renaming partitions. Note that this creates a copy of the partition:

    hashtag
    Truncating Partitions

    [ALTER TABLE](../../reference/sql-statements-and-structure/sql-statements/data-definition/alter/alter-table.md) ... TRUNCATE PARTITION

    removes all data from the specified partition/s, leaving the table and partition structure unchanged. Partitions don't need to be contiguous:

    hashtag
    Analyzing Partitions

    Similar to , key distributions for specific partitions can also be analyzed and stored, for example:

    hashtag
    Checking Partitions

    Similar to , specific partitions can be checked for errors, for example:

    The ALL keyword can be used in place of the list of partition names, and the check operation are performed on all partitions.

    hashtag
    Repairing Partitions

    Similar to , specific partitions can be repaired:

    As with , the QUICK and EXTENDED options are available. However, the USE_FRM option cannot be used with this statement on a partitioned table.

    REPAIR PARTITION fails if there are duplicate key errors. ALTER IGNORE TABLE ... REPAIR PARTITION can be used in this case.

    The ALL keyword can be used in place of the list of partition names, and the repair operation are performed on all partitions.

    hashtag
    Optimizing Partitions

    Similar to , specific partitions can be checked for errors:

    OPTIMIZE PARTITION does not support per-partition optimization on InnoDB tables, and will issue a warning and cause the entire table to rebuilt and analyzed. ALTER TABLE ... REBUILD PARTITION and ALTER TABLE ... ANALYZE PARTITION can be used instead.

    The ALL keyword can be used in place of the list of partition names, and the optimize operation are performed on all partitions.

    hashtag
    Partitioning for Specific Storage Engines

    Some MariaDB allow more interesting uses for partitioning.

    The storage engine allows one to:

    • Treat a set of identical defined tables as one.

    • A MyISAM table can be in many different MERGE sets and also used separately.

    allows one to:

    • Move partitions of the same table on different servers. In this way, the workload can be distributed on more physical or virtual machines (data sharding).

    • All partitions of a SPIDER table can also live on the same machine. In this case there are a small overhead (SPIDER uses connections to localhost), but queries that read multiple partitions will use parallel threads.

    allows one to:

    • Build a table whose partitions are tables using different storage engines (like InnoDB, MyISAM, or even engines that do not support partitioning).

    • Build an indexable, writeable table on several data files. These files can be in different formats.

    See also:

    hashtag
    See Also

    • contains information about existing partitions.

    • for suggestions on using partitions

    This page is licensed: CC BY-SA / Gnu FDL

    this section
    IGNORE

  • Exchange a partition with a table;
  • Perform administrative operations on some or all partitions (analyze, optimize, check, repair).

  • , the WITHOUT VALIDATION option is specified.
    Changing the value lists for a subset of partitions defined using VALUES I.
  • Renaming partitions.

  • SHOW PLUGINS;
    ...
    | Aria                          | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
    | FEEDBACK                      | DISABLED | INFORMATION SCHEMA | NULL    | GPL     |
    | partition                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
    +-------------------------------+----------+--------------------+---------+---------+
    | partition                     | DISABLED | STORAGE ENGINE     | NULL    | GPL     |
    +-------------------------------+----------+--------------------+---------+---------+
    --skip-partition
    --disable-partition
    --partition=OFF
    ADD PARTITION [IF NOT EXISTS] (partition_definition)
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    ALTER TABLE t1 ADD PARTITION (
      PARTITION p4 VALUES LESS THAN (2017), 
      PARTITION p5 VALUES LESS THAN (2018)
    );
    ALTER TABLE t1 ADD PARTITION (
      PARTITION p0a VALUES LESS THAN (2012)
    );
    ERROR 1493 (HY000): VALUES LESS THAN value must be strictly increasing for each partition
    COALESCE PARTITION number
    CREATE OR REPLACE TABLE t1 (v1 INT)
      PARTITION BY KEY (v1)
      PARTITIONS 5;
    ALTER TABLE t1 COALESCE PARTITION 2;
    CONVERT PARTITION partition_name TO TABLE tbl_name
    CONVERT TABLE normal_table TO partition_definition
    CREATE OR REPLACE TABLE t1 (
       dt DATETIME NOT NULL
     )
       ENGINE = InnoDB
       PARTITION BY RANGE (YEAR(dt))
       (
       PARTITION p0 VALUES LESS THAN (2013),
       PARTITION p1 VALUES LESS THAN (2014),
       PARTITION p2 VALUES LESS THAN (2015),
       PARTITION p3 VALUES LESS THAN (2016)
     );
    
    INSERT INTO t1 VALUES ('2013-11-11'),('2014-11-11'),('2015-11-11');
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    | 2015-11-11 00:00:00 |
    +---------------------+
    
    ALTER TABLE t1 CONVERT PARTITION p3 TO TABLE t2;
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    +---------------------+
    
    SELECT * FROM t2;
    +--------------+
    | dt           |
    +--------------+
    | 2015-11-11 00:00:00 |
    +---------------------+
    
    SHOW CREATE TABLE t1\G
    *************************** 1. row ***************************
           TABLE: t1
    CREATE TABLE: CREATE TABLE `t1` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
     PARTITION BY RANGE (year(`dt`))
    (PARTITION `p0` VALUES LESS THAN (2013) ENGINE = InnoDB,
     PARTITION `p1` VALUES LESS THAN (2014) ENGINE = InnoDB,
     PARTITION `p2` VALUES LESS THAN (2015) ENGINE = InnoDB)
    
    SHOW CREATE TABLE t2\G
    *************************** 1. row ***************************
           TABLE: t2
    CREATE TABLE: CREATE TABLE `t2` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
    ALTER TABLE t1 CONVERT TABLE t2 TO PARTITION p3 VALUES LESS THAN (2016);
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    | 2015-11-11 00:00:00 |
    +---------------------+
    3 rows in set (0.001 sec)
    
    SELECT * FROM t2;
    ERROR 1146 (42S02): Table 'test.t2' doesn't exist
    
    SHOW CREATE TABLE t1\G
    *************************** 1. row ***************************
           TABLE: t1
    CREATE TABLE: CREATE TABLE `t1` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
     PARTITION BY RANGE (year(`dt`))
    (PARTITION `p0` VALUES LESS THAN (2013) ENGINE = InnoDB,
     PARTITION `p1` VALUES LESS THAN (2014) ENGINE = InnoDB,
     PARTITION `p2` VALUES LESS THAN (2015) ENGINE = InnoDB,
     PARTITION `p3` VALUES LESS THAN (2016) ENGINE = InnoDB)
    CONVERT TABLE normal_table TO partition_definition [{WITH | WITHOUT} VALIDATION]
    CREATE OR REPLACE TABLE t1 (
       dt DATETIME NOT NULL
     )
       ENGINE = InnoDB
       PARTITION BY RANGE (YEAR(dt))
       (
       PARTITION p0 VALUES LESS THAN (2013),
       PARTITION p1 VALUES LESS THAN (2014),
       PARTITION p2 VALUES LESS THAN (2015),
       PARTITION p3 VALUES LESS THAN (2016)
     );
    
    INSERT INTO t1 VALUES ('2013-11-11'),('2014-11-11'),('2015-11-11');
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    | 2015-11-11 00:00:00 |
    +---------------------+
    
    CREATE OR REPLACE TABLE t2 LIKE t1;
    
    ALTER TABLE t2 REMOVE PARTITIONING;
    
    ALTER TABLE t1 EXCHANGE PARTITION p3 WITH TABLE t2;
    
    ALTER TABLE t1 DROP PARTITION p3;
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    +---------------------+
    
    SELECT * FROM t2;
    +--------------+
    | dt           |
    +--------------+
    | 2015-11-11 00:00:00 |
    +---------------------+
    
    SHOW CREATE TABLE t1\G
    *************************** 1. row ***************************
           TABLE: t1
    CREATE TABLE: CREATE TABLE `t1` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
     PARTITION BY RANGE (year(`dt`))
    (PARTITION `p0` VALUES LESS THAN (2013) ENGINE = InnoDB,
     PARTITION `p1` VALUES LESS THAN (2014) ENGINE = InnoDB,
     PARTITION `p2` VALUES LESS THAN (2015) ENGINE = InnoDB)
    
    SHOW CREATE TABLE t2\G
    *************************** 1. row ***************************
           TABLE: t2
    CREATE TABLE: CREATE TABLE `t2` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
    ALTER TABLE t1 ADD PARTITION (PARTITION p3 VALUES LESS THAN (2016));
    
    ALTER TABLE t1 EXCHANGE PARTITION p3 WITH TABLE t2;
    
    DROP TABLE t2;
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-11 00:00:00 |
    | 2014-11-11 00:00:00 |
    | 2015-11-11 00:00:00 |
    +---------------------+
    
    SHOW CREATE TABLE t1\G
    *************************** 1. row ***************************
           TABLE: t1
    CREATE TABLE: CREATE TABLE `t1` (
      `dt` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
     PARTITION BY RANGE (year(`dt`))
    (PARTITION `p0` VALUES LESS THAN (2013) ENGINE = InnoDB,
     PARTITION `p1` VALUES LESS THAN (2014) ENGINE = InnoDB,
     PARTITION `p2` VALUES LESS THAN (2015) ENGINE = InnoDB,
     PARTITION `p3` VALUES LESS THAN (2016) ENGINE = InnoDB)
    DROP PARTITION [IF EXISTS] partition_names
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    INSERT INTO t1 VALUES ('2012-11-15');
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2012-11-15 00:00:00 |
    +---------------------+
    
    ALTER TABLE t1 DROP PARTITION p0;
    
    SELECT * FROM t1;
    Empty set (0.002 sec)
    EXCHANGE PARTITION partition_name WITH TABLE tbl_name [{WITH | WITHOUT} VALIDATION]
    EXCHANGE PARTITION partition_name WITH TABLE tbl_name
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014)
    );
    
    CREATE OR REPLACE TABLE t2 (
      dt DATETIME NOT NULL
    ) ENGINE = InnoDB;
    
    INSERT INTO t1 VALUES ('2012-01-01'),('2013-01-01');
    
    INSERT INTO t2 VALUES ('2013-02-02');
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2012-01-01 00:00:00 |
    | 2013-01-01 00:00:00 |
    +---------------------+
    
    SELECT * FROM t2;
    +--------------+
    | dt           |
    +--------------+
    | 2013-02-02 00:00:00 |
    +---------------------+
    
    ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t2;
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2012-01-01 00:00:00 |
    | 2013-02-02 00:00:00 |
    +---------------------+
    
    SELECT * FROM t2;
    +--------------+
    | dt           |
    +--------------+
    | 2013-01-01 00:00:00 |
    +---------------------+
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014)
    );
    
    CREATE OR REPLACE TABLE t2 (
      dt DATETIME NOT NULL
    ) ENGINE = InnoDB;
    
    INSERT INTO t1 VALUES ('2012-02-02'),('2013-03-03');
    
    INSERT INTO t2 VALUES ('2015-05-05');
    
    ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t2;
    ERROR 1526 (HY000): Table has no partition for value 0
    ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t2 WITHOUT VALIDATION;
    Query OK, 0 rows affected (0.048 sec)
    REMOVE PARTITIONING
    ALTER TABLE t1 REMOVE PARTITIONING;
    REORGANIZE PARTITION [partition_names INTO (partition_definitions)]
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    ALTER TABLE t1 REORGANIZE PARTITION p0 INTO (
        PARTITION p0a VALUES LESS THAN (2012),
        PARTITION p0b VALUES LESS THAN (2013)
    );
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016),
      PARTITION p4 VALUES LESS THAN MAXVALUE
    );
    
    ALTER TABLE t1 REORGANIZE PARTITION p4 INTO (
        PARTITION p4 VALUES LESS THAN (2017),
        PARTITION p5 VALUES LESS THAN MAXVALUE
    );
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    ALTER TABLE t1 REORGANIZE PARTITION p2,p3 INTO (
        PARTITION p2 VALUES LESS THAN (2016)
    );
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    ALTER TABLE t1 REORGANIZE PARTITION p3 INTO (
      PARTITION p3 VALUES LESS THAN (2017)
    );
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    ALTER TABLE t1 REORGANIZE PARTITION p3 INTO (
      PARTITION p3_new VALUES LESS THAN (2016)
    );
    TRUNCATE PARTITION partition_names
    CREATE OR REPLACE TABLE t1 (
      dt DATETIME NOT NULL
    )
      ENGINE = InnoDB
      PARTITION BY RANGE (YEAR(dt))
      (
      PARTITION p0 VALUES LESS THAN (2013),
      PARTITION p1 VALUES LESS THAN (2014),
      PARTITION p2 VALUES LESS THAN (2015),
      PARTITION p3 VALUES LESS THAN (2016)
    );
    
    INSERT INTO t1 VALUES ('2012-11-01'),('2013-11-02'),('2014-11-03'),('2015-11-04');
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2012-11-01 00:00:00 |
    | 2013-11-02 00:00:00 |
    | 2014-11-03 00:00:00 |
    | 2015-11-04 00:00:00 |
    +---------------------+
    
    ALTER TABLE t1 TRUNCATE PARTITION p0,p2;
    
    SELECT * FROM t1;
    +--------------+
    | dt           |
    +--------------+
    | 2013-11-02 00:00:00 |
    | 2015-11-04 00:00:00 |
    +---------------------+
    ALTER TABLE t1 ANALYZE PARTITION p0,p1,p3;
    +---------+---------+----------+----------+
    | Table   | Op      | Msg_type | Msg_text |
    +---------+---------+----------+----------+
    | test.t1 | analyze | status   | OK       |
    +---------+---------+----------+----------+
    CHECK PARTITION {ALL | PARTITION [,partition2 ...]}
    ALTER TABLE t1 CHECK PARTITION p1,p3;
    +---------+-------+----------+----------+
    | Table   | Op    | Msg_type | Msg_text |
    +---------+-------+----------+----------+
    | test.t1 | check | status   | OK       |
    +---------+-------+----------+----------+
    REPAIR PARTITION {ALL | partition [,partition2 ...]} [QUICK] [EXTENDED]
    ALTER TABLE t1 REPAIR PARTITION p0,p3;
    +---------+--------+----------+----------+
    | Table   | Op     | Msg_type | Msg_text |
    +---------+--------+----------+----------+
    | test.t1 | repair | status   | OK       |
    +---------+--------+----------+----------+
    OPTIMIZE PARTITION {ALL | PARTITION [,partition2 ...]}
    ALTER TABLE t1 OPTIMIZE PARTITION p0,p3;
    +---------+----------+----------+----------+
    | Table   | Op       | Msg_type | Msg_text |
    +---------+----------+----------+----------+
    | test.t1 | optimize | status   | OK       |
    +---------+----------+----------+----------+
    RANGE
    LIST
    RANGE COLUMNS and LIST COLUMNS
    HASH
    SHOW PLUGINS
    --skip-partition
    CREATE TABLE
    ALTER TABLE
    ADD PARTITION
    RANGE
    Splitting Partitions
    ALTER TABLE
    ALTER TABLE
    ALTER TABLE EXCHANGE PARTITION
    ALTER TABLE DROP PARTITION
    RANGE
    LIST
    HASH
    KEY
    Removing Partitioning
    ALTER TABLE REMOVE PARTITIONING
    Dropping Partitions
    RANGE
    Adding Partitions
    ALTER TABLE REORGANIZE PARTITION
    ALTER TABLE TRUNCATE PARTITION
    ANALYZE TABLE
    CHECK TABLE
    REPAIR TABLE
    REPAIR TABLE
    OPTIMIZE TABLE
    storage engines
    MERGE
    MyISAM
    SPIDER
    CONNECT
    Using CONNECT - Partitioning and Sharding
    ALTER TABLE
    INFORMATION_SCHEMA.PARTITIONS
    Partition Maintenance
    spinner

    Partitioning Types

    Explore different partitioning types for MariaDB Server tables. Understand range, list, hash, and key partitioning to optimize data management and improve query performance.

    LINEAR HASH
    KEY
    LINEAR KEY
    SYSTEM_TIME

    HASH Partitioning Type

    Learn about HASH partitioning, which distributes data based on a user-defined expression to ensure an even spread of rows across partitions.

    hashtag
    Syntax

    PARTITION BY HASH (partitioning_expression)
    [PARTITIONS(number_of_partitions)]

    hashtag
    Description

    HASH partitioning is a form of in which the server takes care of the partition in which to place the data, ensuring an even distribution among the partitions.

    It requires a column value, or an expression based on a column value, which is hashed, as well as the number of partitions into which to divide the table.

    • partitioning_expression needs to return a non-constant, deterministic integer. It is evaluated for each insert and update, so overly complex expressions can lead to performance issues. A hashing function operating on a single column, and where the value changes consistently with the column value, allows for easy pruning on ranges of partitions, and is usually a better choice. For this reason, using multiple columns in a hashing expression is not usually recommended.

    • number_of_partitions is a positive integer specifying the number of partitions into which to divide the table. If the PARTITIONS clause is omitted, the default number of partitions is one.

    hashtag
    Determining the Partition

    To determine which partition to use, perform the following calculation:

    For example, if the expression is TO_DAYS(datetime_column) and the number of partitions is 5, inserting a datetime value of '2023-11-15' would determine the partition as follows:

    • TO_DAYS('2023-11-15') gives a value of 739204.

    • MOD(739204,5) returns 4, so the 4th partition is used.

    HASH partitioning makes use of the modulus of the hashing function's value. The is similar, using a powers-of-two algorithm. Data is more likely to be evenly distributed over the partitions than with the LINEAR HASH partitioning type; however, adding, dropping, merging and splitting partitions is much slower.

    hashtag
    Examples

    Using the for more information:

    hashtag
    See Also

    • for suggestions on using partitions

    This page is licensed: CC BY-SA / Gnu FDL

    partitioning
    LINEAR HASH partitioning type
    Information Schema PARTITIONS Table
    Partition Maintenance
    spinner
    MOD(partitioning_expression, number_of_partitions)
    CREATE OR REPLACE TABLE t1 (c1 INT, c2 DATETIME) 
      PARTITION BY HASH(TO_DAYS(c2)) 
      PARTITIONS 5;
    INSERT INTO t1 VALUES (1,'2023-11-15');
    
    SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS 
      WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
    +----------------+------------+
    | PARTITION_NAME | TABLE_ROWS |
    +----------------+------------+
    | p0             |          0 |
    | p1             |          0 |
    | p2             |          0 |
    | p3             |          0 |
    | p4             |          1 |
    +----------------+------------+

    LINEAR KEY Partitioning Type

    Learn about LINEAR KEY partitioning, which combines the internal key hashing with a linear algorithm for efficient partition handling.

    hashtag
    Syntax

    PARTITION BY LINEAR KEY [ALGORITHM={MYSQL51|MYSQL55|BASE31|CRC32C|XXH32|XXH3}]
    ([column_names])
    [PARTITIONS (number_of_partitions)]

    For a description of the different ALGORITHM types, see KEY Partitioning.

    PARTITION BY LINEAR KEY ([column_names])
    [PARTITIONS (number_of_partitions)]

    hashtag
    Description

    LINEAR KEY partitioning is a form of , similar to .

    LINEAR KEY partitioning makes use of a powers-of-two algorithm, while KEY partitioning uses modulo arithmetic to determine the partition number.

    Adding, dropping, merging and splitting partitions is much faster than with the ; however, data is less likely to be evenly distributed over the partitions.

    hashtag
    Example

    This page is licensed: CC BY-SA / Gnu FDL

    partitioning
    KEY partitioning
    KEY partitioning type
    spinner
    CREATE OR REPLACE TABLE t1 (v1 INT)
      PARTITION BY LINEAR KEY (v1)
      PARTITIONS 2;
    MariaDB 11.3.2
    MariaDB 11.4