Crunchy Data Blog

9 篇内容

技术文章Crunchy Data Blog

Postgres Calculations and the Ambiguity of NULL

文章深入剖析 PostgreSQL(以及其他 SQL 数据库)中 NULL 的三值逻辑语义。作者从 NULL 代表“未知”而非某个值出发,依次讲解了比较运算、布尔逻辑、算术、NOT IN、聚合、窗口函数、字符串拼接和排序中 NULL 的行为差异,并用大量可运行的查询示例展示常见错误。例如 active OR NOT active 并非永真,NOT IN 遇到 NULL 会返回空集,聚合函数会忽略 NULL 而 COUNT(*) 不会,窗口函数中的 lag/first_value 不会自动跳过 NULL,字符串拼接 || 遇到 NULL 直接返回 NULL 而 concat 会将其视为空串,NULL 默认排序高于所有真实值。文章还介绍了 IS NOT DISTINCT FROM、COALESCE、NOT EXISTS、FILTER、concat_ws、NULLS FIRST/LAST 等处理手段,并预告 Postgres 19 的 IGNORE NULLS 子句。最后强调应根据业务规则显式处理 NULL,或在表结构中用 NOT NULL 约束从源头避免歧义。适合所有使用 SQL 的开发者阅读。

推荐收录。文章不是简单罗列语法,而是从三值逻辑原理出发系统解释 NULL 在各 SQL 子句中的一致与不一致表现,并给出可迁移的排查清单。案例覆盖 WHERE、NOT IN、聚合、窗口函数、拼接、排序等高频场景,对数据工程师、后端开发者和数据库维护者都有直接参考价值。其清晰的问题定位方式和标准引用也适合作为团队内部 SQL 培训材料。风险在于示例基于 Postgres,部分行为在其他数据库略有差异,但核心概念通用。

工程实践Crunchy Data Blog

Postgres 19: How Our Advice Has Changed Since We Wrote It

文章围绕 Postgres 19 的 beta 功能,回顾 Crunchy Data 多年来关于数据加载、TOAST、BRIN 索引、覆盖索引和分区管理的既有建议,并逐项说明哪些版本改变了这些建议的落点。作者指出核心原则仍成立:批量导入优先用 COPY,JSON 存 jsonb,索引是权衡,分区主要服务生命周期管理。主要变化包括 async I/O 显著加速堆扫描与 vacuum,COPY 新增 ON_ERROR 与 REJECT_LIMIT 等容错选项,LZ4 成为默认 TOAST 压缩算法,BRIN 增加 minmax_multi 与 Bloom 形状,B-tree skip scan 覆盖更多查询,以及并发 detach、merge/split 分区等新 DDL。文章给出了大量可直接使用的 SQL 示例和调参建议,并强调这些功能基于 beta,正式发布细节可能调整,升级后应结合 EXPLAIN (ANALYZE, BUFFERS, IO) 重新验证。

建议收录。它不是零散的版本新闻,而是把 Postgres 11 到 19 的功能演进与真实运维建议逐条对照,给出了从 COPY 容错、LZ4 压缩、BRIN 调优到分区在线操作的可执行路径。适合数据库管理员、后端工程师和依赖 PostgreSQL 的团队在升级前做功能核查与基准测试;文中先验证再调整的决策方式,也能迁移到其他数据库平台。注意文章内容基于 beta,部分行为需以正式版文档为准。

工程实践Crunchy Data Blog

Hybrid Search Patterns with Postgres and pgvector

文章系统探讨了在PostgreSQL和pgvector中实现混合搜索(向量相似度加标量过滤)的工程模式。首先阐述了pgvector迭代索引扫描如何平衡召回与性能,然后分析了向量优先和标量优先两条路径各自的适用场景与局限。作者进一步提供了三种实用工作区:为低基数过滤构建部分HNSW索引;通过过采样再过滤应对高基数或临时过滤器;以及利用缓存加速重复查询。文中给出了过采样的估算公式、查询计划诊断方法以及各方案的决策指南,并强调了每种模式在召回率、性能和维护成本之间的权衡。

