实测升级 Python 3.15 会撞上的移除项:No module named sre_compile/sre_constants/sre_parse;glob.glob0/glob1、platform.java_ver、typing.no_type_check_decorator、ctypes.SetPointerType 变成 AttributeError;pathlib.PathInfo 等四个名字搬走;typing.ByteString、tarfile.version 开始警告;以及怎么在 3.14 上用 -W 提前发现。
实测 Python 3.15 默认 UTF-8:GBK、ISO8859-1 环境下 open() 的默认编码 3.14 跟系统、3.15 一律 utf-8;3.14 写的 GBK 文件在 3.15 里 UnicodeDecodeError,反方向也读不了;GBK 环境下 print emoji 3.14 UnicodeEncodeError;read_text、configparser、subprocess 一起变;PYTHONUTF8=0 与 -X warn_default_encoding。
实测 Python 3.15 报错信息的变化:110 个常见出错小程序逐字比较,只有 6 个文字变了——AttributeError 的建议从 Did you mean: 'append'? 变成 Did you mean '.append' instead of '.appnd'?,% 格式化的 TypeError 重写;SyntaxError 31 个全部相同;10 个常见警告只多了 typing.ByteString;以及依赖报错文字的正则会怎样。
实测 Python 3.14.9 对 3.15.0 的性能:18 个测试独立做两遍,几何平均比值 1.01 和 1.03(整体持平);递归 fib 两遍都是 1.23(3.15 慢),json.dumps 两遍是 0.89 和 0.86(3.15 快);Homebrew 的两个包编译选项不一样:3.14.9 有 --with-tail-call-interp,3.15.0 没有。
实测 PostgreSQL 16.15 的行版本:用 pageinspect 看堆页,UPDATE 会插入新版本并填旧版本的 xmax,DELETE 只填 xmax,ROLLBACK 的版本留在页里只是标志无效;repeatable read 事务在别人删除后仍能看到旧行;只更新非索引列 1000 次全是 HOT 更新,表仍是 1 页。
实测 PostgreSQL 16.15 表膨胀与 VACUUM:20 万行全表 UPDATE 后表大小从 26.9 MB 翻倍到 53.9 MB;普通 VACUUM 清掉死行但文件不缩小,之后的更新重用空间;VACUUM FULL 缩回 26.9 MB 但会挡住 SELECT;只有尾部空页能被截断;老事务会让 VACUUM 回收不了。
实测 PostgreSQL 16.15 autovacuum 什么时候触发:门槛是 50 + 0.2 × 行数(1 万行的表 2050),更新 2000 行不触发、累计 2100 行触发;analyze 的门槛 1050 先到;10 万行的表默认要 20050,单表设 scale_factor = 0 后 1.0 s 内清理;老事务让 autovacuum 空转;日志里能看到 removed 行数。
实测 PostgreSQL 16.15 HOT 更新与 fillfactor:改有索引的列不可能是 HOT;只改没索引的列也要页里有空位;fillfactor 100/90/70/50 的 HOT 占比是 0%/12.2%/44.7%/100.0%;连续更新 5 轮 fillfactor 100 涨到 85.2 MB 而 50 不变;长事务会挡住剪枝(1 页变 5 页);fillfactor 50 的全表扫描 6.8 ms 对 4.5 ms。
实测 PostgreSQL 16.15 事务隔离级别:READ COMMITTED 同事务两次读不同、UPDATE 等锁后重新评估 WHERE;REPEATABLE READ 无幻读但更新别人改过的行报 could not serialize access due to concurrent update;SERIALIZABLE 拦下写偏斜;热点行 8 个会话重试 1180 次;先读后写丢 311 次更新,原子 UPDATE 和 FOR UPDATE 不丢。
实测 PostgreSQL 16.15 ALTER TABLE 为什么会卡住所有查询:长查询拿着 ACCESS SHARE,ALTER 排队,后来的普通 SELECT 被挡 1.59 s;pg_locks 里能看到排队的锁;lock_timeout 把 C 的等待降到 0.10 s;重试循环;各种 DDL 是否重写整表(add column 可空 0.6 ms,volatile 默认值 594.2 ms);CREATE INDEX CONCURRENTLY 不挡写入。
实测 PostgreSQL 16.15 索引为什么没被用:100 万行里取 1 行走 Index Scan、取 90% 走 Seq Scan 都是对的;30% 起索引扫描比全表扫描慢;对列做 lower()、加法、类型转换会让普通索引失效(89.28 ms 对 0.00 ms);LIKE 前缀在 en_US.UTF-8 下要 text_pattern_ops;random_page_cost = 1.1 让 50% 的查询换成更慢的 Index Scan(190.70 ms)。
实测 PostgreSQL 16.15 的索引类型:100 万行上 B-tree 18.8 MB、Hash 32.0 MB、BRIN 24 KB;BRIN 只在与物理顺序相关的列上有效(随机列 43.66 ms 等于没用,顺序列 0.44 ms);Hash 不支持范围;jsonb 的 GIN 与 jsonb_path_ops(12.0 MB 对 8.9 MB);pg_trgm 让 LIKE '%qzx%' 从 59.80 ms 降到 0.07 ms。