
Postgres LSP 安全规则实战requireConcurrentIndexCreation 并发建索引检测详解【免费下载链接】postgres_lspA Language Server for Postgres项目地址: https://gitcode.com/GitHub_Trending/po/postgres_lsp导读requireConcurrentIndexCreation是 Postgres Language Serverpostgres_lsp内置的lint/safety安全 lint 规则用于检测生产环境中使用非并发方式不带CONCURRENTLY创建索引、从而阻塞表写入并可能引发宕机的高危操作。本文以官方规则文档为核心结合仓库源码、测试快照与配置定义完整讲解该规则的触发逻辑、豁免场景、诊断输出格式、配置方法及底层实现原理帮助你在 CI 和编辑器工作流中落地「建索引必须并发」的安全基线。规则概述诊断类别与基本信息属性值诊断类别Diagnostic Categorylint/safety/requireConcurrentIndexCreation版本Sincevnext默认严重级别Warning源码定义见 rules.rs是否默认推荐开启否recommended: false见 require_concurrent_index_creation.rs规则来源受 Squawk 的require-concurrent-index-creation规则启发移植见 port_squawk_rules.md规则要解决的问题在已有的表上执行CREATE INDEX不带CONCURRENTLY时PostgreSQL 会在整个索引构建期间持有ACCESS EXCLUSIVE级别的表锁阻止所有对该表的写入操作。对于流量较大的生产系统这意味着索引构建的每秒钟都会造成写入停滞严重时直接导致业务宕机。规则的核心理念是在已有表上建索引应使用CREATE INDEX CONCURRENTLY并发构建避免阻塞并发操作只有新创建的表同一文件/事务内刚CREATE TABLE的表上建索引才不存在阻塞既有写入的问题可以豁免检测。触发与豁免逻辑从源码实现require_concurrent_index_creation.rs可以看到规则采用「先识别语句类型 → 逐层排除安全场景 → 剩余情况上报诊断」的判断流程语句类型匹配只有 AST 节点为IndexStmt即CREATE INDEX语句时才继续处理其他语句直接返回空诊断并发豁免如果语句声明了concurrent标志即使用了CONCURRENTLY说明是安全建索引方式直接放行同文件建表豁免通过file_context检查当前文件内所有语句若存在CreateStmt且其表名与索引目标表一致即该表是在同一文件/事务内新建的则放行上报诊断其余情况在既有表上非并发建索引产生一条lint/safety/requireConcurrentIndexCreation诊断。为什么存在「同文件建表」豁免is_table_created_in_filerequire_concurrent_index_creation.rs遍历文件上下文中的所有语句查找与目标表同名的CreateStmt。这是针对迁移脚本的典型场景许多迁移文件会在同一文件内先CREATE TABLE再立即建索引。由于表刚创建、尚无存量写入流量此时非并发建索引不会造成生产影响因此被判定为安全。这一设计与规则的移植来源 Squawk 保持行为一致——后者同样需要结合「文件内语句上下文」来判断表是否为新建表。仓库的移植文档 port_squawk_rules.md 明确将该规则标记为已从 Squawk 移植完成require_concurrent_index_creation ✓。示例与诊断输出无效写法Invalid对已有表users直接建索引CREATE INDEX users_email_idx ON users (email);运行 lint 后会产生如下格式的诊断输出完整输出见测试快照 basic.sql.snapcode-block.sql:1:1 lint/safety/requireConcurrentIndexCreation ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Creating an index non-concurrently blocks writes to the table. 1 │ CREATE INDEX users_email_idx ON users (email); │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 │ i Use CREATE INDEX CONCURRENTLY to avoid blocking concurrent operations on the table.诊断包含两个关键部分主信息Creating an index non-concurrently blocks writes to the table.非并发建索引会阻塞表写入辅助建议Use CREATE INDEX CONCURRENTLY to avoid blocking concurrent operations on the table.改用并发方式避免阻塞。源码中这两条消息分别通过LinterDiagnostic::new(...)的 markup 正文与.detail(...)方法注入见 require_concurrent_index_creation.rs并且诊断会精确覆盖整条CREATE INDEX语句的源码区间快照中^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^标注的位置。有效写法ValidCREATE INDEX CONCURRENTLY users_email_idx ON users (email);使用CONCURRENTLY后PostgreSQL 会以较低级别的锁SHARE UPDATE EXCLUSIVE构建索引期间允许对表进行读写规则不会产生任何诊断。如何配置该规则通过postgres-language-server.jsonc或对应 IDE 配置中的linter.rules.safety段进行配置。官方文档给出的完整配置示例{ linter: { rules: { safety: { requireConcurrentIndexCreation: error } } } }配置说明规则值支持error、warn、off等诊断级别。示例中设为error表示将违规提升为错误级别适合在迁移文件检查的 CI 流程中强制阻断非并发建索引仓库的配置解析层rules.rs注册了requireConcurrentIndexCreation这一配置键名并为其定义了默认严重级别Severity::Warningrules.rs若要在某个文件/目录中临时豁免可结合项目的 suppressions 机制见 docs/guides/suppressions.md按行或按语句进行抑制项目根目录提供了示例配置文件 postgres-language-server.jsonc可作为配置起点参考。底层实现原理规则定义宏规则通过declare_lint_rule!宏声明元信息require_concurrent_index_creation.rspub RequireConcurrentIndexCreation { version: next, name: requireConcurrentIndexCreation, severity: Severity::Warning, recommended: false, sources: [RuleSource::Squawk(require-concurrent-index-creation)], }其中name与诊断类别中的requireConcurrentIndexCreation一一对应sources标注了规则灵感来源于 Squawk 的同名规则recommended: false表示它不属于默认推荐规则集需要用户显式开启。规则执行流程规则的run方法接收LinterRuleContext从中取出当前语句的 ASTctx.stmt()和文件上下文ctx.file_context()返回VecLinterDiagnostic。关键判断点let pgls_query::NodeEnum::IndexStmt(stmt) ctx.stmt() else { return diagnostics; }; // Concurrent indexes are safe if stmt.concurrent { return diagnostics; }AST 由pgls_querycrate 提供其NodeEnum是基于 libpg_query 生成的 PostgreSQL 语法树枚举IndexStmt节点上的concurrent字段直接对应 SQL 中是否出现CONCURRENTLY关键字。注册与分发规则在 safety.rs 中以模块形式声明并注册进Safety规则组declare_lint_group!运行时通过 registry.rs 中的规则名到具体规则实例的映射完成分发。也就是说配置里写入requireConcurrentIndexCreation后检查器会根据规则名找到RequireConcurrentIndexCreation并执行上述判断逻辑。测试验证仓库为该规则提供了规格测试spec位于 crates/pgls_analyser/tests/specs/safety/requireConcurrentIndexCreation/ 目录输入文件 basic.sql 通过-- expect_lint/safety/requireConcurrentIndexCreation声明期望产生该规则诊断测试体为一行非并发建索引语句快照文件 basic.sql.snap 记录了期望的诊断输出验证了主信息Creating an index non-concurrently blocks writes to the table.与建议信息Use CREATE INDEX CONCURRENTLY to avoid blocking concurrent operations on the table.的精确呈现。这些测试与pgls_analysercrate 的rules_tests.rs测试框架配合见 CONTRIBUTING.md确保规则行为在后续演进中保持稳定。与其他相关规则的配合safety规则组还包含与索引锁行为相关的其他规则组合使用可形成更完整的迁移安全体系banConcurrentIndexCreationInTransactionban-concurrent-index-creation-in-transaction.mdCREATE INDEX CONCURRENTLY不能在事务块内执行该规则负责检测反向误用requireConcurrentIndexDeletionrequire-concurrent-index-deletion.md删除索引同样存在锁风险要求使用DROP INDEX CONCURRENTLYrequireConcurrentRefreshMatviewrequire-concurrent-refresh-matview.md物化视图刷新也推荐并发执行。三条规则共同覆盖了「建索引、删索引、刷物化视图」三类常见锁风险操作均移植自 Squawk见 port_squawk_rules.md 的 DONE 列表。最佳实践建议CI 中设为error对迁移文件目录单独启用该规则并提升为error让非并发建索引在合并前就被阻断善用同文件建表豁免新建表场景同一迁移文件内先建表再建索引不会误报无需额外抑制若确实需要在既有表上非并发建索引再考虑使用 suppressions 或先CREATE TABLE后分文件建索引注意CONCURRENTLY的事务限制并发建索引不能放在事务块内因此与banConcurrentIndexCreationInTransaction配合时需要在文件级合理组织语句顺序先建表、再并发建索引避免两者互相冲突在编辑器中即时反馈postgres_lsp 的 IDE 集成见 docs/guides/ide_setup.md会实时提示该警告配合docs/features/linting.mdlinting.md了解完整的 lint 能力可在编写 SQL 时第一时间发现风险。总结requireConcurrentIndexCreation规则精准识别「在既有表上非并发建索引」这一高风险操作通过CONCURRENTLY与「同文件新建表」双重豁免机制既守住生产写入安全底线又不打扰迁移脚本中的常规建表建索引流程。结合源码实现与规格测试你可以放心将其纳入 Postgres 迁移检查流水线作为数据库变更安全的常备防线。【免费下载链接】postgres_lspA Language Server for Postgres项目地址: https://gitcode.com/GitHub_Trending/po/postgres_lsp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考