All Products
Search
Document Center

PolarDB:Create and use a CCI

Last Updated:Mar 30, 2026

This topic explains how to create and use the clustered columnar index (CCI) feature in PolarDB-X to accelerate analytical queries on your data.

Prerequisites

Before you begin, make sure your instance meets the following requirements:

  • Edition: Enterprise Edition with an AUTO mode database

  • Version: 5.4.19-16989811 or later

For version naming rules, see Release notes. To check your current version, see View and update the version of an instance.

Usage notes

  • Prefix indexes cannot be used on a CCI.

  • You must specify an index name when creating a CCI.

  • A CCI includes all columns of the primary table by default and is automatically updated when columns are added or dropped. You cannot manually change which columns are included.

  • Creating a CCI does not create any additional local indexes.

  • The LENGTH parameter of the sort key is ignored in the index definition.

  • Primary instances, read-only instances, and columnstore read-only instances all support SHOW INDEX and related query commands. See SHOW COLUMNAR INDEX, SHOW COLUMNAR OFFSET, and SHOW COLUMNAR STATUS.

  • Only columnstore read-only instances support CCI-based query execution.

Syntax

PolarDB-X extends MySQL Data Definition Language (DDL) syntax. Use the following syntax to create a CCI the same way you create a regular index in MySQL:

CREATE
    CLUSTERED COLUMNAR INDEX index_name
    ON tbl_name (index_sort_key_name,...)
    [partition_options]

-- Define a partitioning policy
partition_options:
    PARTITION BY
          HASH({column_name | partition_func(column_name)})
        | KEY(column_list)
        | RANGE({column_name | partition_func(column_name)})
        | RANGE COLUMNS(column_list)
        | LIST({column_name | partition_func(column_name)})
        | LIST COLUMNS(column_list)
    partition_list_spec

-- Define a partitioning function
partition_func:
    YEAR
  | TO_DAYS
  | TO_SECOND
  | UNIX_TIMESTAMP
  | MONTH

-- Define a partition list
partition_list_spec:
    hash_partition_list
  | range_partition_list
  | list_partition_list

-- For HASH/KEY partitioned tables
hash_partition_list:
    PARTITIONS partition_count

-- For RANGE/RANGE COLUMNS partitioned tables
range_partition_list:
    range_partition [, range_partition ...]

range_partition:
    PARTITION partition_name VALUES LESS THAN {(expr | value_list)} [partition_spec_options]

-- For LIST/LIST COLUMNS partitioned tables
list_partition_list:
    list_partition [, list_partition ...]

list_partition:
    PARTITION partition_name VALUES IN (value_list) [partition_spec_options]

Create a CCI

The following example creates a table named t_order and a CCI named cc_i_seller on it.

Step 1: Create the primary table.

