惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security @ Cisco Blogs
H
Hacker News: Front Page
P
Privacy International News Feed
N
News and Events Feed by Topic
T
Threatpost
Simon Willison's Weblog
Simon Willison's Weblog
S
Schneier on Security
K
Kaspersky official blog
S
Secure Thoughts
V2EX - 技术
V2EX - 技术
Security Latest
Security Latest
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
CERT Recently Published Vulnerability Notes
L
Lohrmann on Cybersecurity
Jina AI
Jina AI
P
Proofpoint News Feed
AI
AI
雷峰网
雷峰网
T
Tailwind CSS Blog
Engineering at Meta
Engineering at Meta
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - 叶小钗
Webroot Blog
Webroot Blog
Apple Machine Learning Research
Apple Machine Learning Research
SecWiki News
SecWiki News
罗磊的独立博客
N
Netflix TechBlog - Medium
Martin Fowler
Martin Fowler
Google DeepMind News
Google DeepMind News
Cyberwarzone
Cyberwarzone
MongoDB | Blog
MongoDB | Blog
博客园 - Franky
Schneier on Security
Schneier on Security
The GitHub Blog
The GitHub Blog
S
Security Affairs
Blog — PlanetScale
Blog — PlanetScale
Last Week in AI
Last Week in AI
P
Proofpoint News Feed
月光博客
月光博客
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Securelist
W
WeLiveSecurity
T
Troy Hunt's Blog
A
Arctic Wolf
博客园 - 司徒正美

数据库

各位现在还手写 sql 吗? [翻译] 为什么我要用 C# 构建数据库引擎 向量数据库的正确用法是什么? 明天就要软考了,我发现了数据库三范式之第一范式好像过时了 WM 到 IOS 用了二十年的数据表格软件 Listpro 准备退休了 异机备份方案 Oracle 裁员裁到大动脉了?官方软件 Oacle SQL Developer 居然出现恶性 BUG 了。 ubuntu 中 DataGrip 从数据表中复制的中文成了乱码 你们在用什么数据库管理软件? 大佬们,生产环境的 Mysql 和 Redis 都是部署在哪里的呢 不知道全国有多少数据系统被 Oracle 数据库的 VARCHAR2(X) 的默认单位给坑了 海量数据访问 刚问 AI 解了一个去年看书的一个疑惑:数据存储选择 lklv, llkv 有没有好用 GUI client 可以方便管理多个 Postgre 数据库 你们现在设计系统数据库的时候还在数据库层面搞外键约束吗? - V2EX 有没有类似阿里云 mysql 数据库这样的数据恢复工具? 刚接触后端不久,帮忙推荐一个免费的数据库可视化工具 2026 年了,公司搞了一大堆没用的 Tracing 数据,存 ES 都快卡炸了 请教 oracle, mysql 不停机同步到达梦数据库实际工作中有什么方案吗 datagrip 切换查询界面的时候,结果集不随着跳转 我发现 TiDB Cloud 比较牛逼啊 请问有做过时序数据库的大佬么? - V2EX 程序员玩具多系列:有什么 navicat/datagrip 替代品推荐 - V2EX grafana 中 dashboard 里的数据显示为空,实际通过 Queries 查询是有数据的? 数据库性能测试的要点有哪些? 标签系统内容最大标签数放开到很大(比如三万)对性能影响有多大? 2025 年了, select *是否仍然禁止使用? - V2EX AI 给我写了一个 SQL DB 模糊测试工具,求 star [讨论] 大家的项目中会使用外键约束吗? - V2EX 帮忙看看是不是太垃圾,断断续续搞了几个月数据库监控工具,一个用户都没有 - V2EX 有能把 navicat 连接转为 datagrip 的工具吗 内存数据库 h2 与 mysql 兼容性太差了,能把 PostgreSQL 整成单测环境启动吗 [讨论] 免费的数据库工具中大家喜欢哪款 怎么评价 order by rand() limit 1 这条 sql 大佬们,请教一个数据库设计的问题 你们用过数据库联合索引优化排序功能吗 靓仔们, DataGrip 非商用免费了 - V2EX PgSQL 和 Sqlserver 哪个好?哪个资源占用小?哪个性能好速度快? 有没有公开的、靠谱的美妆品牌&产品库数据源 - V2EX 有个关于 mongodb 的问题,求大神来解答一下 sql server where 查询时 字段是 nvarchar 类型的保存的数字 但是可以用 int 类型的数字去匹配,这是什么原理? 你们平时手撸 SQL 多吗?还是 ORM 优先 postgres vs mysql - Why Uber Engineering Switched from Postgres to MySQL 信创, Mongo、redis 可以用到信创项目里吗 团队日志要存几年,怎么找一个便宜又能查的地方? - V2EX 数据表和字段取名太难了,有没有工具可以根据描述生成表名? 不限语言,你觉得最好用的框架和 ORM 是什么? 2025 年了,贵司的可观测技术栈用的是什么?监控怎么存,日志怎么存,追踪怎么存?想知道新的趋势都有什么? 小白求教:图数据库和关系型数据最大的区别是什么 VictoriaMetrics 开发者笔记: Traces 的查询性能与优化倾向 [新手求建议] 结构化数据,波形图为主,用于识别模型训练有没有推荐的数据库? SQL 数据库咨询 DMS 客户端已经很久没有更新了,后面也不会维护 新系统做大数据解析是否需要上 hadoop sql 占位符替换 TUI 工具 pebble kv 数据库,在查询过程中是怎么处理的。(针对存放在不同地方的的数据库) 阿里云的各种云数据库同步功能就是个大坑。。 数据库操作,如何在多个不同的库里筛选数据 关于数据库索引的一个问题:有复合索引建立于列 a,b,c。那么 where a=1 and b like b% and c=3 命中此索引吗? where a=1 and b > 2 and c=3 命中此索引吗? 项目 MYSQL 数据库,要改造成信创国产数据库,有没有改造最小的方案; 有没有异构数据库对比的软件? TIDB 在 LEFT JOIN 时,为什么不使用被关联表的索引,而是全表扫描?
SQL 查不到数据,数据却明明存在——MySQL 降序主键与 index_merge intersect 的一次诡异排查 - V2EX
EasonIndie · 2026-07-17 · via 数据库