推荐收录,因为本文是针对Postgres+pgvector混合搜索问题的实战指南,从问题根源到四种解决方案给出了完整的权衡分析、代码示例和调优公式,远超简单教程。适合正在构建带标量过滤的向量搜索系统的工程师,文中部分索引、过采样和缓存等模式可直接应用于生产环境,决策树和EXPLAIN诊断方法具有跨场景的可迁移价值。

技术文章Crunchy Data Blog

Postgres 19 Compression: from pglz to LZ4

Postgres 19计划将默认TOAST压缩算法从pglz切换为LZ4。本文追溯了从Postgres 7.0引入lztext到7.1实现TOAST与pglz的历史,解释了pglz设计的取舍:速度优先、极小内存占用、快速终止和零外部依赖。然后对比了LZ4的优势:更快的压缩速度(测试中提速约8倍)、更大的滑动窗口带来更好的压缩率,并保留了快速终止特性。文章详细说明了变长类型的varlena格式、EXTENDED/PLAIN/EXTERNAL/MAIN四种存储策略,以及写入时的压缩决策树:行大小超过约2KB阈值时,依次压缩前列大对象或移入TOAST表。此外,还介绍了B树索引中机会主义压缩的机制:当键值超过510字节时尝试压缩,并举例说明可压缩与不可压缩数据对索引的影响。整体内容既包含机制解析也包含实践测试,展示了Postgres团队在压缩演进上的谨慎策略。边界在于测试非科学化,且未深入LZ4算法内部细节。

本文系统梳理了Postgres压缩框架的历史、原理与决策路径,并结合代码示例和对比数据说明LZ4替代pglz的收益。适合需要理解Postgres存储优化、TOAST机制或索引限制的DBA与开发者,可迁移的价值在于掌握如何诊断压缩效果、选择存储策略以及评估算法升级对性能的影响。内容详实且有长期参考价值。

工程实践Crunchy Data Blog

British Columbia, Time Zones, and Postgres

文章以不列颠哥伦比亚省时区规则变更为例,讨论了 PostgreSQL 中时间存储的核心陷阱:把未来的“本地意图”仅用 timestamptz 保存,会因 tzdata 更新而在查询时还原出错误的本地时间。作者进一步提出双列模式,将 local_time 和 timezone_name 作为事实源,再用触发器计算并维护 starts_at_utc,以同时满足本地语义、UTC 索引与约束检查的需求。文中还说明了这种方案的适用边界、tzdata 变更后的重算策略,以及 RFC 9557 目前并不能解决这类未来本地时间问题。

推荐收录,因为文章围绕真实的时区规则变更给出了可直接迁移到数据库设计中的方案,不只是泛泛讲时间处理。它对预约、日程、法务截止时间等需要保留未来本地意图的系统尤其有参考价值,也明确提醒了哪些场景仍应继续使用 plain timestamptz。

工程实践Crunchy Data Blog

Postgres Serials Should be BIGINT (and How to Migrate)

这篇文章讨论了 Postgres 中自增主键从 SERIAL/INT 升级到 BIGINT 的必要性,核心理由是 INT 只有约 21 亿上限,而 BIGINT 基本不会溢出。作者进一步说明 BIGINT 在很多行布局下并不比 INT 更占空间,因为 PostgreSQL 的行对齐和填充会抵消所谓的 4 字节节省,因此用 BIGINT 的长期成本通常很低。文章还对比了 UUID 的适用场景,认为跨系统或需要公开暴露 ID 的场景可以选 UUID,但纯数据库序列号未必需要放弃整数。随后给出了一套可在线执行的迁移方案:新增 BIGINT 列、触发器同步、分批回填、定期 VACUUM、并发建唯一索引、处理外键引用表,再在一个短事务里完成 atomic swap。文中也强调了边界条件:需要预留短暂排它锁、先在非生产环境验证批次大小和回填策略,并确保序列、外键和主键约束在切换后都能正确接管。

