本机对5万行数据做ORDER BY,把sort_buffer_size分别调到32KB、默认256KB、64MB,用Sort_merge_passes这个状态变量验证:32KB真实触发了6次磁盘归并,默认256KB也真实触发了1次,只有调到64MB才真实做到0次。
本机把internal_tmp_mem_storage_engine切到旧版MEMORY引擎后验证:GROUP BY只聚合数字列,Created_tmp_disk_tables真实是0;一旦GROUP BY要带上一个真正的TEXT列,Created_tmp_disk_tables真实立刻变成1。换回默认的TempTable引擎,同一条查询又真实变回了0。
本机对同一个索引做ALTER TABLE ... INVISIBLE验证:索引可见时走索引范围扫描,真实耗时1.33毫秒;标记成不可见后优化器真实彻底无视它,退化成全表扫描,耗时变成18.5毫秒,慢了约14倍。
本机验证ORDER BY customer_id ASC, created_at DESC这种两列排序方向不一样的查询:普通复合索引真实还是要Sort;建一个方向完全匹配的降序复合索引后,Sort真实消失了,1.5万行的真实查询耗时从64.2毫秒降到26.0毫秒。
本机验证WHERE UPPER(note)='...'这种对列做了函数运算的查询:note列上一个普通索引真实完全帮不上忙,还是全表扫描;建一个函数索引后,真实变成Index lookup,5万行数据上从16.4毫秒降到0.22毫秒,快了约75倍。
本机对比同一个OR查询在高选择性(约7%行匹配)和低选择性(约92%行匹配)下的真实表现:高选择性时index_merge真实比全表扫描快3.3倍;低选择性时手动模拟index_merge的UNION写法,真实比优化器自己选的全表扫描慢了66%。
本机打开OPTIMIZER_TRACE,把上一篇index_merge的代价拆解成三个真实数字:读两条索引range本身只要355.08,排序rowid读磁盘要514.79,而按行ID去重真实要3657.61——去重这一步的代价,比另外两步加起来还高5倍多。
本机开两个真实会话验证:session A开一个REPEATABLE READ事务读到amount=148.08,session B把同一行改成9999.99并提交,A在自己事务内再读一次,真实还是148.08。用History list length验证:40个独立提交的事务真实让它从1涨到41。
本机在同一个REPEATABLE READ事务里连续做三次读:普通SELECT两次真实都读到快照里的1000.00,哪怕另一个会话中途已经把值改成500并提交;紧接着加上FOR UPDATE再读一次,真实立刻变成了500.00。
本机验证REPEATABLE READ下的幻读:session A用普通SELECT数了两次某个id范围的行数,B在中途真实插入一行新数据并提交,A的两次普通计数真实都是8;A紧接着换成SELECT...FOR UPDATE再数一次,真实变成了9——当前读能看见幻影行。
本机用一张id取值10,20,30...80的表验证:SELECT ... WHERE id BETWEEN 10 AND 30 FOR UPDATE真实锁住了(10,20)和(20,30)这两个间隙,向id=15插入真实被阻塞;但id=10前面和id=30后面的间隙没被锁,真实立即插入成功。
本机用两个查询真实做出对比:不匹配真实行的范围查询拿到的是纯Gap Lock,不会阻止更新边界记录;真实匹配到行的范围查询拿到的是Next-Key Lock,会阻止更新记录本身——同样落在id=20,是否匹配真实数据决定了锁的种类。