尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

postgres_lsp 规则详解:requireConcurrentIndexDeletion —— 用 `DROP INDEX CONCURRENTLY` 避免删除索引时锁表阻塞生产读写

postgres_lsp 规则详解:requireConcurrentIndexDeletion —— 用 `DROP INDEX CONCURRENTLY` 避免删除索引时锁表阻塞生产读写 postgres_lsp 规则详解requireConcurrentIndexDeletion —— 用DROP INDEX CONCURRENTLY避免删除索引时锁表阻塞生产读写【免费下载链接】postgres_lspA Language Server for Postgres项目地址: https://gitcode.com/GitHub_Trending/po/postgres_lsp本文深入解析 postgres_lsp 内置的lint/safety/requireConcurrentIndexDeletion规则它为什么存在、在什么条件下触发、会输出怎样的诊断信息以及如何在postgres-language-server.jsonc中配置规则级别。文章同时结合 规则实现源码、配置结构定义 与 测试快照 进行佐证读完你可以直接在生产环境的迁移脚本或 CI 检查中落地这一条安全规则。规则背景非并发删除索引为什么危险PostgreSQL 中DROP INDEX默认会获取目标表上的ACCESS EXCLUSIVE锁。这意味着在删除索引的整个执行期间该表上的所有读写操作都会被阻塞直到索引删除完成并释放锁为止。对于持续有流量访问的生产表一次耗时较长的索引删除可能直接演变成一次线上事故downtime。DROP INDEX CONCURRENTLY则不同它采用多阶段方式删除索引过程中只短暂持有轻量级锁允许表的读写并发进行。代价是执行时间通常更长、无法在事务块内使用并且如果删除中途失败会留下一个INVALID状态的索引此时仍需用CONCURRENTLY方式补删。正因如此postgres_lsp 在safety安全规则组中提供了requireConcurrentIndexDeletion规则当检测到非并发删除索引的语句时给出警告提示改用CONCURRENTLY。规则的官方定义规则的基础信息定义在规则源码的declare_lint_rule!宏中见 require_concurrent_index_deletion.rsDiagnostic Categorylint/safety/requireConcurrentIndexDeletion规则名称namerequireConcurrentIndexDeletionSincevnext规则源码中version: next默认严重级别Severity::Warning默认是否推荐recommendedfalse即默认不随推荐规则集启用需要显式配置灵感来源从 Squawk 的require-concurrent-index-deletion规则移植而来移植记录 中已标记为 ported from Squawk规则的官方描述为Dropping indexes non-concurrently can lock the table for reads. When dropping an index, usingDROP INDEXwithoutCONCURRENTLYwill lock the table preventing reads and writes for the duration of the drop. This can cause downtime in production systems. UseDROP INDEX CONCURRENTLYto drop the index without blocking concurrent operations.触发逻辑规则到底检查什么从实现上看该规则的检测逻辑非常聚焦require_concurrent_index_deletion.rsfn run(ctx: LinterRuleContextSelf) - VecLinterDiagnostic { let mut diagnostics Vec::new(); if let pgls_query::NodeEnum::DropStmt(stmt) ctx.stmt() !stmt.concurrent stmt.remove_type() pgls_query::protobuf::ObjectType::ObjectIndex { diagnostics.push(LinterDiagnostic::new( rule_category!(), None, markup! { Dropping an index non-concurrently blocks reads and writes to the table. }, ).detail(None, Use DROP INDEX CONCURRENTLY to avoid blocking concurrent operations on the table.)); } diagnostics }命中规则需要同时满足三个条件语句类型是DropStmt即DROP ...语句由 postgres_lsp 的查询语法树节点pgls_query::NodeEnum::DropStmt表示concurrent标志为假即语句中没有写CONCURRENTLY删除的对象类型是索引即stmt.remove_type()返回ObjectType::ObjectIndex。三个条件同时成立时规则生成一条诊断主消息为Dropping an index non-concurrently blocks reads and writes to the table.并附上修复建议Use DROP INDEX CONCURRENTLY to avoid blocking concurrent operations on the table.。值得注意的是该规则的选项类型为()空类型见 options.rs 中的类型别名RequireConcurrentIndexDeletion ... as LinterRule::Options意味着它没有任何可配置的附加参数——你只能通过规则级别error/warn/off来控制启用与否。示例非法写法与合法写法非法示例会触发诊断DROP INDEX IF EXISTS users_email_idx;在 CLI 检查或编辑器内联诊断中输出效果如下code-block.sql:1:1 lint/safety/requireConcurrentIndexDeletion ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Dropping an index non-concurrently blocks reads and writes to the table. 1 │ DROP INDEX IF EXISTS users_email_idx; │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 │ i Use DROP INDEX CONCURRENTLY to avoid blocking concurrent operations on the table.合法示例不触发诊断DROP INDEX CONCURRENTLY IF EXISTS users_email_idx;带CONCURRENTLY的写法满足stmt.concurrent true因此不会被该规则标记。测试快照佐证仓库为该规则提供了独立的测试用例basic.sql 与对应的 basic.sql.snap。测试输入为-- expect_lint/safety/requireConcurrentIndexDeletion DROP INDEX IF EXISTS users_email_idx;快照中记录的诊断输出为lint/safety/requireConcurrentIndexDeletion ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ × Dropping an index non-concurrently blocks reads and writes to the table. i Use DROP INDEX CONCURRENTLY to avoid blocking concurrent operations on the table.这验证了实现与文档描述完全一致。如何配置该规则属于safety规则组配置项挂载在linter.rules.safety之下配置字段定义见 rules.rs。在项目的postgres-language-server.jsonc配置文件中加入{ linter: { rules: { safety: { requireConcurrentIndexDeletion: error } } } }级别说明error将违规提升为错误CI 中可借此阻断合并warn仅提示警告不阻断这是该规则源码中定义的默认严重级别off显式关闭该规则。由于recommended: false如果不做任何配置该规则默认不会生效需要像上面这样显式声明才会开启。开启后既可以在编辑器配合 postgres_lsp 的 LSP 能力中获得实时内联提示也可以在执行 lint 检查的命令行流程中输出诊断结果。同类规则的横向参考在 postgres_lsp 的safety规则组中requireConcurrentIndexDeletion并非孤例它属于一组要求显式使用CONCURRENTLY以避免长时间锁表的规则家族实现均位于 crates/pgls_analyser/src/lint/safety 目录requireConcurrentIndexCreation创建索引CREATE INDEX同样建议使用CONCURRENTLY避免锁住写入requireConcurrentReindexREINDEX不带CONCURRENTLY会获取ACCESS EXCLUSIVE锁requireConcurrentRefreshMatviewREFRESH MATERIALIZED VIEW不带CONCURRENTLY同样会获取ACCESS EXCLUSIVE锁requireConcurrentDetachPartition分区表DETACH PARTITION不带CONCURRENTLY也会持有ACCESS EXCLUSIVE锁。这些规则的配置字段相邻定义在 rules.rs主题一致凡是 PostgreSQL 中可能长时间阻塞读写对象的 DDL 操作postgres_lsp 都提供了对应的安全提示规则。如果你的迁移脚本以并发安全为底线可以按需把这些规则一并开启。适用前提与注意事项本规则面向 PostgreSQL 环境其判断依据是语句中是否出现CONCURRENTLY关键字即语法树中DropStmt.concurrent标志与数据库实例的实时锁状态无关属于静态分析DROP INDEX CONCURRENTLY本身存在限制不能在事务块中执行。如果迁移脚本整体被包在事务里需要先提交/回滚事务再单独执行该语句这一点不在本规则的检测范围内规则当前定义在vnext版本使用前请确认你使用的 postgres_lsp 构建版本包含该规则规则的完整配置结构可进一步参考 docs/reference/rules.md 与项目根目录的 postgres-language-server.jsonc 示例配置。小结requireConcurrentIndexDeletion是 postgres_lsp 面向数据库迁移安全提供的低成本高收益规则之一它把删除索引必须考虑并发锁这一 PostgreSQL 运维常识固化为可自动执行的静态检查配合DROP INDEX CONCURRENTLY的修复建议能在迁移合入生产之前就拦截潜在的表锁风险。配置只需几行 JSON即可让它成为你 DDL 迁移流程中的一道常规防线。【免费下载链接】postgres_lspA Language Server for Postgres项目地址: https://gitcode.com/GitHub_Trending/po/postgres_lsp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表