MySQL CSV引擎仅支持读取和导入,不支持INSERT/UPDATE/DELETE,本质是只读文本桥接器,适用场景限于快速查询已有CSV文件或配合LOAD DATA INFILE导入其他引擎表。

CSV 引擎在 MySQL 里根本不能写入数据
MySQL 的 CSV 存储引擎只支持读取和导入,不支持 INSERT、UPDATE、DELETE —— 这是它最常被误用的点。你建一个 CSV 表,执行 INSERT 会直接报错:ERROR 1036 (HY000): Table 'xxx' is read only。它本质是个“只读文本桥接器”,不是通用表类型。
适用场景非常窄:把已有的 CSV 文件(比如导出报表、日志切片)快速映射成表来 SELECT 查询,或者用 LOAD DATA INFILE 导入到其他引擎表中。别指望它当业务表用。
-
CREATE TABLE时指定ENGINE=CSV,字段只能是CHAR、VARCHAR、TEXT等非二进制字符串类型,不支持INT、DATETIME(即使声明了也会被当作字符串存) - 表对应的真实文件是
/var/lib/mysql/数据库名/表名.CSV,必须由 MySQL 进程可读写,且格式严格:逗号分隔、双引号包裹字段、换行符为\n(Windows 的\r\n会导致解析错行) - 没有索引、没有事务、没有崩溃恢复能力,文件被外部程序修改后,MySQL 不会自动感知变化,需手动
FLUSH TABLES
如何让 CSV 表能被 SELECT 正确识别字段类型
CSV 引擎本身不解析数据类型,所有列都是字符串。但你可以用视图或查询时显式转换,绕过这个限制:
- 用
CAST(col AS UNSIGNED)或STR_TO_DATE(col, '%Y-%m-%d')在SELECT中转类型,注意空值和格式错误会变NULL - 更稳妥的做法是:先用
CSV表读原始文件,再用INSERT INTO target_table SELECT ...导入到InnoDB表,过程中做类型校验和清洗 - 如果字段含逗号或换行符,必须用双引号包裹,且内部双引号要写成两个(
""),否则SELECT会错位 —— 这类脏数据会让整行失效,不会报错,只会返回空值
LOAD DATA INFILE 导入 CSV 到 InnoDB 表时的坑
这才是 CSV 数据交换的主力路径。LOAD DATA INFILE 比 CSV 引擎实用得多,但参数稍有偏差就会静默失败或错列:
- 务必确认
secure_file_priv配置,MySQL 只允许从该路径下读文件;查它用SHOW VARIABLES LIKE 'secure_file_priv' - 字段分隔符默认是
\t(制表符),不是逗号!要导 CSV 必须显式写FIELDS TERMINATED BY ',' - 如果首行是标题,加
IGNORE 1 ROWS;字段含双引号需配OPTIONALLY ENCLOSED BY '"',否则引号会被当成内容 - 目标列类型是
DATE但源数据是2024/05/20?STR_TO_DATE()在SET子句里补转换,例如:SET created_at = STR_TO_DATE(@created_at, '%Y/%m/%d')
为什么不用 CSV 引擎做定时同步或 ETL
因为它的可靠性边界太低:文件权限错、换行符混用、字段内含未转义引号、MySQL 进程意外退出导致 .CSV 文件损坏 —— 任一情况都会让整个表不可查,且无日志可追溯。
真正需要交换数据时,优先走标准路径:mysqldump --tab 导出为纯文本 + LOAD DATA INFILE 导入,或用 SELECT ... INTO OUTFILE 生成规范 CSV 再交给下游处理。CSV 引擎只适合临时查一查那个没人维护的运营导出文件。
它连 ALTER TABLE 都不支持,改个字段名都得删表重建 —— 这种脆弱性,在自动化流程里就是定时炸弹。










