mysqli_fetch_all()需加MYSQLI_ASSOC参数才能返回关联数组;Python需手动zip字段名转字典;未释放结果集或大结果集全加载易致内存溢出与数据错乱。
PHP 中用 mysqli_fetch_all() 直接转数组,但要注意第二个参数
查完数据库后想直接拿到 php 数组?mysqli_fetch_all() 是最省事的选择,但它默认返回的是二维索引数组(每行是数字下标),不是你写 sql 时字段名那种关联数组。
常见错误现象:var_dump($result) 看到全是 [0] => "张三", [1] => 25,没法用 $row['name'] 访问。
- 加第二个参数
MYSQLI_ASSOC:得到关联数组,字段名作键 - 加
MYSQLI_NUM:保持纯数字下标(默认行为) - 加
MYSQLI_BOTH:同时有数字和字符串键 —— 冗余,占内存,别用
示例:$rows = mysqli_fetch_all($result, MYSQLI_ASSOC);
Python 的 cursor.fetchall() 返回元组,转字典要自己配字段名
Python 的 DB-API(比如 mysql-connector-python 或 pymysql)里,fetchall() 默认返回的是 tuple 套 tuple,没有字段名信息。不像 PHP 那样一个参数就能切模式。
使用场景:你想导出成 [{"id": 1, "name": "李四"}, ...] 这种结构,而不是 [(1, "李四"), (2, "王五")]。
- 先取字段名:
columns = [col[0] for col in cursor.description] - 再 zip 每行数据:
[dict(zip(columns, row)) for row in cursor.fetchall()] - 注意:如果用
sqlite3,可以设conn.row_factory = sqlite3.Row,之后row['name']可直接用,但导出仍需手动转成 dict(dict(row))
导出前没清空结果集缓存,下次查询会拿错数据
很多同学在循环中反复执行查询、导出,结果发现第二次导出的内容和第一次一样,或者报错 Commands out of sync —— 这是因为上一次查询的结果集没读完或没释放。
典型错误操作:fetchall() 后没做任何处理,又立刻执行新 execute()。
- MySQLi:必须调用
mysqli_free_result($result),或让变量自动销毁(函数内局部变量一般没问题) - Python:确保
fetchall()/fetchone()把结果全取完;若只取部分,要用cursor.nextset()跳过剩余结果集(尤其存储过程多结果集时) - 不释放的后果:连接被占住,后续查询可能返回旧数据、报错,甚至影响并发
大结果集直接 fetchall() 会爆内存,得流式处理
导出几万行还行,几十万行以上还用 fetchall(),PHP 报 Fatal error: Allowed memory size exhausted,Python 也一样卡死 —— 不是语法问题,是设计误用。
性能影响:一次性加载所有数据进内存,GC 压力大,响应延迟高,服务容易抖动。
- PHP:改用
while ($row = mysqli_fetch_assoc($result)) { ... }边取边处理 - Python:用
for row in cursor:或fetchmany(size=1000)分批拉取 - 别想着“先全取再导出”,导出动作本身就可以是流式的(比如边查边写 CSV)
真正麻烦的从来不是怎么转数组,而是没想清楚数据量级和生命周期 —— 缓存没清、内存没控、字段名没对齐,三个点踩中一个,导出来的就不是“数组”,是隐患。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










