分类: 未分类

  • Immich 从 PostgreSQL 16 迁移到 PostgreSQL 18

    适用版本

    • Immich v3.x
    • Unraid
    • PostgreSQL 16(pgvecto-rs)
    • PostgreSQL 18(官方 Vector + VChord)

    本文记录了一条经过实际验证成功的迁移方案。整个过程采用官方 PostgreSQL 18 数据库,将旧版 pgvecto-rs 数据库迁移到新版 Vector + VChord 数据库,同时完整保留用户、照片、相册、标签等数据。(chatgpt 生成!!!)


    前言

    升级 Immich v3 后,很多用户都会遇到数据库无法启动的问题,例如:

    Error: No vector extension found.
    Available extensions: vchord, vector

    或者:

    Detected schema drift

    产生这些问题的根本原因是:

    Immich v3 已经放弃了 pgvecto-rs,改用了 pgvector + VChord

    也就是说:

    Immich 旧版本Immich v3
    vectors(pgvecto-rs)vector(pgvector)
    PostgreSQL 16PostgreSQL 18
    tensorchord/pgvecto-rsghcr.io/immich-app/postgres

    因此,直接升级容器通常无法正常启动,需要迁移数据库。

    本文最终实现的效果

    迁移完成后,可以保留:

    • 所有照片
    • 所有视频
    • 所有用户
    • 所有相册
    • 所有标签
    • 所有收藏
    • 所有分享
    • 所有 Memories
    • 数据库升级到 PostgreSQL 18

    AI 数据(人脸识别、智能搜索)会重新建立索引,不影响照片数据。

    恢复数据库到 PostgreSQL 18

    完成数据库导出后,就可以开始恢复到新的 PostgreSQL 18 数据库。

    整个恢复过程分为四个步骤:

    1. 创建新的 PostgreSQL 18 数据库
    2. 删除旧扩展信息
    3. 恢复数据库
    4. 验证恢复结果

    创建 PostgreSQL 18

    首先,在 Unraid 中安装新的 PostgreSQL 18 容器。

    建议不要覆盖旧数据库,而是使用新的数据目录,例如:

    /mnt/user/appdata/PostgreSQL_Immich18

    数据库镜像:

    ghcr.io/immich-app/postgres:18-vectorchord

    容器名称:

    Immich_PostgreSQL

    启动后,进入数据库:

    docker exec -it Immich_PostgreSQL psql -U postgres

    查看数据库:

    \l

    应该可以看到:

     immich
     postgres
     template0
     template1

    如果没有 immich,可以创建:

    CREATE DATABASE immich;

    退出:

    \q

    检查新版数据库扩展

    进入新数据库:

    docker exec -it Immich_PostgreSQL \
    psql -U postgres -d immich

    查看扩展:

    \dx

    正常应该包含:

    cube
    earthdistance
    pg_trgm
    uuid-ossp
    vector
    vchord

    其中最重要的是:

    vector
    vchord

    说明数据库已经满足 Immich v3 的要求。

    退出:

    \q

    将备份复制到容器

    恢复之前,将备份复制到 PostgreSQL 容器:

    docker cp /mnt/user/immich_no_vectors.dump \
    Immich_PostgreSQL:/tmp/

    复制成功后,开始生成恢复列表。


    生成恢复对象列表

    执行:

    docker exec PostgreSQL_Immich \
    pg_restore -l /tmp/immich_no_vectors.dump \
    > /mnt/user/immich.list

    这里生成的是整个备份文件的目录。

    不要直接恢复。

    原因是里面仍然包含旧版 vectors 扩展。


    删除 vectors 相关对象

    复制一份恢复列表:

    cp /mnt/user/immich.list \
    /mnt/user/immich_filtered.list

    删除所有 vectors 内容:

    sed -i '/vectors/d' \
    /mnt/user/immich_filtered.list

    同时删除 AI 搜索表:

    sed -i '/face_search/d' \
    /mnt/user/immich_filtered.list
    
    sed -i '/smart_search/d' \
    /mnt/user/immich_filtered.list

    检查是否已经删除:

    grep -Ei "vectors|face_search|smart_search" \
    /mnt/user/immich_filtered.list

    如果没有任何输出:

    (无输出)

    说明过滤成功。


    将过滤后的文件复制到 PostgreSQL 18

    复制:

    docker cp /mnt/user/immich_filtered.list \
    Immich_PostgreSQL:/tmp/

    恢复文件如果尚未复制,也一起复制:

    docker cp /mnt/user/immich_no_vectors.dump \
    Immich_PostgreSQL:/tmp/

    开始恢复数据库

    执行:

    docker exec Immich_PostgreSQL \
    pg_restore \
    -L /tmp/immich_filtered.list \
    -U postgres \
    -d immich \
    /tmp/immich_no_vectors.dump

    整个恢复过程中一般不会有输出。

    恢复完成后返回:

    root@Tower:~#

    表示恢复成功。


    验证数据库恢复

    进入数据库:

    docker exec -it Immich_PostgreSQL \
    psql -U postgres -d immich

    查看数据表:

    \dt

    应该看到六十多个表,例如:

    asset
    album
    person
    memory
    library
    workflow
    user
    tag
    plugin
    video_stream_session
    ...

    说明业务数据已经恢复。

    退出:

    \q

    验证数据数量

    检查照片数量:

    docker exec -it Immich_PostgreSQL \
    psql -U postgres -d immich \
    -c "SELECT count(*) FROM asset;"

    例如:

     count
    -------
    23600

    再检查用户:

    docker exec -it Immich_PostgreSQL \
    psql -U postgres -d immich \
    -c "SELECT count(*) FROM \"user\";"

    例如:

     count
    -------
    2

    如果这些数量与旧数据库一致,就说明迁移成功。


    启动 Immich

    确认 Immich 连接的是新的 PostgreSQL:

    docker exec immich env | grep DB_

    例如:

    DB_HOSTNAME=<IP地址>
    DB_DATABASE_NAME=immich
    DB_USERNAME=postgres
    DB_PORT=5432

    确认无误后,启动 Immich。

    第一次启动时,很可能会出现:

    Detected schema drift

    以及:

    face_search is missing
    clip_index does not exist

    不要紧张。

    这是因为新版数据库没有旧版 AI 向量表。

    属于正常现象。

    下一部分将介绍如何使用 immich-admin schema-check 自动修复数据库结构,并重新创建 face_searchsmart_searchface_indexclip_index,最终使 Immich 正常启动。

    修复数据库结构并完成迁移

    完成数据库恢复后,Immich 已经能够读取数据库中的绝大部分业务数据,但第一次启动时通常仍然无法正常运行。

    这是因为在导出数据库时,我们主动移除了旧版 AI 向量数据,因此新版数据库缺少了 AI 搜索相关的数据表。

    这一步只需要重新创建这些数据表即可。


    第一次启动 Immich

    启动 Immich 后,可以查看日志:

    docker logs -f immich

    正常情况下会看到类似输出:

    Running migrations
    Finished running migrations
    Checking for schema drift

    随后可能出现:

    Detected schema drift

    并提示:

    The table "face_search" is missing
    
    The table "smart_search" is missing
    
    The index "face_index" is missing
    
    The index "clip_index" is missing

    紧接着 Immich 会退出,并出现:

    relation "clip_index" does not exist

    这是迁移过程中最容易让人误以为失败的一步。

    实际上,这是正常现象

    因为我们恢复的是业务数据,而没有恢复旧版 AI 向量数据库。


    使用 schema-check 检查数据库

    Immich 已经提供了自动检查工具。

    执行:

    docker exec -it immich immich-admin schema-check

    如果数据库正常,会看到:

    Migrations are up to date

    随后输出:

    Detected schema drift

    例如:

    TableCreate:
    face_search
    
    IndexCreate:
    face_index
    
    TableCreate:
    smart_search
    
    IndexCreate:
    clip_index

    最下面还会自动生成 SQL。

    例如:

    CREATE TABLE "face_search" (
    ...
    );
    
    CREATE INDEX "face_index" ...
    
    CREATE TABLE "smart_search" (
    ...
    );
    
    CREATE INDEX "clip_index" ...

    这些 SQL 正是我们需要执行的内容。


    执行 schema-check 生成的 SQL

    进入 PostgreSQL:

    docker exec -it Immich_PostgreSQL \
    psql -U postgres -d immich

    把 schema-check 输出的 SQL 完整复制进去执行

    执行完成后会看到类似输出:

    CREATE TABLE
    
    CREATE INDEX
    
    CREATE TABLE
    
    ALTER TABLE
    
    CREATE INDEX

    说明数据库已经修复完成。

    退出:

    \q

    再次启动 Immich

    重新启动 Immich:

    docker restart immich

    查看日志:

    docker logs -f immich

    正常情况下可以看到:

    Running migrations
    
    Finished running migrations
    
    Checking for schema drift

    随后:

    Nest application successfully started

    最后:

    Immich Server is listening on http://127.0.0.1:8080

    说明服务器已经正常启动。

    如果同时看到:

    Application startup complete

    以及:

    Starting microservices worker

    则说明整个 Immich 服务已经恢复正常。


    登录 Immich

    浏览器访问:

    http://服务器IP:2283

    登录后建议首先检查:

    • 是否能够正常登录
    • 用户是否存在
    • 相册是否存在
    • Memories 是否正常
    • 标签是否正常
    • 收藏是否正常
    • 分享链接是否正常

    如果这些都正常,说明数据库迁移已经成功。


    重新建立 AI 搜索索引

    由于旧版 vectors 数据没有迁移,因此:

    • 人脸识别
    • 智能搜索(CLIP)
    • 人物搜索

    都会重新建立索引。

    进入:

    Administration

    打开:

    Jobs

    依次运行:

    Generate Thumbnails
    
    Generate CLIP Embeddings
    
    Facial Recognition
    
    Smart Search

    根据照片数量不同,整个过程可能需要数小时。

    等待任务全部完成即可。


    清理旧数据库

    确认新数据库已经稳定运行几天后,就可以删除旧数据库。

    停止旧 PostgreSQL:

    docker stop PostgreSQL_Immich

    删除容器:

    docker rm PostgreSQL_Immich

    如果确认不会再回退,可以删除旧数据库目录:

    /mnt/user/appdata/PostgreSQL_Immich

    建议至少保留一周备份后再删除。


    建议重新备份 PostgreSQL 18

    迁移完成后,建议立即备份新的数据库。

    执行:

    docker exec Immich_PostgreSQL \
    pg_dump \
    -U postgres \
    -Fc \
    immich \
    > /mnt/user/immich_pg18_backup.dump

    以后恢复时,直接使用这个备份即可,无需再次处理 vectors 扩展。


    常见问题

    1. No vector extension found

    原因:

    旧数据库仍然使用 vectors 扩展。

    解决:

    迁移到 PostgreSQL 18,并恢复到 vector + vchord 数据库。


    2. extension “vectors” is not available

    原因:

    恢复了旧数据库中的 CREATE EXTENSION vectors

    解决:

    使用 pg_restore -l 生成恢复列表,并删除所有包含 vectors 的条目。


    3. relation “clip_index” does not exist

    原因:

    AI 搜索数据表未创建。

    解决:

    运行:

    docker exec -it immich immich-admin schema-check

    执行其自动生成的 SQL。


    4. Detected schema drift

    原因:

    数据库结构与当前 Immich 版本不一致。

    解决:

    按照 schema-check 提供的 SQL 修复即可。


    迁移总结

    本次迁移最终采用了以下路线:

    PostgreSQL 16
            │
            ▼
    导出数据库(排除 AI 向量表)
            │
            ▼
    删除 vectors 扩展信息
            │
            ▼
    恢复到 PostgreSQL 18
            │
            ▼
    schema-check 修复数据库结构
            │
            ▼
    Immich 正常启动
            │
            ▼
    重新建立 AI 搜索索引

    整个过程中,照片、视频、用户、相册、标签等业务数据全部保留,仅重新生成了 AI 向量索引。

    实践证明,这是一条稳定、可靠且易于复现的迁移方案。


    后记

    这次迁移过程中,一个重要的经验是:

    数据库迁移最重要的不是尝试很多方案,而是确定一条正确的路线,并坚持执行到底。

    中途频繁切换方案,容易引入新的问题,也会浪费大量时间。

    最终采用的方案——导出业务数据 → 删除旧版 vectors 扩展对象 → 恢复到 PostgreSQL 18 → 使用 schema-check 修复数据库结构——顺利完成了整个迁移过程,也为今后的升级提供了一条清晰、可复用的路径。

    希望本文能够帮助遇到同样问题的用户少走弯路,顺利完成 Immich 数据库升级。