分区键选择不当导致数据倾斜,需通过实际count统计而非information_schema估算定位;mysql用partition()子句查真实行数,postgresql结合pg_partition_tree与analyze;reorganize卡住应改用新建表+rename切换;分区裁剪失效主因是函数包裹或隐式转换。

分区表数据倾斜怎么快速定位
分区键选得不好,数据会扎堆在少数几个分区里,查询变慢、清理卡住、空间爆满——这不是配置问题,是数据分布本身失衡。直接查 information_schema.PARTITIONS 只能看到行数估算,不准;得用实际统计。
- 对每个分区执行
SELECT COUNT(*) FROM tbl PARTITION(p202401)(MySQL 8.0+ 支持),别信TABLE_ROWS字段 - PostgreSQL 要用
pg_partition_tree+pg_class关联查真实reltuples,再结合ANALYZE后才可靠 - 注意:
EXPLAIN PARTITIONS在 MySQL 中只显示“可能用到哪些分区”,不反映实际扫描量;真正看负载得上performance_schema.events_statements_summary_by_digest找高耗时的分区扫描语句
ALTER TABLE ... REORGANIZE PARTITION 卡住怎么办
想合并旧分区或拆分热点分区时,REORGANIZE PARTITION 会锁表、复制数据、重建索引,大表动辄几小时,期间写入阻塞。这不是语法错,是操作粒度太大。
- MySQL 5.7+ 支持
ALGORITHM=INPLACE的REORGANIZE,但仅限 RANGE/LIST 分区且不改分区键类型;否则默认走COPY,必须停写 - 替代方案:新建空分区表 →
INSERT INTO new_tbl SELECT * FROM old_tbl PARTITION(p202301)(带 WHERE 过滤更安全)→ 用RENAME TABLE原子切换 - PostgreSQL 没有原生
REORGANIZE,靠ATTACH/DETACH PARTITION配合CREATE TABLE AS拆分,但 DETACH 不锁父表,可提前做
分区裁剪失效的典型场景和验证方法
写了 WHERE dt = '2024-01-01' 却扫全表?不是 SQL 写错了,是分区裁剪根本没触发。常见于隐式类型转换、函数包裹分区键、或分区字段被索引覆盖了。
- MySQL 中
WHERE DATE(dt) = '2024-01-01'会让分区裁剪失效;必须用dt >= '2024-01-01' AND dt - PostgreSQL 对
WHERE dt::date = '2024-01-01'同样不裁剪,得用WHERE dt >= '2024-01-01' AND dt - 验证是否裁剪:MySQL 看
EXPLAIN PARTITIONS输出里partitions列是否只列了目标分区;PostgreSQL 看EXPLAIN结果中是否出现Partition Iterator和具体子表名
监控分区表空间增长异常的最小可行路径
磁盘突然告警,但 df -h 显示其他目录正常——八成是某个分区子表暴增。不要一上来就 du -sh * 扫整个 data 目录,太慢,且 MySQL 的 .ibd 文件不直接对应分区名。
- MySQL:查
information_schema.INNODB_SYS_TABLESPACES,用NAME字段匹配db_name/tbl_name#P#p202401格式,再关联FILE_SIZE - PostgreSQL:用
\dt+ schema.tbl_name查主表大小,再逐个\dt+ schema.tbl_name_1_prt_p202401(命名依策略而异)比对 - 关键点:定期导出
pg_total_relation_size()或DATA_LENGTH + INDEX_LENGTH快照,diff 才能发现单日突增;临时查只能救急
分区裁剪逻辑、空间归属、重组织操作这三块,最容易在低峰期测试时“看起来没问题”,一到高峰就暴露。特别是跨时区应用写入时间字段,分区键值和实际物理分布常有小时级偏差,得按 UTC 统一校验。