一、现象:看得见,却查不到

线上某张表 t_invoice 出现一个反常现象:同一条记录,去掉某个等值条件能查到,加上却查不到。

-- 查询 A:带状态等值条件 —— 返回空
SELECT biz_id, status, serial_no
FROM t_invoice
WHERE biz_id = 537
  AND status = 'PASSED';

-- 查询 B:不带状态条件 —— 返回 6 行,其中 3 行 status = 'PASSED'
SELECT biz_id, status, serial_no
FROM t_invoice
WHERE biz_id = 537;

查询 B 的结果:

biz_id status serial_no
537 PASSED 2692*************8629
537 PASSED 2692*************4377
537 PASSED 2692*************1155
537 REJECTED 2692*************6649
537 CANCELLED 2692*************6599
537 REJECTED 2692*************7967

明明有 3 条 PASSED,查询 A 却返回空——典型的"看得见却匹配不到"。数据没丢,问题出在哪?


二、排查

第 1 步:先怀疑隐藏字符 —— 排除

这类问题的头号嫌疑是字段值里混入了不可见字符(尾部空格、零宽字符、BOM )。用 HEX 看真实字节:

SELECT status,
       LENGTH(status)       AS byte_len,
       CHAR_LENGTH(status)  AS char_len,
       HEX(status)          AS hex_val
FROM t_invoice
WHERE biz_id = 537;

结果:PASSEDHEX = 504153534544,纯 ASCII ,6 字节 6 字符,干干净净,无任何隐藏字符。排除数据问题,方向转向优化器。

第 2 步:看表结构 —— 发现一个"不对劲"的主键

SHOW CREATE TABLE t_invoice;

关键字段与索引:

`status` varchar(32) ... COLLATE utf8mb4_general_ci NOT NULL,
...
PRIMARY KEY (`id` DESC, `status`) USING BTREE,   -- ⚠ 异常:降序 + 业务列进了主键
KEY `idx_biz` (`biz_id`),
KEY `idx_status` (`status`),
KEY `idx_biz_status` (`biz_id`, `status`)

字符集与排序规则一切正常,但主键 (id DESC, status) 极不寻常:

  • idAUTO_INCREMENT 自增列,单独做主键就够了,没必要把业务状态列 status 塞进来;
  • DESC 降序索引对自增主键毫无意义,反而有害——自增插入会变成 B+ 树头部插入,引发页分裂。

这个设计是后面所有麻烦的源头。

第 3 步:对比执行计划 —— 锁定 Using intersect

EXPLAIN SELECT ... WHERE biz_id = 537 AND status = 'PASSED';
EXPLAIN SELECT ... WHERE biz_id = 537;
查询 type key Extra 结果
A (查不到) index_merge idx_biz_status, idx_status Using intersect(...) ❌ 空
B (能查到) ref idx_biz - ✅ 6 行

