一批SKU每天同步一次,图片内容没有变化,但商品图库每天多一张。有时是 image.jpg、Image.jpg、IMAGE.JPG 三种记录,有时数据库路径一样,磁盘却出现 _1、_2 后缀。导入器的去重依赖媒体路径,Linux文件系统区分大小写,而上游Windows系统通常不区分,两个世界一碰就很容易重复。
先不要急着删文件,建立对应关系
SELECT value_id,value FROM catalog_product_entity_media_gallery WHERE LOWER(value) LIKE '%sku-1001%'; SELECT value_id,store_id,label,position,disabled FROM catalog_product_entity_media_gallery_value WHERE value_id IN (/* 上一步ID */);
Magento 2不同版本媒体图库表结构略有差异,还可能存在 catalog_product_entity_media_gallery_value_to_entity。先用DESCRIBE确认,不要把网上的删除SQL直接复制到生产。
同时在 pub/media/catalog/product 下用不区分大小写方式查找。
find pub/media/catalog/product -type f -iname '*sku-1001*' -printf '%p %s bytes\n'
确认重复发生在哪一步
- 上游导出的CSV路径是否每天改变大小写
- import目录里是否同时保留旧文件与新文件
- 导入前是否有脚本自动重命名冲突文件
- 自定义导入器比较路径时是否做了统一规范化
- 对象存储同步是否把同一路径当成不同Key
最稳的规则是在进入Magento前统一:路径使用小写、扩展名统一、去除前后空格,并确保同一个二进制文件得到确定的目标名。若业务要求保留原文件名,也至少应生成一个规范化比较键。
normalized = strtolower(trim(path)) extension = strtolower(pathinfo(normalized, PATHINFO_EXTENSION)) compare by normalized path + optional content hash
清理已有重复记录
先导出商品与图库映射做备份。对同一商品、同一图片内容,选择一个规范路径作为保留项;把base_image、small_image、thumbnail角色指向保留项,再通过Magento媒体图库服务移除多余项。不要先删磁盘文件,否则后台会出现数据库记录存在但图片404。
批量清理建议写一次性CLI:读取ProductRepository,按规范路径或sha256分组,保留仍承担角色且position最前的一张,调用MediaGalleryManagement移除其余图片,保存后再清理无人引用的物理文件。
导入后的检查
bin/magento catalog:images:resize bin/magento cache:clean block_html full_page
- 连续执行同一CSV两次,第二次图库数量不应增加
- Linux磁盘上不存在仅大小写不同的同内容文件
- base/small/thumbnail角色仍指向有效图片
- 不同Store View的label和disabled没有被清理脚本误删
- 前台原图、缓存图和WebP衍生图都能正常加载
去重之前一定先确认“同内容”还是“同文件名”。不同角度的图片可能文件名相近,不能只按SKU前缀批量删除。

