skip to Main Content

This is my table

Column A Column B Column C Column D
Cell 1 Cell 2 Cell 1 Cell 2
Cell 3 Cell 4 Cell 3 Cell 4

Where Column A is the primary key and Column D is a TINYINT column. Column D contains values from 0 to 3 only. (0,1,2,3)
I want to partition this table based on column D.

I tried this code to partition the table.

ALTER TABLE to_be_partitioned PARTITION BY HASH(Column D) PARTITIONS 4;

It says A PRIMARY KEY must include all columns in the table’s partitioning function

How can I partition this table based on Column D values please???

I tried using KEY partition type and it also gives an error.

I’m expecting something like this.

P0 contains all records with column D value of 0

P1 contains all records with column D value of 1

P2 contains all records with column D value of 2

P3 contains all records with column D value of 3

3

Answers


    1. As Akina suggested, partitioning by LIST makes for sense for this case.
    2. A PRIMARY KEY must include all columns in the table’s partitioning function. Your primary key needs to be either (Column A, Column D) or (Column D, Column A), or you’ll get SQL Error [1503] [HY000].
    create table to_be_partitioned (
        col_a   int,
        col_b   int,
        col_c   int,
        col_d   int,
        primary key (col_a, col_d))
    partition by list (col_d) (
        partition p0 values in (0),
        partition p1 values in (1),
        partition p2 values in (2),
        partition p3 values in (3)
    );
    

    or

    create table to_be_partitioned (
        col_a   int,
        col_b   int,
        col_c   int,
        col_d   int,
        primary key (col_d, col_a))
    partition by list (col_d) (
        partition p0 values in (0),
        partition p1 values in (1),
        partition p2 values in (2),
        partition p3 values in (3)
    );
    

    EDIT:

    1. If col_a is an auto_increment column, col_a alone is already unique. Thus (col_a, col_d) is also unique.
    2. If the purpose of partitioning is to evenly distribute data. The DDL below may works for you:
    -- answer per comment
    create table to_be_partitioned (
        col_a   int auto_increment,
        col_b   int,
        col_c   int,
        col_d   int,
        primary key (col_a, col_d))
    partition by list (col_d) (
        partition p0 values in (0),
        partition p1 values in (1),
        partition p2 values in (2),
        partition p3 values in (3)
    );
    
    insert into to_be_partitioned (col_b, col_c, col_d) values (1, 1, last_insert_id() mod 4);
    insert into to_be_partitioned (col_b, col_c, col_d) values (2, 1, last_insert_id() mod 4);
    insert into to_be_partitioned (col_b, col_c, col_d) values (3, 1, last_insert_id() mod 4);
    insert into to_be_partitioned (col_b, col_c, col_d) values (4, 1, last_insert_id() mod 4);
    insert into to_be_partitioned (col_b, col_c, col_d) values (5, 1, last_insert_id() mod 4);
    insert into to_be_partitioned (col_b, col_c, col_d) values (6, 1, last_insert_id() mod 4);
    insert into to_be_partitioned (col_b, col_c, col_d) values (7, 1, last_insert_id() mod 4);
    
    select * from to_be_partitioned order by col_a;
    
    col_a|col_b|col_c|col_d|
    -----+-----+-----+-----+
        1|    1|    1|    1|
        2|    2|    1|    1|
        3|    3|    1|    2|
        4|    4|    1|    3|
        5|    5|    1|    0|
        6|    6|    1|    1|
        7|    7|    1|    2|
    
    -- from a partition p2
    select * from to_be_partitioned partition(p2);
    
    col_a|col_b|col_c|col_d|
    -----+-----+-----+-----+
        3|    3|    1|    2|
        7|    7|    1|    2|
    
    Login or Signup to reply.
  1. DEMO

    Partitioning with PK provided by additional table and a trigger.

    The table which must be partitioned – no PK.

    CREATE TABLE main (
      colA INT NOT NULL,  -- should be AI PK
      colB INT,
      colC TINYINT CHECK (colC BETWEEN 0 AND 3)
    )
      PARTITION BY LIST (colC) (
      PARTITION zero VALUES IN (0),
      PARTITION one VALUES IN (1),
      PARTITION two VALUES IN (2),
      PARTITION three VALUES IN (3)
    );
    

    Additional table which will be used for AI PK generation.

    CREATE TABLE main_ai_pk (
      colA INT AUTO_INCREMENT PRIMARY KEY
    );
    

    Trigger which will generate AI PK. If explicit value for colA is provided then it will be overrided.

    CREATE TRIGGER tr_bi_main_set_pk
    BEFORE INSERT ON main
    FOR EACH ROW
    BEGIN
      INSERT INTO main_ai_pk VALUES (DEFAULT);        -- generate new AI value
      SET NEW.colA = LAST_INSERT_ID();                -- assign it to "PK" in main table
      DELETE FROM main_ai_pk WHERE colA < NEW.colA;   -- clear excess rows
    END
    

    Some inserts. In 2nd INSERT the value for colA which is provided explicitly is overrided.

    INSERT INTO main (colB, colC) VALUES (11,1), (22,2), (111,1);
    INSERT INTO main VALUES (NULL,33,3), (3333,333,3);
    

    Look at final data state.

    SELECT * FROM main ORDER BY colA;
    SELECT * FROM main_ai_pk;
    SELECT PARTITION_NAME, TABLE_ROWS
      FROM INFORMATION_SCHEMA.PARTITIONS
      WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'main'
      ORDER BY PARTITION_ORDINAL_POSITION;
    
    colA colB colC
    1 11 1
    2 22 2
    3 111 1
    4 33 3
    5 333 3
    colA
    5
    PARTITION_NAME TABLE_ROWS
    zero 0
    one 2
    two 1
    three 2

    fiddle

    Login or Signup to reply.
  2. The other Answers explain how to do Partitioning. I will explain why you don’t need Partitioning.

    Let’s see the SELECT that would benefit. It sounds like it has

    WHERE colc = ...
      AND cola = ...
    

    In that case, a non-partitioned table with

    INDEX(colc, cola)
    

    is likely to be as fast or faster than any flavor of PARTITION BY ...(colc).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search