查询 A 触发了 index_merge + Using intersect:优化器对两个索引分别扫描后取交集。这就是头号嫌疑犯。

第 4 步:两个验证 —— 确认 intersect 就是元凶

-- ① 改用 LIKE ,走 range 而非 intersect
WHERE biz_id = 537 AND status LIKE 'PASSED%';
-- 执行计划:type=range, key=idx_biz_status, Extra=Using index condition
-- 结果:✅ 返回 3 条

-- ② 用 hint 关闭 index_merge
SELECT /*+ SET_VAR(optimizer_switch='index_merge=off') */ ...
WHERE biz_id = 537 AND status = 'PASSED';
-- 结果:✅ 返回 3 条

LIKE 能查到,说明复合索引物理完好、数据都在;关闭 index_merge 后等值查询也正常——铁证。问题既不是数据、也不是索引损坏,而是 intersect 算法本身算错了。

第 5 步:NO_INDEX 模拟删索引 —— 区分"索引问题"还是"算法问题"

NO_INDEX hint 让优化器假装某个索引不存在,无需真正 DDL 就能模拟"删索引后"的执行计划:

-- 模拟删复合索引 idx_biz_status
EXPLAIN SELECT /*+ NO_INDEX(t idx_biz_status) */ ...
-- -> 仍走 intersect(idx_biz, idx_status),返回空 ❌

-- 模拟删单列索引 idx_status
EXPLAIN SELECT /*+ NO_INDEX(t idx_status) */ ...
-- -> 改走 idx_biz_status ref(const,const),返回 3 条 ✅
模拟操作 执行计划 结果
删复合索引 idx_biz_status index_merge / Using intersect(idx_biz, idx_status) ❌ 空
删单列索引 idx_status ref / idx_biz_status / const,const ✅ 3 条

关键结论:删复合索引没用(还有两个索引继续 intersect ),删 idx_status 才有用(消除了 intersect 的候选)。说明问题不在某个索引,而在"多索引共存触发 intersect + 降序主键"这个组合。


MySQL 8.0.26-cluster 的 index_merge intersection 算法与降序复合主键不兼容,触发链如下:

  1. 等值查询命中多个索引(idx_biz_statusidx_status 都覆盖 status 列);
  2. 优化器选择 index_merge intersect,对两个索引的 rowid 集合取交集;
  3. 主键含降序列 id DESC,二级索引的 rowid (= 主键值)在交集比较时字节序处理出错
  4. 本应匹配的主键被判为不相等 → 交集为空 → 查询返回空集。

LIKErange、不带状态条件走单索引 ref,都不触发 intersect ,所以只有"biz_id = ? AND status = ?"这类等值查询会中招。


四、解决:

止血:应用层加 hint (立即生效)

-- 方式 A:精准指定复合索引(最优,直接定位)
SELECT /*+ INDEX(t idx_biz_status) */
       t.biz_id, t.status, t.serial_no
FROM t_invoice t
WHERE t.biz_id = 537 AND t.status = 'PASSED';

-- 方式 B:关闭 index_merge (兜底)
SELECT /*+ SET_VAR(optimizer_switch='index_merge=off') */
       t.biz_id, t.status, t.serial_no
FROM t_invoice t
WHERE t.biz_id = 537 AND t.status = 'PASSED';

注意:该表所有 biz_id=? AND status=? 等值查询都受影响,需统一加 hint ,不能只改一处。

根治:修正主键(最终采用方案)

由于数据量不大,备份表后,在业务量少时,把主键从 (id DESC, status) 改回标准自增主键 (id)

-- 1. 备份(务必)
CREATE TABLE t_invoice_bak AS SELECT * FROM t_invoice;

-- 2. 修正主键
ALTER TABLE t_invoice
  DROP PRIMARY KEY,
  ADD PRIMARY KEY (`id`);

-- 3. 验证(应返回 3 条)
SELECT biz_id, status, serial_no
FROM t_invoice
WHERE biz_id = 537 AND status = 'PASSED';

-- 4. 行数核对
SELECT
  (SELECT COUNT(*) FROM t_invoice)     AS now_cnt,
  (SELECT COUNT(*) FROM t_invoice_bak) AS bak_cnt;

安全性id 为自增全局唯一,(id, status) 唯一 ⟸ id 唯一,改主键不改变任何唯一性语义;自增计数器保留;二级索引 rowid 由 MySQL 自动重建,无需手动干预。