推荐收录,因为文章直接给出了从 INT 到 BIGINT 的完整 PostgreSQL 迁移链路,包含分批回填、NOT VALID 外键、并发建索引和原子切换等可复用证据。适合负责数据库演进、线上改表或容量规划的后端/DBA 读者,主要价值是把一次高风险 schema 变更拆成可验证的操作步骤。

工程实践Crunchy Data Blog

Postgres 18 New Default for Data Checksums and How to Deal with Upgrades

文章介绍了 Postgres 18 将数据校验和(data checksums)设为 initdb 的默认开启项,强调其核心价值是及早发现磁盘页的静默损坏。作者先解释校验和如何在写入数据页时生成、存入页头,并在读取时重新计算比对,从而把原本难以察觉的数据腐败转化为可报警错误。随后文章说明这一默认变化对新建集群是纯收益,但会影响使用 pg_upgrade 的大版本升级,因为新旧集群的校验和开关必须一致。文中给出两条应对路径:升级时可用 --no-data-checksums 保持兼容,或提前用 pg_checksums 为现有集群补开校验和,但后者通常需要停机或通过副本切换来降低影响。整体适用于自建 PostgreSQL 运维、升级规划和备份完整性管理场景。

文章直接给出 Postgres 18 默认行为变化、pg_upgrade 兼容条件和 pg_checksums 处理方案,证据明确且可操作性强。适合数据库运维、平台工程和升级规划读者,尤其对自建集群的完整性保障与停机权衡有长期参考价值。

技术文章Crunchy Data Blog

PostGIS Performance: Simplification

这篇文章围绕 PostGIS 中“几何简化”展开,比较了多种常见方法在点数压缩、形状保真和有效性上的差异。作者先用 ST_Letters、ST_Segmentize 和 ST_RemoveRepeatedPoints 构造出可观察的测试图形,再依次展示 ST_Simplify(Douglas-Peucker)、ST_SimplifyVW(Visvalingam-Whyatt)、ST_SnapToGrid 与 ST_ReducePrecision 的效果。文章指出,Douglas-Peucker 更偏向折线压缩,VW 在多边形形状保留上通常更好,而简单网格吸附虽能统一精度却容易产生无效多边形。相较之下,ST_ReducePrecision 在固定精度与几何有效性之间提供了更稳妥的折中。最后还补充了 PostGIS 3.6 新增的覆盖面处理能力:先用 ST_CoverageClean 清理共享边界,再用 ST_CoverageSimplify 对相邻面集合整体简化,适用于需要边界一致性的专题图或覆盖数据。

文章直接比较了多种 PostGIS 简化函数的输出差异、有效性风险和适用场景,不是泛泛介绍 API。对做空间数据处理、地图渲染或数据库性能优化的读者很有参考价值,尤其适合需要在精度、合法性和边界一致性之间做取舍的工程场景。

技术文章Crunchy Data Blog

How to Read Postgres EXPLAIN: A Guide to Scan Types

这篇文章以 Postgres 的 EXPLAIN 输出为切入点,系统讲解了常见扫描类型及其适用场景,帮助读者从执行计划中判断查询为何快或慢。文章依次解释了顺序扫描、索引扫描、位图索引扫描与位图堆扫描、并行顺序扫描、并行索引扫描以及索引仅扫描,并配合真实的 EXPLAIN ANALYZE 示例展示各自的计划形态和指标。作者不仅说明了这些扫描方式的工作机制,还强调了优化器的选择逻辑,例如小表、返回比例较高或需要随机访问过多时,顺序扫描可能优于索引扫描。对于索引仅扫描,文章进一步讨论了覆盖索引带来的收益,以及写放大、索引体积和适用列数等边界条件。整体上,这是面向 PostgreSQL 性能排查与执行计划阅读的实用入门,但内容仍以常见扫描类型为主,未深入展开代价模型或更复杂的连接/排序计划。

文章直接给出了多种 EXPLAIN 扫描节点的真实输出和判读方法,适合做 PostgreSQL 性能排查、SQL 优化和执行计划入门参考。它的可迁移价值在于帮助读者建立“选择哪种扫描方式、为什么会选它”的心智模型,但内容主要覆盖基础扫描类型,深层优化仍需结合具体工作负载。