Ubuntu修改SQLite最大列限制后Anaconda调用仍报列数超限如何解决
- 你卸载系统apt安装的sqlite3后,Anaconda环境内的
import sqlite3仍可正常使用,是因为Anaconda的Python运行时自带独立的sqlite3动态链接库,和系统包管理安装的sqlite完全隔离,卸载系统包不会影响Anaconda内的依赖。 - 执行
make时提示Nothing to be done for 'all',是因为源码目录存在旧的编译缓存,修改sqlite3.c后构建系统未检测到需要重新编译,你调整的SQLITE_MAX_COLUMN参数根本没有被编入最终二进制文件。 - 最终导入数据时报
too many columns on MyTable,是因为你的Python环境自始至终调用的都是Anaconda自带的默认配置sqlite(默认单表列上限2000),自行编译的自定义版本sqlite从未被Python加载。
方案1:重新编译自定义参数的SQLite并正确加载
步骤1:清理缓存重新编译
进入你解压的sqlite-amalgamation源码目录,先清理旧的编译产物:
make distclean
指定独立安装路径(避免覆盖系统/Anaconda自带文件造成环境损坏)重新配置:
./configure --prefix=/opt/sqlite_custom
确认sqlite3.c中SQLITE_MAX_COLUMN参数已修改为3000(官方规定该参数安全上限为32767,3000属于合理范围),之后执行编译安装:
make -j$(nproc) sudo make install
编译完成后执行以下命令验证参数是否生效:
/opt/sqlite_custom/bin/sqlite3 :memory: "PRAGMA max_column_count;"
命令返回3000即代表编译成功。
步骤2:让Anaconda环境加载自定义版本SQLite
不要直接替换Anaconda目录下的sqlite文件,容易造成环境损坏,通过预加载动态库的方式实现最稳妥:
先确认编译生成的动态库路径,默认在/opt/sqlite_custom/lib/libsqlite3.so.0,可通过以下命令确认:
ls /opt/sqlite_custom/lib/libsqlite3*
在启动Spyder或运行Python脚本前,先设置环境变量指定优先加载自定义的sqlite库:
export LD_PRELOAD=/opt/sqlite_custom/lib/libsqlite3.so.0 spyder
启动后在Spyder控制台执行以下代码验证加载是否正确:
import sqlite3 conn = sqlite3.connect(':memory:') print(conn.execute("PRAGMA max_column_count;").fetchone()[0])
返回3000即可正常执行你的数据导入代码。如果需要永久生效,把上述export语句添加到用户目录下的.bashrc文件末尾,执行source ~/.bashrc即可。
方案2:优化表结构(更推荐,无需修改源码)
SQLite单表存储3000列本身读写性能极差,即便突破列数上限,后续查询、写入、维护的效率都会非常低。存储矩阵数据更合理的方式是使用长表结构,完全不需要修改SQLite默认配置:
仅需创建3列的表即可存储全量2500行*3000列的矩阵数据,表结构参考:
CREATE TABLE matrix_data ( row_id INTEGER, col_id INTEGER, value REAL, -- 根据你矩阵单元格的实际数据类型调整 PRIMARY KEY (row_id, col_id) );
用pandas导入前,先通过pd.melt方法把宽表转为长表格式,再调用to_sql写入即可。这种存储方式不受列数上限限制,配合主键索引,查询、聚合的效率远高于3000列的宽表。
内容的提问来源于stack exchange,提问作者leila

