Skip to main content

MySQL Compatibility Notes

Doris is highly compatible with the MySQL protocol and standard SQL syntax. Business systems, BI tools, and operations scripts can usually connect without major changes. However, as an analytics-oriented MPP database, Doris still differs from MySQL in areas such as data types, table creation syntax, data models, and DML behavior.

This document organizes the main differences between Doris and MySQL from two perspectives, migration and daily use, to help you quickly locate syntax or behavior incompatibilities.

Intended Readers and Scenarios

  • You plan to migrate a MySQL application or data warehouse to Doris and need to quickly assess SQL compatibility.
  • You run into syntax or behavior differences when writing SQL on Doris with MySQL habits.
  • You need to check whether a specific data type or DDL/DML statement is supported in Doris.

Data Type Differences

The differences from MySQL are listed below, grouped by numeric, date, string, JSON, and Doris-specific types.

Numeric Types

TypeMySQLDoris
Boolean- Supported
- Range: 0 stands for false, 1 stands for true
- Supported
- Keyword: Boolean
- Range: 0 stands for false, 1 stands for true
Bit- Supported
- Range: 1 to 64
Not supported
Tinyint- Supported
- Supports signed and unsigned
- Range: signed is -128 to 127, unsigned is 0 to 255
- Supported
- Only signed is supported
- Range: -128 to 127
Smallint- Supported
- Supports signed and unsigned
- Range: signed is -2^15 to 2^15-1, unsigned is 0 to 2^16-1
- Supported
- Only signed is supported
- Range: -32768 to 32767
Mediumint- Supported
- Supports signed and unsigned
- Range: signed is -2^23 to 2^23-1, unsigned is 0 to 2^24-1
Not supported
Int- Supported
- Supports signed and unsigned
- Range: signed is -2^31 to 2^31-1, unsigned is 0 to 2^32-1
- Supported
- Only signed is supported
- Range: -2147483648 to 2147483647
Bigint- Supported
- Supports signed and unsigned
- Range: signed is -2^63 to 2^63-1, unsigned is 0 to 2^64-1
- Supported
- Only signed is supported
- Range: -2^63 to 2^63-1
LargeintNot supported- Supported
- Only signed is supported
- Range: -2^127 to 2^127-1
Decimal- Supported
- Supports signed and unsigned (supported before 8.0.17, marked as deprecated in later versions)
- Default: Decimal(10, 0)
- Supported
- Only signed is supported
- Default: Decimal(9, 0)
Float/Double- Supported
- Supports signed and unsigned (supported before 8.0.17, marked as deprecated in later versions)
- Supported
- Only signed is supported

Date Types

TypeMySQLDoris
Date- Supported
- Range: ['1000-01-01', '9999-12-31']
- Format: YYYY-MM-DD
- Supported
- Range: ['0000-01-01', '9999-12-31']
- Format: YYYY-MM-DD
DateTime- Supported
- DATETIME([P]), where the optional parameter P is the precision
- Range: '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'
- Format: YYYY-MM-DD hh:mm
.fraction
- Supported
- DATETIME([P]), where the optional parameter P is the precision
- Range: ['0000-01-01 00:00:00[.000000]', '9999-12-31 23:59:59[.999999]']
- Format: YYYY-MM-DD hh:mm
.fraction
Timestamp- Supported
- Timestamp[(p)], where the optional parameter P is the precision
- Range: ['1970-01-01 00:00:01.000000' UTC, '2038-01-19 03:14:07.999999' UTC]
- Format: YYYY-MM-DD hh:mm
.fraction
- Supported
- TIMESTAMPTZ([P]), where the optional parameter P is the precision
- Range: ['0000-01-01 00:00:00[.000000]' UTC, '9999-12-31 23:59:59[.999999]' UTC]
- Format: YYYY-MM-DD hh:mm
.fraction
+XX.XX
Time- Supported
- Time[(p)]
- Range: ['-838:59:59.000000', '838:59:59.000000']
- Format: hh:mm
.fraction
- Supported for computation, cannot be stored as a column in OLAP tables
- Time[(p)]
- Range: ['-838:59:59.999999', '838:59:59.999999']
- Format: hh:mm
.fraction
Year- Supported
- Range: 1901 to 2155, or 0000
- Format: yyyy
Not supported

