Use Direct Load to efficiently import CSV and Parquet data into PolarDB for MySQL columnar tables from OSS or local files.
Overview
Direct Load is a high-performance bulk loading mechanism for X-Engine columnar tables that imports data from OSS (Object Storage Service) or local files in CSV (default) or Parquet format. X-Engine columnar tables also support MySQL native import and DTS import (with the target engine set to X-Engine).
Session parameters
Direct Load uses the following session-level parameters:
|
Parameter |
Description |
Valid values |
Default |
|
|
Storage-layer parallelism. |
0 to 1024 |
1 |
|
|
The uniqueness check mode.
|
OFF / KEEPONE / ERROR |
KEEPONE |
|
|
Whether to build non-clustered indexes (NCI) asynchronously. |
ON / OFF |
OFF |
|
|
Whether to skip redo log replication on CFile commit. The CFile is persisted to primary storage but not replicated to the Standby cluster. Note
This parameter applies only to Standard Edition clusters without a Standby cluster. |
ON / OFF |
OFF |
Syntax
Direct Load extends the LOAD DATA syntax for OSS and local file imports.
LOAD DATA [OSS|LOCAL]
INFILE 'file_name'
[REPLACE | IGNORE]
INTO TABLE tbl_name
[PARTITION (partition_name [, ...])]
[CHARACTER SET charset_name]
[{FIELDS | COLUMNS}
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
[IGNORE number {LINES | ROWS}]
[(col_name_or_user_var [, ...])]
[SET col_name={expr | DEFAULT} [, ...]]
Restrictions
Direct Load has the following restrictions:
-
Table requirements: Direct Load supports only tables with
ENGINE=XENGINEandTABLE_FORMAT=COLUMN. The target table must be empty. -
Index support:
-
Tables with ORDER KEY are supported.
-
Secondary indexes, foreign keys, and hidden keys are not supported.
NoteThe hidden key restriction applies when the parameter
xengine_enable_ctable_hidden_key=ONis set.
-
-
Binary logging: Direct Load automatically disables binary logging for the import session by temporarily clearing the
OPTION_BIN_LOGflag. This does not affect the global configuration. -
Triggers: Tables with triggers are not supported.
-
Concurrency: Only one Direct Load statement can run per table at a time. The statement holds an exclusive MDL lock, which blocks all DML and DDL operations on the table.
-
Wildcards:
-
OSS mode supports wildcards (*). For example,
/home/t4/data/*.csv. -
LOCAL mode and non-Direct Load mode do not support wildcards.
-
Examples
Import data from OSS
Step 1: Create an OSS Server
Create an OSS Server with the connection details.
Creating an OSS Server requires the SERVERS_ADMIN privilege. Run SHOW GRANTS FOR username; to verify the current user has the SERVERS_ADMIN privilege.
A privileged account can grant this privilege. Without it, the following error is returned: Access denied; you need (at least one of) the SERVERS_ADMIN OR SUPER privilege(s) for this operation.
DROP SERVER IF EXISTS my_server;
CREATE SERVER my_server FOREIGN DATA WRAPPER oss OPTIONS (
EXTRA_SERVER_INFO '{"oss_endpoint":"oss-cn-xxxx-internal.aliyuncs.com","oss_bucket":"xxxx","oss_access_key_id":"xxxx","oss_access_key_secret":"xxxx"}'
);
SELECT * FROM mysql.servers;
Step 2: Create the target table
Create an X-Engine columnar table. This example uses the TPC-H lineitem table.
CREATE TABLE lineitem (
l_orderkey BIGINT NOT NULL,
l_partkey BIGINT NOT NULL,
l_suppkey BIGINT NOT NULL,
l_linenumber INT NOT NULL,
l_quantity DECIMAL(15,2) NOT NULL,
l_extendedprice DECIMAL(15,2) NOT NULL,
l_discount DECIMAL(15,2) NOT NULL,
l_tax DECIMAL(15,2) NOT NULL,
l_returnflag CHAR(1) NOT NULL,
l_linestatus CHAR(1) NOT NULL,
l_shipdate DATE NOT NULL,
l_commitdate DATE NOT NULL,
l_receiptdate DATE NOT NULL,
l_shipinstruct CHAR(25) NOT NULL,
l_shipmode CHAR(10) NOT NULL,
l_comment VARCHAR(44) NOT NULL,
PRIMARY KEY (l_orderkey, l_linenumber, l_shipdate),
ORDER KEY(l_orderkey)
) ENGINE=XENGINE TABLE_FORMAT=COLUMN;
Step 3: Import data
Set the parallelism level and run LOAD DATA OSS to import data. Wildcards can match multiple files.
-- Set the parallelism level (optional)
SET xengine_dload_parallel = 2;
-- Use wildcards to import multiple files (OSS mode only)
LOAD DATA OSS INFILE 'my_server/lineitem/lineitem_test*.csv'
INTO TABLE lineitem
FIELDS TERMINATED BY '|';
-- Verify the import results
SELECT * FROM lineitem ORDER BY l_orderkey, l_partkey DESC LIMIT 10;
SELECT COUNT(1) FROM lineitem;
Import data from a local file
Direct Load supports only one local file per statement. To import multiple files, use Import data from OSS.
Use LOAD DATA LOCAL to import data from a local file.
CREATE TABLE lineitem (
l_orderkey BIGINT NOT NULL,
l_partkey BIGINT NOT NULL,
l_suppkey BIGINT NOT NULL,
l_linenumber BIGINT NOT NULL,
l_quantity DECIMAL(15,2) NOT NULL,
l_extendedprice DECIMAL(15,2) NOT NULL,
l_discount DECIMAL(15,2) NOT NULL,
l_tax DECIMAL(15,2) NOT NULL,
l_returnflag CHAR(1) NOT NULL,
l_linestatus CHAR(1) NOT NULL,
l_shipdate DATE NOT NULL,
l_commitdate DATE NOT NULL,
l_receiptdate DATE NOT NULL,
l_shipinstruct CHAR(25) NOT NULL,
l_shipmode CHAR(10) NOT NULL,
l_comment VARCHAR(44) NOT NULL,
PRIMARY KEY (l_orderkey, l_linenumber, l_shipdate),
ORDER KEY(l_orderkey)
) ENGINE=XENGINE TABLE_FORMAT=COLUMN;
SET xengine_dload_parallel = 1;
-- Import from a local file (wildcards are not supported)
LOAD DATA LOCAL INFILE '/home/data/lineitem/lineitem_test.csv'
INTO TABLE lineitem
FIELDS TERMINATED BY '|';
-- Verify the import results
SELECT * FROM lineitem ORDER BY l_orderkey, l_partkey DESC LIMIT 10;
SELECT COUNT(1) FROM lineitem;
FORMAT PARQUET import
Direct Load imports Parquet files directly into X-Engine columnar tables, skipping CSV text parsing through an Arrow-to-ORC columnar fast path for better performance.
Parquet syntax
LOAD DATA [LOCAL | OSS] INFILE 'file_name_or_glob'
[REPLACE | IGNORE]
FORMAT PARQUET
INTO TABLE tbl_name
[PARALLEL n]
[(col_name [, col_name] ...)]
[OPTIONS (
batch_size = <unsigned int>,
validate_schema = TRUE | FALSE,
parallel = <unsigned int>
)];
Syntax details
-
Auto-detection: If the file name ends with
.parquet(case-insensitive), the system automatically enables Parquet import mode, even if you omit theFORMAT PARQUETkeyword. -
Parallel loading (
PARALLEL n): Specifies the thread count for parallel RowGroup reads. The actual parallelism is the smaller ofnand the total number of RowGroups across all files:actual parallelism = min(n, RowGroups x files). If omitted, parallelism defaults to the session variablexengine_dload_parallel.-
The
parallelkey inOPTIONSis equivalent to the outerPARALLEL n. When both are set,OPTIONS(parallel=N)takes precedence.
-
-
Selective column import (
(col_name, ...)): Lists specific columns to import from the Parquet file. Only listed columns are loaded; unlisted columns receive their default values.
Parquet restrictions
-
Data type compatibility: Data types in the Parquet file must be compatible with the target table column types. For example, Parquet
STRINGmaps toVARCHARorTEXT, butBINARYmaps only toBLOBorVARBINARY. See Type mapping for details. -
Schema matching:
-
Positional mode (no column list): The number of columns in the Parquet file must exactly match the number of columns in the target table, and types must be compatible by position.
-
Named mode (column list provided): Each column name in the list must exist in both the Parquet file and the target table, and the types must be compatible.
-
-
Asynchronous index build: Parquet import always uses asynchronous NCI (non-clustered index) build internally.
LOAD DATAreturns immediately after data is written, and the index builds in the background. During this process, the table supports only columnar queries. You do not need to setxengine_dload_async_build_ncimanually. -
Unsupported type:
FIXED_SIZE_BINARYArrow columns are not supported in the current version.
Type mapping
Parquet/Arrow types map to MySQL column types as follows.
|
Parquet / Arrow type |
Compatible MySQL types |
Notes |
|
|
|
Auto-widened |
|
|
Matching or wider integer types |
Smaller integers auto-widen to |
|
|
|
Safe widening on signed types |
|
|
|
|
|
|
|
- |
|
|
|
Non-binary character sets only |
|
|
|
For extra-long strings |
|
|
|
Cannot map to |
|
|
|
- |
|
|
|
When mapped to |
|
|
|
Nullable types are supported |
|
|
|
Uses the Decimal64 path internally |
|
|
|
Uses the Decimal128 path internally |
|
|
-- |
Not supported |
Parquet import examples
Import with named columns
Specify columns to import. Each name must exist in both the Parquet file and the target table.
-- Import only the id and name columns. Other columns are filled with defaults or NULL.
LOAD DATA LOCAL INFILE '/data/test_basic.parquet'
FORMAT PARQUET INTO TABLE t_prune (id, name);
Parallel loading (PARALLEL clause)
-- PARALLEL clause: 4 threads split by RowGroup
LOAD DATA LOCAL INFILE '/data/big.parquet'
FORMAT PARQUET INTO TABLE t_par PARALLEL 4;
-- Wildcards + PARALLEL: multi-file parallel import
LOAD DATA LOCAL INFILE '/data/multi_*.parquet'
FORMAT PARQUET INTO TABLE t_multi PARALLEL 8;
OPTIONS clause
The OPTIONS clause controls batch size and schema validation for Parquet imports.
LOAD DATA LOCAL INFILE '/data/test_basic.parquet'
FORMAT PARQUET INTO TABLE t_opts
OPTIONS(batch_size=65536, validate_schema=TRUE);
Import with a user-defined primary key
When the target table has a user-defined primary key, the Parquet file must include the primary key columns.
-- Single-column primary key
CREATE TABLE t_upk1 (
id INT PRIMARY KEY,
bigval BIGINT,
amount DOUBLE,
name VARCHAR(100)
) ENGINE=XENGINE TABLE_FORMAT=COLUMN;
LOAD DATA LOCAL INFILE '/data/test_basic.parquet'
FORMAT PARQUET INTO TABLE t_upk1;
-- Composite primary key
CREATE TABLE t_upk_comp (
id INT,
bigval BIGINT,
amount DOUBLE,
name VARCHAR(100),
PRIMARY KEY (id, bigval)
) ENGINE=XENGINE TABLE_FORMAT=COLUMN;
LOAD DATA LOCAL INFILE '/data/test_basic.parquet'
FORMAT PARQUET INTO TABLE t_upk_comp;
Import Parquet from OSS
Import Parquet files from OSS. Wildcards can match multiple files.
-- Create the OSS Server (same as the CSV example)
DROP SERVER IF EXISTS my_server;
CREATE SERVER my_server FOREIGN DATA WRAPPER oss OPTIONS (
EXTRA_SERVER_INFO '{"oss_endpoint": "oss-cn-xxxx.aliyuncs.com",
"oss_bucket": "xxxx",
"oss_access_key_id": "xxxx",
"oss_access_key_secret": "xxxx"}'
);
SET xengine_dload_parallel = 16;
LOAD DATA OSS INFILE 'my_server/path/to/data_*.parquet'
FORMAT PARQUET INTO TABLE t_basic PARALLEL 16;
Asynchronous NCI build mode
When xengine_dload_async_build_nci=ON, the import returns immediately after CTable files are written. The NCI builds asynchronously in the background.
Usage
SET xengine_dload_async_build_nci = ON;
SET xengine_dload_parallel = 64;
LOAD DATA OSS INFILE 'my_server/tpch1000g/lineitem.*'
INTO TABLE tpch1000.lineitem
FIELDS TERMINATED BY '|';
Restrictions during NCI build
-
DML and DDL operations on the table are blocked during the NCI build.
-
Only columnar execution plans are supported. Row-store plans fail with
ER_XENGINE_CTABLE_NCI_NOT_READY_FOR_ROWPLAN.
Query examples during asynchronous NCI build
SET use_imci_engine = ON;
SELECT * FROM lineitem ORDER BY l_orderkey, l_partkey DESC LIMIT 10; -- OK
SELECT COUNT(1) FROM lineitem; -- OK
SET use_imci_engine = OFF;
SELECT * FROM lineitem ORDER BY l_orderkey, l_partkey DESC LIMIT 10; -- Error
UPDATE lineitem SET l_partkey=1 WHERE l_orderkey=149999904; -- Error
Monitor NCI build progress
Query information_schema.XENGINE_CTABLE_NCI_BUILD to monitor progress.
SELECT schema_name, table_name, task_status FROM information_schema.XENGINE_CTABLE_NCI_BUILD ORDER BY subtable_id;
Cancel and rebuild NCI
Cancel an ongoing NCI build with the dbms_ctable package, then rebuild if needed.
-- Cancel the NCI build
CALL dbms_ctable.cancel_nci_build(<subtable_id>);
-- Rebuild the NCI after cancellation
CALL dbms_ctable.rebuild_nci(<subtable_id>);
TPC-H 100 GB import example (CSV)
This example imports TPC-H 100 GB data from OSS using Direct Load.
Create the target tables
This example uses the lineitem table.
SET xengine_enable_ctable_hidden_key = OFF;
DROP DATABASE IF EXISTS tpch100;
CREATE DATABASE tpch100;
USE tpch100;
-- Example: Create the lineitem table
CREATE TABLE lineitem (
L_ORDERKEY INTEGER NOT NULL,
L_PARTKEY INTEGER NOT NULL,
L_SUPPKEY INTEGER NOT NULL,
L_LINENUMBER INTEGER NOT NULL,
L_QUANTITY DECIMAL(15,2) NOT NULL,
L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL,
L_DISCOUNT DECIMAL(15,2) NOT NULL,
L_TAX DECIMAL(15,2) NOT NULL,
L_RETURNFLAG CHAR(1) NOT NULL,
L_LINESTATUS CHAR(1) NOT NULL,
L_SHIPDATE DATE NOT NULL,
L_COMMITDATE DATE NOT NULL,
L_RECEIPTDATE DATE NOT NULL,
L_SHIPINSTRUCT CHAR(25) NOT NULL,
L_SHIPMODE CHAR(10) NOT NULL,
L_COMMENT VARCHAR(44) NOT NULL,
PRIMARY KEY (L_ORDERKEY, L_LINENUMBER, L_SHIPDATE)
) ENGINE=XENGINE TABLE_FORMAT=COLUMN;
Create the OSS Server
DROP SERVER IF EXISTS my_server;
CREATE SERVER my_server
FOREIGN DATA WRAPPER oss OPTIONS
(
EXTRA_SERVER_INFO '{"oss_endpoint": "oss-cn-xxxx.aliyuncs.com","oss_bucket": "xxxx","oss_access_key_id": "xxxx","oss_access_key_secret": "xxxx"}'
);
Batch import script
The following bash script imports all TPC-H tables in parallel.
#!/usr/bin/env bash
set -u
SOCK=/tmp/mysql29.sock
OUT=output.txt
PREFIX="my_server/imci/tpch100g"
DB=tpch100
PARA=64
: > "$OUT"
tables=(lineitem nation region part supplier partsupp customer orders)
run() {
local t="$1"
(
echo "===== [$t] START $(date '+%F %T') ====="
sql="SET xengine_dload_parallel=${PARA};
LOAD DATA OSS INFILE '${PREFIX}/${t}.*'
INTO TABLE ${DB}.${t}
FIELDS TERMINATED BY '|';"
{ time mysql -uroot -S "$SOCK" -e "$sql"; } 2>&1
rc=${PIPESTATUS[0]:-0}
echo "===== [$t] END $(date '+%F %T') rc=$rc ====="
echo
exit "$rc"
) >>"$OUT" 2>&1 &
echo "[$t] pid=$!"
}
for t in "${tables[@]}"; do
run "$t"
done
wait
echo "ALL DONE $(date '+%F %T')" >>"$OUT"
TPC-H Parquet import example
This example follows the same structure as TPC-H 100 GB import example (CSV). Table DDL and OSS Server setup are identical — replace tpch100 with tpch_parquet for a separate database. The differences: FORMAT PARQUET replaces CSV, FIELDS TERMINATED BY is not needed, and asynchronous NCI runs automatically without setting xengine_dload_async_build_nci.
#!/usr/bin/env bash
set -u
SOCK=/tmp/mysql29.sock
OUT=output.txt
# TODO: Replace with the actual OSS path, for example: my_server/imci/tpch1000g_parquet
PREFIX="my_server/<TBD>/tpch_parquet"
DB=tpch_parquet
PARA=64
: > "$OUT"
tables=(lineitem nation region part supplier partsupp customer orders)
run() {
local t="$1"
(
echo "===== [$t] START $(date '+%F %T') ====="
sql="SET xengine_dload_parallel=${PARA};
LOAD DATA OSS INFILE '${PREFIX}/${t}/*.parquet'
FORMAT PARQUET INTO TABLE ${DB}.${t} PARALLEL ${PARA};"
{ time mysql -uroot -S "$SOCK" -e "$sql"; } 2>&1
rc=${PIPESTATUS[0]:-0}
echo "===== [$t] END $(date '+%F %T') rc=$rc ====="
echo
exit "$rc"
) >>"$OUT" 2>&1 &
echo "[$t] pid=$!"
}
for t in "${tables[@]}"; do
run "$t"
done
wait
echo "ALL DONE $(date '+%F %T')" >>"$OUT"
# Wait for the background asynchronous NCI build to complete before using row plans or DML
mysql -uroot -S "$SOCK" -N -e "
SELECT TABLE_NAME, TASK_STATUS, RUN_SEC
FROM information_schema.XENGINE_CTABLE_NCI_BUILD
ORDER BY CREATE_TIME;"
Error handling
Common Direct Load errors and solutions.
|
Error code |
Description |
Solution |
|
|
Unsupported feature |
Verify that the table uses |
|
|
Primary key conflict |
Check for duplicate primary keys in the data. Set |
|
|
NCI not ready for row-store plan |
Wait for the NCI build to complete, or use a columnar execution plan. Check the build progress in |
|
|
DML attempted during NCI build |
DML and DDL operations are not allowed during NCI build. Wait for the NCI build to complete. |
Best practices
-
Binary logging is automatically disabled: Direct Load disables binary logging for the import session. The global configuration is not affected.
-
Set appropriate parallelism: For OSS imports, set
xengine_dload_parallelto 32–64. For local file imports, use a lower value. -
Use asynchronous NCI build for large imports: Enable
xengine_dload_async_build_nci=ONto reduce import time. -
Ensure the target table is empty: Direct Load requires an empty target table.
-
Remove secondary indexes before import: Drop secondary indexes before import and recreate them afterward.
-
Use wildcards in OSS mode: Match multiple files with wildcards (*) in a single statement.
-
Monitor NCI build progress: Check
information_schema.XENGINE_CTABLE_NCI_BUILDto verify completion before running row-store plans. -
Prefer Parquet over CSV: Parquet skips text parsing and uses a columnar fast path for better performance.