SQLite 已声明外键却写入孤儿数据:连接初始化与存量校验实践
订单明细表已经写了 REFERENCES orders(id),导入程序却能插入不存在的订单号。更容易误判的情况是:初始化脚本设置过 PRAGMA foreign_keys = ON,接口仍然产生孤儿明细。 这时先确认写入连接的状态。SQLite 的外键执行开关属于连接;迁移连接开启,不代表接口、后台任务和临时导入脚本
Tag
包含这个标签的文章。
订单明细表已经写了 REFERENCES orders(id),导入程序却能插入不存在的订单号。更容易误判的情况是:初始化脚本设置过 PRAGMA foreign_keys = ON,接口仍然产生孤儿明细。 这时先确认写入连接的状态。SQLite 的外键执行开关属于连接;迁移连接开启,不代表接口、后台任务和临时导入脚本
适用场景与现象 配置表按租户和作用域保存覆盖项:scope_id 有值表示某个具体作用域,为 NULL 表示租户默认配置。业务要求每个租户只能有一条默认配置,每个具体作用域也只能有一条。 表上已经有 UNIQUE (tenant_id, scope_id),压测后却出现两条默认配置。读取接口用 LIMIT 1 暂时掩盖
订单明细增加退款展示后,报表的销售额突然变大。单独查订单金额正确,单独查退款也正确,只有合并查询对不上。此时先检查关联后的数据粒度:一张订单同时对应多条商品明细和多条退款时,两组明细会组合成多行,最后的 SUM 会把同一金额累计多次。 本文以 PostgreSQL 17 为语义基准,用一套可复现数据定位问题,再把查询改
场景:有待处理订单,补偿任务却扫不到 补偿任务从订单表里找出“尚未有成功回执”的订单。原先使用 NOT IN (SELECT order_id ...),导入一条未关联订单的回执后,任务突然返回零行,接口没有报错,查询耗时也正常。 下面是隔离复现,不代表真实生产事故。SQL 按 PostgreSQL 17 编写,使用会
适用场景 本文适用于 PostgreSQL 13 及以上版本的生产库:为了避免普通 CREATE INDEX 长时间阻塞写入,运维或开发人员改用 CREATE INDEX CONCURRENTLY,但命令执行数十分钟后失败、被取消,或者发布系统超时退出。重新执行时又提示索引已存在,查询计划却仍然走顺序扫描。 本文重点处
适用场景 商品详情、活动配置、首页聚合数据和权限策略等读取接口,通常会把查询结果缓存在 Redis 中。平时数据库负载很低,一旦某个热点键过期,大量并发请求却可能同时回源,几百毫秒内把连接池占满,最终形成接口超时、重试放大和数据库雪崩。 本文讨论的是单个或少量热点键失效导致的缓存击穿。如果大量键在同一时间过期,属于缓存
适用场景与现象 同一个接口在生产环境中偶发出现以下现象:有时写入没有立即提交,有时日期相差 8 小时,有时普通查询突然以更严格的事务隔离级别执行。重启应用后故障暂时消失,单独连接 MySQL 手工执行又无法复现。 这类问题常见于使用连接池的 Web 服务、异步任务和批处理程序。连接池归还的是可复用的物理连接,而 MyS
适用场景 本文适用于 PostgreSQL 表使用 serial、bigserial 或 identity 列生成主键,但执行正常 INSERT 时仍出现主键重复的场景。常见诱因包括数据迁移、手工补数据、COPY 导入、只恢复表数据却漏掉序列状态,或者在不同环境之间合并数据。 典型表结构如下: CREATE TABLE
适用场景 本文适用于使用 Redis Stream 消费组承载异步任务、事件通知或轻量消息队列的系统。典型架构是生产者通过 XADD 写入 Stream,多个消费者用 XREADGROUP 拉取消息,业务成功后再执行 XACK。 当某个消费者在处理期间崩溃、被强制重启或网络中断时,已经投递但尚未确认的消息不会重新出现在
适用场景 本文适用于 MySQL 8.0 使用 InnoDB 的生产环境。典型场景是 SQL 和索引近期都没有修改,但一次批量导入、归档删除或数据分布变化后,原本几十毫秒的查询突然变成数秒;EXPLAIN 显示优化器改走了低选择性索引、错误的连接顺序,甚至全表扫描。 这类问题容易被误判为“数据库负载太高”。真正需要回答