String Types

TypeMySQLDoris
Char- Supported
- CHAR(M), where M is the character length, defaults to 1
- Fixed length
- Range: [0, 255], in bytes
- Supported
- CHAR(M), where M is the byte length
- Variable
- Range: [1, 255]
Varchar- Supported
- VARCHAR(M), where M is the character length
- Range: [0, 65535], in bytes
- Supported
- VARCHAR(M), where M is the byte length
- Range: [1, 65533]
StringNot supported- Supported
- 1048576 bytes (1 MB), can be increased up to 2147483643 bytes (2 GB)
Binary- Supported
- Similar to Char
Not supported
Varbinary- Supported
- Similar to Varchar
Not supported
Blob- Supported
- TinyBlob, Blob, MediumBlob, LongBlob
Not supported
Text- Supported
- TinyText, Text, MediumText, LongText
Not supported
Enum- Supported
- Up to 65535 elements
Not supported
Set- Supported
- Up to 64 elements
Not supported

JSON Data Type

TypeMySQLDoris
JSONSupportedSupported

Doris-Specific Data Types

The following types are analytics-oriented data types that Doris extends beyond MySQL. They are commonly used for distinct counting, quantile computation, and semi-structured scenarios.

  • HyperLogLog

    The HLL type cannot be used as a Key column. When used in an Aggregate model table, the matching aggregation type at table creation is HLL_UNION. You do not need to specify length or default value; the length is controlled internally by the system based on the aggregation level of the data. HLL columns can only be queried or used through the matching HLL_UNION_AGG, HLL_RAW_AGG, HLL_CARDINALITY, and HLL_HASH functions.

    HLL is approximate distinct counting and outperforms Count Distinct on large data volumes. The error rate of HLL is typically around 1%, and may sometimes reach 2%.

  • BITMAP

    The BITMAP type cannot be used as a Key column. When used in an Aggregate table, it must be paired with the BITMAP_UNION aggregation definition. You do not need to specify length or default value; the length is controlled internally by the system based on the aggregation level of the data. BITMAP columns can only be queried or used through the matching BITMAP_UNION_COUNT, BITMAP_UNION, BITMAP_HASH, BITMAP_HASH64, and other functions.

    Using BITMAP in offline scenarios may affect import speed. With large data volumes, its query speed is slower than HLL but faster than Count Distinct. Note: in real-time scenarios, if BITMAP is used without a global dictionary and BITMAP_HASH() is used instead, an error of about one in a thousand may occur. If this error is unacceptable, you can use BITMAP_HASH64.

  • QUANTILE_PERCENT (QUANTILE_STATE)

    The QUANTILE_STATE type cannot be used as a Key column. When used in an Aggregate model table, the matching aggregation type at table creation is QUANTILE_UNION. You do not need to specify length or default value; the length is controlled internally by the system based on the aggregation level of the data. QUANTILE_STATE columns can only be queried or used through the matching QUANTILE_PERCENT, QUANTILE_UNION, TO_QUANTILE_STATE, and other functions.

    QUANTILE_STATE is a type for computing approximate quantiles. During import, it pre-aggregates different Values for the same Key: when the number of Values does not exceed 2048, all data is recorded in detail; when the number of Values exceeds 2048, the TDigest algorithm is used to aggregate (cluster) the data and store the centroids of the clusters.

  • Array<T>

    Array<T> is an array of elements of type T and cannot be used as a Key column.

  • MAP<K, V>

    Map is a mapping table of elements of type K and V and cannot be used as a Key column.

  • STRUCT<field_name:field_type, ...>

    Struct is a structure composed of multiple Fields, which can also be understood as a collection of multiple columns. It cannot be used as a Key.

    The Field names and number in a Struct are fixed and always Nullable. A Field typically consists of:

    • field_name: the identifier of the Field, which must be unique
    • field_type: the type of the Field
  • Agg_State

    AGG_STATE cannot be used as a Key column. When creating a table, you must also declare the signature of the aggregate function.

    You do not need to specify length or default value; the actual storage size depends on the function implementation.

    AGG_STATE can only be used together with the STATE / MERGE / UNION function combinators.