CREATE TABLE t_order (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `order_id` varchar(20) DEFAULT NULL,
  `buyer_id` varchar(20) DEFAULT NULL,
  `seller_id` varchar(20) DEFAULT NULL,
  `order_snapshot` longtext DEFAULT NULL,
  `order_detail` longtext DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `l_i_order` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 partition by hash(`order_id`) partitions 16;

Step 2: Create the CCI.

CREATE CLUSTERED COLUMNAR INDEX `cc_i_seller` ON t_order (`seller_id`) partition by hash(`order_id`) partitions 16;

The annotated diagram below shows each component of the CCI definition:

image
Component Description
CLUSTERED COLUMNAR Keyword that specifies the index type as a CCI
Primary table t_order, partitioned by HASH on order_id with 16 partitions
Index name cc_i_seller — used to reference the index in SQL statements
Sort key seller_id — data in the index file is stored in order by this column
Index partition clause partition by hash(order_id) partitions 16 — uses the same syntax as CREATE TABLE

Verify CCI creation status

After you issue the CREATE CLUSTERED COLUMNAR INDEX statement, check the build status:

SHOW COLUMNAR INDEX FROM t_order;

To monitor the DDL task progress:

SHOW DDL;

The CCI is ready to use when the status shows as complete. For a description of the output fields, see SHOW COLUMNAR INDEX and SHOW DDL.

Use a CCI in queries

After you create a CCI, you can specify the index table to use for queries in the following ways:

Level Mechanism Behavior
1 (default) Automatic (cost-based optimizer) The optimizer picks the lowest-cost index automatically. No hints required.
2 USE INDEX / IGNORE INDEX Advise the optimizer to prefer or skip a specific index.
3 FORCE INDEX Override the optimizer and force the query to use the specified index.

Start with automatic selection. Use hints only when you need to override the optimizer's decision.

Automatic selection

For queries on a primary table that contains a CCI, PolarDB-X automatically selects the index table that the optimizer determines has the lowest cost. Currently, only columnstore read-only instances support CCI-based queries. No additional configuration is required.

USE INDEX

Advise the optimizer to use the specified index:

USE INDEX({index_name},...)

Example — prefer cc_i_seller:

SELECT t_order.id, t_order.order_snapshot
FROM t_order USE INDEX(cc_i_seller)
WHERE t_order.seller_id = 's1';

IGNORE INDEX

Advise the optimizer to skip the specified index:

IGNORE INDEX({index_name},...)

Example — exclude cc_i_seller from consideration:

SELECT t_order.id, t_order.order_snapshot
FROM t_order IGNORE INDEX(cc_i_seller)
WHERE t_order.seller_id = 's1';

FORCE INDEX

Override the optimizer and force use of the specified index:

FORCE INDEX({index_name})

Example — force cc_i_seller in a join:

SELECT a.*, b.order_id
FROM t_seller a
  JOIN t_order b FORCE INDEX(cc_i_seller) ON a.seller_id = b.seller_id
WHERE a.seller_nick = 'abc';

Limitations

Supported data types

The following table shows the data types supported for the primary key of the primary table and the sort and partition keys of the CCI:

Data type Primary key Sort key Partition key
Numeric: BIT (UNSIGNED) Supported Supported Not supported
Numeric: TINYINT (UNSIGNED) Supported Supported Supported
Numeric: SMALLINT (UNSIGNED) Supported Supported Supported
Numeric: MEDIUMINT (UNSIGNED) Supported Supported Supported
Numeric: INT (UNSIGNED) Supported Supported Supported
Numeric: BIGINT (UNSIGNED) Supported Supported Supported
Time: DATE Supported Supported Supported
Time: DATETIME Supported Supported Supported
Time: TIMESTAMP Supported Supported Supported
Time: TIME Supported Supported Not supported
Time: YEAR Supported Supported Not supported
String: CHAR Supported Supported Supported
String: VARCHAR Supported Supported Supported
String: TEXT Supported Supported Not supported
String: BINARY Supported Supported Supported
String: VARBINARY Supported Supported Supported
String: BLOB Supported Supported Not supported
Floating-point: FLOAT Not supported Not supported Not supported
Floating-point: DOUBLE Not supported Not supported Not supported
Floating-point: DECIMAL Not supported Not supported Not supported
Floating-point: NUMERIC Not supported Not supported Not supported
Special: JSON Not supported Not supported Not supported
Special: ENUM Not supported Not supported Not supported
Special: SET Not supported Not supported Not supported
Special: POINT Not supported Not supported Not supported
Special: GEOMETRY Not supported Not supported Not supported
Partitioning algorithms support different data types. For more information, see Data types.

DDL statement limits

To control whether DDL statements can run on a table that has a CCI, set the following parameter (true allows DDL; false blocks it):

SET [GLOBAL] forbid_ddl_with_cci = [true | false];

Supported DDL operations on primary tables with a CCI:

Category Action Sample SQL Supported
Primary table Delete table DROP TABLE tbl_name; Yes
Primary table Truncate table TRUNCATE TABLE tbl_name; Yes
Primary table Rename table ALTER TABLE old_tbl_name RENAME TO new_tbl_name; or RENAME TABLE old_tbl_name TO new_tbl_name; Yes
Primary table Rename multiple tables RENAME TABLE tbl_name_a TO tbl_name_b, tbl_name_c TO tbl_name_d; Yes
Primary table Add column ALTER TABLE tbl_name ADD col_name TYPE; Yes
Primary table Delete column ALTER TABLE tbl_name DROP COLUMN col_name; Yes
Primary table Modify column type ALTER TABLE tbl_name MODIFY col_name TYPE; Yes
Primary table Rename column ALTER TABLE tbl_name CHANGE old_col new_col TYPE; Yes
Primary table Modify column default value ALTER TABLE tbl_name ALTER COLUMN col_name SET DEFAULT default_value; or ALTER TABLE tbl_name ALTER COLUMN col_name DROP DEFAULT; Yes
Primary table Lock-free column type change ALTER TABLE tbl_name MODIFY col_name TYPE, ALGORITHM = omc; Yes
Primary table Multiple ALTER TABLE operations ALTER TABLE tbl_name MODIFY col_name_a, DROP COLUMN col_name_b; Yes
Primary table Generated column No
Primary table Partition change No
CCI Create CCI CREATE CLUSTERED COLUMNAR INDEX cci_name; or ALTER TABLE tbl_name ADD CLUSTERED COLUMNAR INDEX cci_name; Yes
CCI Delete CCI DROP INDEX cci_name ON TABLE tbl_name; or ALTER TABLE tbl_name DROP INDEX cci_name; Yes
CCI Rename CCI ALTER TABLE tbl_name RENAME INDEX cci_name_a TO cci_name_b; Yes
CCI Add a RANGE partition ALTER TABLE tbl_name.cci_name ADD PARTITION; Yes
CCI Other partition changes No

Column change constraints with `ALTER TABLE`:

Statement Can modify primary key? Can modify index partition key? Can modify sort key?
MODIFY COLUMN Yes Yes Yes
ALTER COLUMN SET DEFAULT / ALTER COLUMN DROP DEFAULT Yes Yes Yes
ADD COLUMN No N/A N/A
CHANGE COLUMN No No No
DROP COLUMN No No No
In versions 5.4.20-20250714 and later, MODIFY COLUMN and column default value changes are supported for some primary keys, CCI partition keys, and CCI sort keys.

Modifying a critical column (primary key, CCI partition key, or CCI sort key) may trigger a full CCI rebuild, which can be a long-running operation on large tables. This capability is disabled by default. We recommend that you use asynchronous execution. To enable it, set the following parameters before running the ALTER statement:

-- Allow modifying critical columns of a CCI
SET ENABLE_MODIFY_CCI_CRITICAL_COLUMN = TRUE;
-- Rebuild strategy: 0 lets the system select automatically
SET REBUILD_CCI_STRATEGY = 0;
-- Maximum number of CCIs per table; increase if the table already has multiple CCIs
SET MAX_CCI_COUNT = 2;

Supported data types for `MODIFY COLUMN` / `CHANGE COLUMN`:

Supported Not supported
Numeric: BIT (UNSIGNED), TINYINT (UNSIGNED), SMALLINT (UNSIGNED), MEDIUMINT (UNSIGNED), INT (UNSIGNED), BIGINT (UNSIGNED) POINT, GEOMETRY
Time: DATETIME, TIMESTAMP, TIME, YEAR
Floating-point: FLOAT, DOUBLE, DECIMAL, NUMERIC
String: CHAR, VARCHAR, TEXT, BINARY, VARBINARY, BLOB
Special: JSON, ENUM, SET

If you need to change a column to POINT or GEOMETRY, drop the CCI with DROP INDEX, change the data type, and recreate the CCI.

Supported index changes with `ALTER TABLE`:

Statement Supported
ALTER TABLE ADD PRIMARY KEY Yes
ALTER TABLE ADD [UNIQUE/FULLTEXT/SPATIAL/FOREIGN] KEY Yes
ALTER TABLE DROP INDEX Yes
ALTER TABLE DROP FOREIGN KEY fk_symbol Yes
ALTER TABLE DROP PRIMARY KEY No (prohibited)
ALTER TABLE RENAME INDEX Yes — can rename a CCI
ALTER TABLE ALTER INDEX index_name {VISIBLE | INVISIBLE} No — cannot modify a CCI
ALTER TABLE {DISABLE | ENABLE} KEYS No — cannot modify a CCI

FAQ

Can I create a CCI without specifying a sort key?

No. You must specify the sort key explicitly in the CREATE CLUSTERED COLUMNAR INDEX statement. The sort key and partition key can be different columns — for example, you can use seller_id as the sort key and order_id as the partition key on the same table.

Can I create a CCI without specifying a partition key?

Yes. If you omit the partition key, PolarDB-X uses the primary key as the partition key with HASH partitioning by default.

How do I check CCI creation progress?

Run SHOW COLUMNAR INDEX to see the current status and SHOW DDL to track DDL task progress. For details on reading the output, see SHOW COLUMNAR INDEX and SHOW DDL.

How do I delete a CCI?

Use the DROP INDEX statement.