Syntax Differences

Doris SQL syntax is overall close to MySQL, but it has some unique extensions or restrictions in scenarios such as table creation, indexes, and views. Pay particular attention to these during migration.

DDL Differences

CREATE TABLE

The Doris table creation syntax is as follows:

CREATE TABLE [IF NOT EXISTS] [database.]table
(
column_definition_list
[, index_definition_list]
)
[engine_type]
[keys_type]
[table_comment]
[partition_info]
distribution_desc
[rollup_list]
[properties]
[extra_properties]

The differences between each clause and MySQL are as follows:

ParameterDifferences from MySQL
column_definition_list- Defines the column list. The basic syntax is similar to MySQL.
- Doris additionally supports an aggregation type operation, primarily for the Aggregate Key data model.
- MySQL allows constraints such as Index, Primary Key, and Unique Key to be added after the column list definition; Doris implements support for these constraints and computations through data models.
index_definition_list- Defines the index list. The basic syntax is similar to MySQL.
- MySQL supports bitmap indexes, inverted indexes, and N-Gram indexes, and can also enable Bloom filter indexes through properties.
- MySQL supports B+Tree indexes and Hash indexes.
engine_type- Specifies the table engine type. Optional.
- The currently supported table engine is mainly the OLAP native engine.
- MySQL supports storage engines such as InnoDB and MyISAM.
keys_type- Specifies the data model. Optional.
- Supported types include:
  1) DUPLICATE KEY (default): the columns specified after it are sort columns;
  2) AGGREGATE KEY: the columns specified after it are dimension columns;
  3) UNIQUE KEY: the columns specified after it are primary key columns.
- MySQL has no concept of a data model.
table_commentTable comment.
partition_infoPartitioning algorithm. Optional.
Doris supports the following partitioning algorithms:
- LESS THAN: defines only the upper bound of the partition; the lower bound is determined by the upper bound of the previous partition.
- FIXED RANGE: defines a left-closed, right-open interval for the partition.
- MULTI RANGE: creates RANGE partitions in batch, defining left-closed, right-open intervals with a time unit and step size. Supported time units are year, month, day, week, and hour.

MySQL supported algorithms: Hash, Range, and List Key, with subpartitions supported. Subpartitions support Hash and Key.
distribution_desc- Bucketing algorithm. Required. Includes:
  1) Hash bucketing: DISTRIBUTED BY HASH (k1[, k2 ...]) [BUCKETS num|auto], uses the specified key columns for hash bucketing;
  2) Random bucketing: DISTRIBUTED BY RANDOM [BUCKETS num|auto], uses random numbers for bucketing.
- MySQL has no bucketing algorithm.
rollup_list- Multiple synchronous materialized views can be created at the same time as table creation.
- Syntax: rollup_name (col1[, col2, ...]) [DUPLICATE KEY(col1[, col2, ...])][PROPERTIES("key" = "value")].
- Not supported by MySQL.
propertiesTable properties. The properties differ from those of MySQL, and the syntax for defining them also differs from MySQL.

CREATE INDEX

CREATE INDEX [IF NOT EXISTS] index_name ON table_name (column [, ...],) [USING BITMAP];
  • Doris currently supports bitmap indexes, inverted indexes, N-Gram indexes, and Bloom filter indexes (configured through separate syntax).
  • MySQL supports B+Tree and Hash index algorithms.

CREATE VIEW

CREATE VIEW [IF NOT EXISTS]
[db_name.]view_name
(column1[ COMMENT "col comment"][, column2, ...])
AS query_stmt

CREATE MATERIALIZED VIEW [IF NOT EXISTS] mvName=multipartIdentifier
(LEFT_PAREN cols=simpleColumnDefs RIGHT_PAREN)? buildMode?
(REFRESH refreshMethod? refreshTrigger?)?
(KEY keys=identifierList)?
(COMMENT STRING_LITERAL)?
(PARTITION BY LEFT_PAREN partitionKey = identifier RIGHT_PAREN)?
(DISTRIBUTED BY (HASH hashKeys=identifierList | RANDOM) (BUCKETS (INTEGER_VALUE | AUTO))?)?
propertyClause?
AS query
  • The basic syntax is the same as MySQL.
  • In addition to logical views, Doris also supports two types of materialized views: synchronous materialized views and asynchronous materialized views.
  • MySQL does not support materialized views.

ALTER TABLE / ALTER INDEX

The Doris ALTER syntax is essentially the same as MySQL.

DROP TABLE / DROP INDEX

The Doris DROP syntax is essentially the same as MySQL.

DML Differences

INSERT

INSERT INTO table_name
[ PARTITION (p1, ...) ]
[ WITH LABEL label]
[ (column [, ...]) ]
[ [ hint [, ...] ] ]
{ VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }

The Doris INSERT syntax is essentially the same as MySQL.

UPDATE

UPDATE target_table [table_alias]
SET assignment_list
WHERE condition

assignment_list:
assignment [, assignment] ...

assignment:
col_name = value

value:
{expr | DEFAULT}

The Doris UPDATE syntax is essentially the same as MySQL, but note that a WHERE condition is required.

DELETE

DELETE FROM table_name [table_alias]
[PARTITION partition_name | PARTITIONS (partition_name [, partition_name])]
WHERE column_name op { value | value_list } [ AND column_name op { value | value_list } ...];

In Doris, the syntax above only allows specifying filter predicates.

DELETE FROM table_name [table_alias]
[PARTITION partition_name | PARTITIONS (partition_name [, partition_name])]
[USING additional_tables]
WHERE condition

In Doris, the syntax above can only be used on Unique Key model tables.

The Doris DELETE syntax is essentially the same as MySQL. However, since Doris is an analytics-oriented database, delete operations should not be performed too frequently.

SELECT

SELECT
[hint_statement, ...]
[ALL | DISTINCT]
select_expr [, select_expr ...]
[EXCEPT ( col_name1 [, col_name2, col_name3, ...] )]
[FROM table_references
[PARTITION partition_list]
[TABLET tabletid_list]
[TABLESAMPLE sample_value [ROWS | PERCENT]
[REPEATABLE pos_seek]]
[WHERE where_condition]
[GROUP BY [GROUPING SETS | ROLLUP | CUBE] {col_name | expr | position}]
[HAVING where_condition]
[ORDER BY {col_name | expr | position} [ASC | DESC], ...]
[LIMIT {[offset_count,] row_count | row_count OFFSET offset_count}]
[INTO OUTFILE 'file_name']

The Doris SELECT syntax is essentially the same as MySQL.

SQL Functions

Doris functions cover the vast majority of MySQL functions. Common string, date, aggregate, and window functions can be used directly.

SQL Mode

Doris supports setting some SQL Modes to control SQL parsing and execution behavior, making it easier to stay aligned with MySQL conventions.

NameBehavior when setBehavior when not setNotes
PIPES_AS_CONCATParses the || symbol as the concat functionParses the || symbol as the logical OR operator-
NO_BACKSLASH_ESCAPESTreats backslashes in strings as normal charactersTreats backslashes in strings as the start of an escape sequence-
ONLY_FULL_GROUP_BYAllows only standard aggregationAllows aggregation result output to include scalar values that are not in the aggregation KEYSupported since version 3.1.0